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.