有些时候你可能须要从后台获取模板,并在前台在本身编译,这在用 AngularJS 1.x 的时候彷佛很常见,能够直接用 ng-include
搞定,在 Vue 1.x 的时候也能够直接用 partial
搞定。
可是在 Vue 2.x 中,官方取消了 partial
这个 API,根据状况推荐使用 component 代替,参见这里html
那我如今有个需求,就是从后台获取一个字符串模板(假设里面包含 v-model 等 vue 指令),模板须要拿到前台来编译,那该怎么实现呢?
(这种需求确实比较少见,可是是存在的。。。)vue
官方根据状况推荐了三种替代 partial 的方式,分别为:webpack
normal component
常规组件,没有处于性能关键区域(简单来讲就是对性能有较大影响)时使用git
dynamic component
动态组件,根据组件名称动态绑定时使用github
functional component
函数组件,处于性能关键区域时使用web
另外根据文档中的的状况来看:api
异步组件和高级异步组件
(异步组件) 也可能解决楼主的问题数组
下面来分别分析一下:缓存
用法服务器
// 注册 Vue.component('my-component', { template: '<div>A custom component!</div>' }) // 建立根实例 new Vue({ el: '#example' })
这是常规组件的注册方法
先来看下 Vue 实例的声明周期图,摘自官网:
图中黄色的部分,能够看出 vue 实例的模板是来自哪里的?
el
选项提供的选择器
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 中编译远程模板的可能性,最后得出了两种方法:
异步组件,应该是官方的推荐方法
动态组件 + computed,变通之法,论坛上发现的思路
固然若是有其余方法欢迎交流,本文若是有不严谨不正确的地方也欢迎指出~
本文发自个人blog,原文连接: 个人blog