您好,登錄后才能下訂單哦!
Vue中怎么動態添加模板,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
例如要做一個類 select 的組件,用戶傳入 options 數據,通過 value prop 獲取選中值,最基本的原型如下。
Vue.component('XSelect', { template: ` <div class="select"> <input :value="value" readonly /> <div class="option" v-for="option in options" @click="value = option.value"> <span v-text="option.label"></span> </div> </div>`, props: ['value','options'] })
如果此時需要增加一個 API 支持讓用戶自定義 option 部分的模板。此處用 slot 并不能解決問題。
通過 $options.template 修改
通過打印組件對象可以獲得一個信息,在 $options 里定義了一個 template 屬性,寫在 template 標簽里的模板,最終編譯后也會在 $options.template 里。通過文檔的生命周期 可以得知,在 created 的時候, 實例已經結束解析選項, 但是還沒有開始 DOM 編譯 也就是說,如果用戶通過 prop 的數據我們可以獲得,但是模板其實還沒有渲染成 DOM。經過測試,在 created
修改 this.$options.template
是可以改變最終生成的 DOM 的,同時也能拿到 props 的內容。
那么我們可以修改下代碼,使其支持自定義模板
Vue.component('XSelect', { props: [ 'value', 'options', { name: 'template', default:'<span v-text="option.label"></span>' } ], created() { varoptionTpl =this.template this.$options.template =` <div class="select"> <input :value="value" readonly /> <div class="option" v-for="option in options" @click="value = option.value"> ${optionTpl} </div> </div>` } })
用戶使用是就可以傳入模板了
<x-select :value.sync="value" template="<span>標簽: {{ option.label }}, 值: {{ option.value }}</span>" :options="[ {value: 1, label: 'a'}, {value: 2, label: 'b'}, {value: 3, label: 'c'} ]"> </x-select>
可能存在的問題
我們知道 Vue 在內部幫我們做了許多優化,但是在這里可能會由于某些優化導致動態拼接的模板無法渲染成功。例如這里我們不使用 v-for 而是手工遍歷 options 生成需要的 HTML
consttpl = options.map(opt =>`<div>${this.optionTpl}</div>`) this.$options.template =` <div class="select"> <input :value="value" readonly> ${tpl} </div>`
這里會導致一個 BUG,如果一個頁面有多個 x-select 組件,并且 options 長度不一樣,會導致長的 options 的組件后面幾個選項渲染不出來。究其原因是 Vue 會幫我們緩存模板編譯結果。翻看代碼可以找到 vue/src/instance/internal/lifecycle.js 里有做優化,同時提供的 _linkerCachable 本意是給 內聯模板 使用。我們可以通過設置 this.$options._linkerCachable = false
達到我們的目的。
這樣我們就可以開發讓用戶自定義布局的組件了,用戶傳入布局參數,通過手工拼接模板,設置了 _linkerCachable = false
也不會被緩存。
通過 $options.partials 動態添加 partial
使用 partials 也能達到添加自定義模板的目的,但是通常的做法是要全局注冊 partial,這么做并不優雅。 vue-strap 就是這么做的。如果重名了會被覆蓋(初次渲染不會,但是數據更新重新渲染 DOM 時就會被覆蓋)。
通過文檔我們知道可以在組件內部通過 partials 屬性注冊局部的 partial,因此自然而然也可以在 this.$options.partials 去動態添加了。
Vue.component('XSelect', { template: ` <div class="select"> <input :value="value" readonly /> <div class="option" v-for="option in options" @click="value = option.value"> <partial name="option"></partial> </div> </div>`, props: ['template','value','options'], partials: { option: '<span v-text="option.label"></span>' }, created() { if(this.template) { this.$options.partials.option =this.template } } })
用 interpolate 渲染模板
這種方式就略顯蛋疼,而且效率最差。 interpolate 也是我最開始做動態渲染模板想到的方式,不推薦使用。
Vue.component('XSelect', { template: ` <div class="select"> <input :value="value" readonly /> <div class="option" v-for="option in options" @click="value = option.value" v-html="renderOption(option)"> </div> </div>`, props: [ 'value', 'options', { name: 'template', default:'<span v-text="option.label"></span>' } ], methods: { renderOption(option) { this.option = option returnthis.$interpolate(this.template) } } })
Vue2.0
目前并沒有找到合適的解決方案。2.0 的 Vue 將 compile 工作提前,并且 compiler 也是單獨一個包(除非你直接引用的是 vue.js 文件,包含 compiler 和 runtime,那么第一種方法是適用的),那么并不能動態的生成模板。除非用戶傳入的是 render 能識別的 DOM tree。
按照這樣的思路,其實可以讓用戶傳入的模板預先編譯好,傳入到組件內,拼接 DOM tree 看起來也能解決問題。那么可以這么玩。
看看就好, 性能太渣
首先要安裝 Vue JSX 的 相關插件
組件
Vue.component({ name: 'XSelect', render(h) { // 這里獲得的 this.template 其實是一個函數,調用該函數返回 DOM // 因此這里的關鍵代碼是拼接一個新的函數,接受 `option` 參數以及上下文 // 使用 new Function 創建一個新函數 return( <divclass="select"> <inputvalue={this.value}readonly/> { this.options.map(option => <div on-click={() => this.$emit('input', option.value) } class="option"> { new Function('option', 'return ' + this.template)(option)(h) } </div> ) } </div>) }, props: ['template', 'value', 'options'] })
入口文件
newVue({ el: '#app', data () { return{ value: '' } }, created() { // 初始化需要傳入的模板,這里會被 Vue 的 JSX 插件轉成 DOM tree this.template = h =><span>標簽: { option.label }, 值: { option.value }</span> }, render(h) { return( <x-select v-model="value" :template="template" :options="[ {value: 1, label: 'a'}, {value: 2, label: 'b'}, {value: 3, label: 'c'} ]"> </x-select>) } })
綜上,在 Vue 1.x 里不存在 預編譯
的概念,所以想動態修改模板還是有許多方式的,甚至還可以結合 <slot></slot>
取到 slot
里的內容拼接進模板里。但 2.0 就麻煩了,并找不到理想的方法。
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。