VueJS 如何编译服务器端远程模板【异步组件+简单方法】

说明

有些时候你可能需要从后台获取模板,并在前台在自己编译,这在用 AngularJS 1.x 的时候似乎很常见,可以直接用 ng-include 搞定,在 Vue 1.x 的时候也可以直接用 partial 搞定。
但是在 Vue 2.x 中,官方取消了 partial 这个 API,根据情况推荐使用 component 代替,参见这里

需求

那我现在有个需求,就是从后台获取一个字符串模板(假设里面包含 v-model 等 vue 指令),模板需要拿到前台来编译,那该怎么实现呢?
(这种需求确实比较少见,但是是存在的。。。)

可能的解决方案

官方根据情况推荐了三种替代 partial 的方式,分别为:

  1. normal component 常规组件,没有处于性能关键区域(简单来说就是对性能有较大影响)时使用
  2. dynamic component 动态组件,根据组件名称动态绑定时使用
  3. functional component 函数组件,处于性能关键区域时使用

另外根据文档中的的情况来看:

  1. 异步组件和高级异步组件异步组件) 也可能解决楼主的问题

下面来分别分析一下:

常规组件

用法

// 注册
Vue.component(‘my-component‘, {
  template: ‘<div>A custom component!</div>‘
})
// 创建根实例
new Vue({
  el: ‘#example‘
})

这是常规组件的注册方法
先来看下 Vue 实例的声明周期图,摘自官网:

图中黄色的部分,可以看出 vue 实例的模板是来自哪里的?

  1. el 选项提供的选择器
  2. template 选项提供的字符串 (当然没有的话会编译组件的 outerHTML)

还有其他可能吗?没有了。。。而且两个选项的提供都是在 beforeMount 之前,这说明啥?这说明这两个选项一旦提供就不能改了!所以在声明组件的时候就必须提供这两个选项来作为编译的模板,而且是不能更改的,那我如果想要异步拿到模板去编译显然不可能。
so,常规组件,卒。

动态组件

动态组件简单来说是使用 <component :is="currentView"></component> 让多个组件使用一个挂载点,currentView 可以直接是注册进来的组件,如:

var vm = new Vue({
  el: ‘#example‘,
  data: {
    currentView: ‘home‘
  },
  components: {
    home: { /* ... */ },
    posts: { /* ... */ },
    archive: { /* ... */ }
  }
})
<component v-bind:is="currentView">
  <!-- 组件在 vm.currentview 变化时改变! -->
</component>

也可以是选项对象!!

var Home = {
  template: ‘<p>Welcome home!</p>‘
}
var vm = new Vue({
  el: ‘#example‘,
  data: {
    currentView: Home
  }
})

从目前了解的情况来看,import 进来的组件一般也都是准备好的,如果想要异步加载可能需要 webpack 的一些功能,暂且先跳过。
那动态组件可以是选项对象?那选项对象如果是异步的呢?好吧有希望~ 糖糖先记着~

函数组件

这个,看了第一遍文档,不是太懂,没关系!找关键的地方: API:render 函数

Vue 选项中的 render 函数若存在,则 Vue 构造函数不会从 template 选项或通过 el 选项指定的挂载元素中提取出的 HTML 模板编译 render 函数。

这里所说的很清楚,template 或 el 选项最终都会被编译成 render 函数,那如果有 render 函数的话,就会忽略那两个选项。还是要看上面那张图,render 函数是在 beforeMount 的时候就已经编译完成的,所以也是不能改变的。
so,函数组件,卒。

异步组件

这里直接摘官网说明:

在大型应用中,我们可能需要将应用拆分为多个小模块,按需从服务器下载。为了让事情更简单,Vue.js 允许将组件定义为一个工厂函数,动态地解析组件的定义。Vue.js 只在组件需要渲染时触发工厂函数,并且把结果缓存起来,用于后面的再次渲染。例如:

Vue.component(‘async-example‘, function (resolve, reject) {
  setTimeout(function () {
    // Pass the component definition to the resolve callback
    resolve({
      template: ‘<div>I am async!</div>‘
    })
  }, 1000)
})

可以看出来,异步组件基本可以实现楼主的需求,但是上面是 ES5 的写法,可以猜一下 ES6 的写法可能如下:

