Introduction to the
When using Vue for development, most cases are using template for development, using template is simple, convenient, fast, but sometimes need special scenarios using template is not very suitable. So to make good use of the Render function, I decided to take a closer look. If you feel that the following is not correct, please point out that your interaction with me is the biggest motivation for writing. Inside the mystery of Vue Render
scenario
When we started to write a component that dynamically generates heading tags using Level Prop, you probably immediately thought of this implementation:
<script type="text/x-template" id="anchored-heading-template">
<h1 v-if="level === 1">
<slot></slot>
</h1>
<h2 v-else-if="level === 2">
<slot></slot>
</h2>
<h3 v-else-if="level === 3">
<slot></slot>
</h3>
<h4 v-else-if="level === 4">
<slot></slot>
</h4>
<h5 v-else-if="level === 5">
<slot></slot>
</h5>
<h6 v-else-if="level === 6">
<slot></slot>
</h6>
</script>
Copy the code
Vue.component('anchored-heading', {
template: '#anchored-heading-template',
props: {
level: {
type: Number,
required: true}}})Copy the code
Using template is not the best choice in this scenario: the code is verbose, and we need to use it repeatedly in order to insert anchor elements in different levels of headers.
While templates are great for most components, they are not very neat here. So, let’s try to rewrite the above example using the render function:
Vue.component('anchored-heading', {
render: function (createElement) {
return createElement(
'h'+ this.level, // tag name Tag name this.$slots.default // Array in subcomponents)}, props: {level: {type: Number,
required: true}}})Copy the code
Much simpler and clearer! In short, the code is much simpler, but you need to be very familiar with Vue instance properties. In this example, you need to know when you’re not using the slot attribute to pass content to the component, like the Hello World! In anchored-heading. These child elements are stored in $slots.default in the component instance.
CreateElement Parameter Description
The next thing you need to be familiar with is how to generate templates in the createElement function. Here are the parameters accepted by createElement:
The createElement method (/ / {String | Object | Function} / / an HTML tag String, component options Object, or / / resolution of any of these an asynchronous Function, async necessary parameters.'div'// {Object} // A data Object containing template-related attributes // So that you can use these attributes in the template. This parameter is optional. {/ / (see the next section)}, / / {String | Array} / / child nodes (VNodes), by ` createElement method () is constructed from the `, / / or using a String to generate a text node. This parameter is optional. ['Write some words first.',
createElement('h1'.'A headline'),
createElement(MyComponent, {
props: {
someProp: 'foobar'}})])Copy the code
Digging into data objects
One thing to note: Just as v-bind:class and V-bind :style are treated specially in template syntax, the following attribute names are the highest-ranking fields in a VNode data object. The object also allows you to bind normal HTML properties, like DOM properties, such as innerHTML (which replaces the V-HTML directive).
{// Same API as' v-bind:class ''class': {
foo: true,
bar: false}, // The same API as' v-bind:style 'style: {color:'red',
fontSize: '14px'}, // Normal HTML attrs: {id:'foo'
},
// 组件 props
props: {
myProp: 'bar'}, // DOM properties domProps: {innerHTML:'baz'}, // Event listeners are based on 'on' // so modifiers such as' V-on :keyup. Enter 'are no longer supported // Need to manually match keyCode. On: {click: this.clickHandler}, // for components only, used to listen for native events, not for component internal use // 'VM.$emit'triggered event. NativeOn: {click: this.nativecLickHandler}, // custom directive. Note that you cannot assign a value to 'oldValue' // in 'binding' because Vue has automatically synchronized for you. directives: [ { name:'my-custom-directive',
value: '2',
expression: '1 + 1',
arg: 'foo',
modifiers: {
bar: true
}
}
],
// Scoped slots in the form of
// { name: props => VNode | Array<VNode> }
scopedSlots: {
default: props => createElement('span', props. Text)}, // If the component is a child of another component, give the slot a name:'name-of-slot'// Other special top-level attributes key:'myKey',
ref: 'myRef'
}
Copy the code
Conditions apply colours to a drawing
Now that you’ve read the API above, let’s get a little hands-on. I wrote it like this
//HTML
<div id="app">
<vv-isshow :show="isShow"></vv-isshow> </div>'vv-isshow', {
props:['show'],
template:
'
}); var vm = new Vue({ el:"#app",
data: {
isShow:true}});Copy the code
Render it
//HTML
<div id="app">
<vv-isshow :show="isShow"><slot> I was found by you 3!! < / slot > < / vv - isshow > < / div > / / js / / component form ponent (Vue.com'vv-isshow', {
props:{
show:{
type: Boolean,
default: true
}
},
render:function(h){
if(this.show ) return h('div',this.$slots.default); }}); var vm = new Vue({ el:"#app",
data: {
isShow:true}});Copy the code
The list of rendering
It was written this way, and the template must be wrapped with a tag for v-for
//HTML
<div id="app">
<vv-aside v-bind:list="list"></vv-aside> </div>'vv-aside', {
props:['list'],
methods:{
handelClick(item){
console.log(item);
}
},
template:'
\
{{item.txt}}
\
',
//template:'<div v-for="item in list" @click="handelClick(item)" :class="{odd:item.odd}">{{item.txt}}</div>'Error}); var vm = new Vue({ el:"#app",
data: {
list: [{
id: 1,
txt: 'javaScript',
odd: true
}, {
id: 2,
txt: 'Vue',
odd: false
}, {
id: 3,
txt: 'React',
odd: true}}}]);Copy the code
Render it
//HTML
<div id="app">
<vv-aside v-bind:list="list"></vv-aside> </div>'vv-aside', {
render: function(h) {
var _this = this,
ayy = this.list.map((v) => {
return h('div', {
'class': {
odd: v.odd
},
attrs: {
title: v.txt
},
on: {
click: function() {
return _this.handelClick(v);
}
}
}, v.txt);
});
return h('div', ayy);
},
props: {
list: {
type: Array,
default: () => {
return this.list || [];
}
}
},
methods: {
handelClick: function(item) {
console.log(item, "item"); }}}); var vm = new Vue({ el:"#app",
data: {
list: [{
id: 1,
txt: 'javaScript',
odd: true
}, {
id: 2,
txt: 'Vue',
odd: false
}, {
id: 3,
txt: 'React',
odd: true}}}]);Copy the code
v-model
The way I wrote it before
//HTML
<div id="app">
<vv-models v-model="txt" :txt="txt"></vv-models>
</div>
//js
//input
Vue.component('vv-models', {
props: ['txt'],
template: '< div >, < p > the reader what you input is: {{txtcout}} < / p > \ < input v - model = "txtcout" type = "text" / > \ < / div >',
computed: {
txtcout:{
get() {return this.txt;
},
set(val){
this.$emit('input', val); }}}}); var vm = new Vue({ el:"#app",
data: {
txt: ' ',}});Copy the code
Render it
//HTML
<div id="app">
<vv-models v-model="txt" :txt="txt"></vv-models>
</div>
//js
//input
Vue.component('vv-models', {
props: {
txt: {
type: String,
default: ' '
}
},
render: function(h) {
var self=this;
return h('div',[h('p'.'Guess what I typed:'+this.txt),h('input',{
on:{
input(event){
self.$emit('input', event.target.value); }}})]); }}); var vm = new Vue({ el:"#app",
data: {
txt: ' ',}});Copy the code
conclusion
Render function is the use of JavaScript full programming ability, in performance is an absolute advantage, xiaobian just to analyze it. As for the actual project, the way you choose to render will still depend on your project and the actual situation.