SoFunction
Updated on 2025-04-04

Detailed explanation of several ways to dynamically add templates for Vue

The following method is only applicable to Vue1.0 version, and the recommended coefficients are arranged from high to low.

Usually we define the template in the template attribute in the component, or *.vue Write a template in the template tag in the file. But sometimes there is a need to dynamically generate templates, such as allowing users to customize component templates, or set up component layouts.

For example, to make a component of the class select, the user passes in options data and gets the selected value through value prop. The most basic prototype is as follows.

('XSelect', {
 template: `
 <div class="select">
 <input :value="value" readonly />
 <div
 class="option"
 v-for="option in options"
 @click="value = ">
 <span v-text=""></span>
 </div>
 </div>`,

 props: ['value','options']
})

If you need to add an API to support the template that allows users to customize the option part. Using slot here does not solve the problem.

Modify by $

By printing component objects, you can obtain an information,$options A template attribute is defined in the template tag, and the template is also written in $ after final compilation. Through the documentlife cycleIt can be seen that when created, the instance has ended the parsing option, but the DOM compilation has not started yet. That is to say, if the user passes the data of prop, we can obtain it, but the template has not actually been rendered to DOM. After testing,createdRevise this.$ It can change the final generated DOM, and also get the content of props.

Then we can modify the code to support custom templates

('XSelect', {
 props: [
'value',
'options',
 {
 name: 'template',
default:'<span v-text=""></span>'
 }
 ],

 created() {
varoptionTpl =

this.$ =`
 <div class="select">
 <input :value="value" readonly />
 <div
 class="option"
 v-for="option in options"
 @click="value = ">
${optionTpl}
 </div>
 </div>`
 }
})

Users can pass in templates when using

&lt;x-select
:="value"
template="&lt;span&gt;Label: {{  }}, value: {{  }}&lt;/span&gt;"
:options="[
 {value: 1, label: 'a'},
 {value: 2, label: 'b'},
 {value: 3, label: 'c'}
 ]"&gt;
&lt;/x-select&gt;

Possible problems

We know that Vue has helped us with many optimizations internally, but here it may cause dynamically spliced ​​templates to fail to render successfully due to some optimizations. For example, we do not use v-for but manually traverse options to generate the required HTML

consttpl = (opt =>`<div>${}</div>`)

this.$ =`
 <div class="select">
 <input :value="value" readonly>
${tpl}
 </div>`

This will cause a bug. If a page has multiple x-select components and the options length is different, the following options for the long options component cannot be rendered. The reason is that Vue will help us cache the template compilation results. You can find it by looking through the codevue/src/instance/internal/ _linkerCachable is provided in the optimization, and the original purpose of providing inline templates is to be used. We can set it up this.$options._linkerCachable = false To achieve our goals.

In this way, we can develop components that allow users to customize layouts. The user passes in layout parameters and sets them by manually splicing the template. _linkerCachable = false It will not be cached either.

Dynamically add partial via $

Using partials can also achieve the purpose of adding custom templates, but the usual practice is to register partial globally, which is not elegant.vue-strap That's what it does. If the name is renamed, it will be overwritten (it won't be the first rendering, but it will be overwritten when the data is updated and re-rendered).

Through the documentation, we know that local partials can be registered inside the component through the partials attribute, so naturally it can be added dynamically in this.$.

('XSelect', {
 template: `
 <div class="select">
 <input :value="value" readonly />
 <div
 class="option"
 v-for="option in options"
 @click="value = ">
 <partial name="option"></partial>
 </div>
 </div>`,

 props: ['template','value','options'],

 partials: {
 option: '<span v-text=""></span>'
 },

 created() {
if() {
this.$ =
 }
 }
})

Render templates with interpolate

This method is slightly more efficient and has the worst efficiency. Interpolate is also the way I thought of when I first made dynamic rendering templates, and it is not recommended to use them.

('XSelect', {
 template: `
 <div class="select">
 <input :value="value" readonly />
 <div
 class="option"
 v-for="option in options"
 @click="value = "
 v-html="renderOption(option)">
 </div>
 </div>`,

 props: [
'value',
'options',
 {
 name: 'template',
default:'<span v-text=""></span>'
 }
 ],

 methods: {
 renderOption(option) {
 = option
returnthis.$interpolate()
 }
 }
})

Vue2.0

No suitable solution has been found yet. Vue in 2.0 works ahead of time, and compiler is also a separate package (unless you directly refer to a file, including compiler and runtime, the first method is applicable), so you cannot dynamically generate templates. Unless the user passes in a DOM tree that render can recognize.

According to this idea, the template passed by the user can be precompiled and passed into the component, and splicing the DOM tree seems to solve the problem. Then it can be played like this.

Just look at it, the performance is too bad

First, you need to install the relevant plug-ins for Vue JSX

Components

({
 name: 'XSelect',

 render(h) {
// What you get here is actually a function, and calling this function returns DOM// Therefore, the key code here is to splice a new function, accept the `option` parameter and the context// Create a new function using new function
return(
&lt;divclass="select"&gt;
&lt;inputvalue={}readonly/&gt;
 {
 (option =&gt;
&lt;div
on-click={() =&gt; this.$emit('input', ) }
 class="option"&gt;
 { new Function('option', 'return ' + )(option)(h) }
&lt;/div&gt;
 )
 }
&lt;/div&gt;)
 },

 props: ['template', 'value', 'options']
})

Entry file

newVue({
 el: '#app',

 data () {
return{
 value: ''
 }
 },

 created() {
// Initialize the template that needs to be passed in, here it will be converted into DOM tree by Vue's JSX plug-in = h =&gt;&lt;span&gt;Label: {  }, value: {  }&lt;/span&gt;
 },

 render(h) {
return(
&lt;x-select
v-model="value"
:template="template"
:options="[
 {value: 1, label: 'a'},
 {value: 2, label: 'b'},
 {value: 3, label: 'c'}
 ]"&gt;
&lt;/x-select&gt;)
 }
})

In summary, it does not exist in VuePrecompiledThe concept of this, so there are still many ways to dynamically modify the template, and you can even combine it with <slot></slot>Get itslot The contents in it are spliced ​​into the template. But 2.0 is troublesome and can't find the ideal method.

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.