// 某个vue文件
export default function (resolve, reject) {
  // 远程加载你的模板
  apiService.then(data => {
    resolve({
      template: data
    })
  }
}

但是这个楼主没有实际用过,官方写的 ES5 可以把选项对象定义成一个工厂方函数,ES6 应该可以直接返回工厂函数。感兴趣的同学可以试一下然后告诉楼主。

楼主的方法

楼主没有用上面的异步组件(其实因为当时看不懂 囧),我在工作中使用的其实是 动态组件结合 Vue 的 computed 属性。灵感来源与 vue 论坛:innerhtml-compilation-vue
LinuxBorg 大神在论坛上回答另一个同学的提问时提到的,可以看到下面还有楼主的留言~

computed: {
  dynComponent() {
    const template = this.content ? this.content : ‘<div>nothing here yet</div>‘
    return {
      template, // use content as template for this component
      props: this.$options.props // re-use current props definitions
    }
}
<component is:="dynComponent" v-bind="$props"/>

即 computed 属性直接返回一个组件的选项对象,这个选项对象的模板可以异步获取,然后配合 动态组件 <component></component> 会帮你编译来自远程的模板,又由于 computed 属性的响应式特性,远程模板如果改变的话,就会自动重新编译咯~

当然楼主用的比这个复杂一些,会涉及到 v-model 等双向绑定,需要将这个组件再封装一层并且转换一下模板,这里就不细说了。

小结

总之呢,上面分析了在 VueJS 2.x 中编译远程模板的可能性,最后得出了两种方法:

  1. 异步组件,应该是官方的推荐方法
  2. 动态组件 + computed,变通之法,论坛上发现的思路

当然如果有其他方法欢迎交流,本文如果有不严谨不正确的地方也欢迎指出~

本文发自我的blog,原文链接我的blog

原文地址:https://www.cnblogs.com/homehtml/p/12212972.html

时间: 2024-11-06 03:30:33

VueJS 如何编译服务器端远程模板【异步组件+简单方法】的相关文章

前端-【学习心得】-模板渲染的简单方法

平时我们使用ajax请求完数据后通常都会有 一个渲染数据的过程,最开始的时候我的做法是在html界面做好数据模板,使用一些类似于angular的标记,然后用使用replace函数替换这些标记为真实的数据,后来再学习过程中找到了一个更加简洁的方法.该方法使用了正则表达式中的捕获数组的方法,完美实现了数据的渲染. var regexp = /(?:\{\{)([a-zA-z][^\s\}]+)(?:\}\})/gfunction render(template, data) {     return

ubuntu 环境下编译 hadoop 2.6.0的简单方法

由于服务器一般都64位系统, hadoop网站的release版本32位native库不能运行,所以需要自己在编译一下.以下是我采用的一个编译的过程,比较简单,不用下载各种版本及环境配置,通过命令就能自动完成了.系统环境为ubuntu server 64位版. 1.安装JDK,我这里使用的是OenJDK sudo apt-get install default-jdk java -version 显示版本信息: java version "1.7.0_65" OpenJDK Runti

vue异步组件和vue.router异步加载

以前在使用angular进行开发时,始终没有处理好异步加载的问题,最多只能使用requirejs异步加载controller里面的内容.导致后来项目扩大的时候,性能问题十分蛋疼.最后我竟然把单页面引用拆成了多页面应用,感觉好囧... 后来尝试用vue写一个项目,配合则webpack,发现效果相当的好.但是vue的异步组件文档太误导人了,让我尝试了好久才发现怎么用.文档上是这样写的: Vue.component('async-webpack-example', function (resolve)

C++ 模板的编译 以及 类模板内部的实例化

在C++中,编译器在看到模板的定义的时候,并不立即产生代码,只有在看到用到模板时,比如调用了模板函数 或者 定义了类模板的 对象的时候,编译器才产生特定类型的代码. 一般而言,在调用函数的时候,只需要知道函数的声明即可: 在定义类的对象时,只需要知道类的定义,不需要成员函数的定义. 但是,这对于模板编译是不奏效的,模板要进行实例化,则必须能够访问定义模板的源代码,当调用函数模板以及类模板的成员函数 的时候,需要知道函数的定义. 标准C++对于模板的编译提供了两种策略: 相同之处:"将类定义以及函

webpack 的异步组件 生成commonchunks

1 new webpack.optimize.CommonsChunkPlugin({ 3 async: 'async-common', 4 minChunks: function (module, count) { 5 // any required modules inside node_modules are extracted to vendor 6 return ( 7 count >= 2 8 ) 9 } 10 }) 上述代码是将异步组件的公共组件打包到async-common中,但

在Java Web Project中实现Vue异步组件加载

背景 最近看上了ElementUI(Vue实现)用来实现一个管理系统Demo,其中一个最常见的需求就是左侧导航不动,右侧主页块在点击导航菜单时动态更新,如下图所示:之前的实现方案是右边嵌入一个iframe,动态更改iframe的url即可,现在既然用了Vue咱也试试单页,是不是显得更优雅.接着就接触到了vue-router.组件.异步组件这些关键字,本以为把页面定义为xxx.vue放到webapp下,然后告诉vue-router去加载就好了,最后发现自己想简单了,思维模式还停留在Java Web

Vue动态组件&amp;异步组件

在动态组件上使用keep-alive 我们之前曾经在一个多标签的界面中使用is特性来切换不同的组件: <component v-bind:is="currentTabComponent"></component> 当在这些组件之间切换的时候,你有时会想保持这些组件的状态,以避免反复重渲染导致的性能问题. 如上是vue官网的例子,你会注意到如果你选择一篇文章,切换到Archive标签,然后切回Posts, 是不会继续展示你之前选择的文章的.因为你每次切换新标签的时

Vue异步组件Demo

Vue异步组件Demo 在大型应用中,我们可能需要将应用拆分为多个小模块,按需从服务器下载.为了进一步简化,Vue.js 允许将组件定义为一个工厂函数,异步地解析组件的定义.Vue.js 只在组件需要渲染时触发工厂函数,并且把结果缓存起来,用于后面的再次渲染. 下面是我写的一个简单Vue异步组件Demo. index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="

Vue动态加载异步组件

背景: 目前我们项目都是按组件划分的,然后各个组件之间封装成产品.目前都是采用iframe直接嵌套页面.项目中我们还是会碰到一些通用的组件跟业务之间有通信,这种情况下iframe并不是最好的选择,iframe存在跨域的问题,当然是postMessage还是可以通信的,但也并非是最好的.目前有这么一个场景:门户需要制作通用的首页和数据概览页面,首页和数据概览页面通过小部件来自由拼接.业务组件在制作的时候只需要提供各个模块小部件的url就可以了,可是如果小部件之间还存在联系呢?那么iframe是不好