有些時候你可能須要從後臺獲取模板,並在前臺在本身編譯,這在用 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