I’m sure you’ve all seen Render in code or used it in some way, so if you’re still stuck with it, get in the car! I’ll bring you a plate of it today.
@[toc]
A brief introduction to Render’s information
The Render function is a function added to Vue2. X to improve node performance and is based on JavaScript calculations. Use the Render function to parse the node inside the Template into a virtual Dom.
Vue recommends using templates to create your HTML in most cases. However, in some scenarios, you really need the full programming power of JavaScript. In this case you can use render functions, which are closer to the compiler than templates.
To put it simply, in Vue we use template HTML syntax to build the page, using the Render function we can use Js language to build the DOM.
Since Vue is a virtual DOM, it also needs to be translated into a VNode function when it gets the Template. Using the Render function to build the DOM, Vue avoids the translation process.
First encounter with Render
When you first encounter it, it might look something like this:
- IView
render:(h, params)=>{
return h('div', {style:{width:'100px',height:'100px',background:'#ccc'}}, 'place')}Copy the code
- Element
<el-table-column :render-header="setHeader">
</el-table-column>
setHeader (h) {
return h('span', [
h('span', { style: 'line-height: 40px; ' }, 'note'),
h('el-button', {
props: { type: 'primary', size: 'medium', disabled: this.isDisable || ! this.tableData.length }, on: { click: this.save } },'Save current page')]])},Copy the code
Or this:
renderContent (createElement, { node, data, store }) {
return createElement('span', [// display tree node information createElement('span', node.label)
// ......
])
}
Copy the code
So what does it really look like? It starts with its history.
2.1. Nodes and trees
Before diving into rendering functions, it’s important to know a little bit about how browsers work. Take the following HTML for example:
<div> <h1>My title</h1> Some text content <! -- TODO: Add tagline --> </div>Copy the code
When the browser reads the code, it creates a tree of DOM nodes to keep track of everything, just as you would draw a family tree to track the progress of family members.
The DOM node tree corresponding to the above HTML is shown in the figure below:
Updating all of these nodes efficiently can be difficult, but fortunately you don’t have to do this manually. You just need to tell Vue what HTML you want on the page, which can be in a template:
<h1>{{ blogTitle }}</h1>
Copy the code
Or in a render function:
render: function (createElement) {
return createElement('h1', this.blogTitle)
}
Copy the code
In both cases, Vue automatically keeps the page updated even if the blogTitle changes.
2.2 virtual DOM
Vue tracks how it changes the real DOM by creating a virtual DOM. Take a closer look at this line of code:
return createElement('h1', this.blogTitle)
Copy the code
What exactly does createElement return? It’s not really an _ actual _ DOM element. It might be more accurately called createNodeDescription, because it contains information that tells the Vue what nodes need to be rendered on the page, including descriptions of their children. We describe such a node as a “virtual node”, often abbreviated to “VNode”. “Virtual DOM” is the name we use for the entire VNode tree built from the Vue component tree.
Note: When using the render function to describe the virtual DOM, vue provides a function that is the tool needed to build the virtual DOM. It’s called createElement on its website. There is also a shorthand for the convention called H, and using H as an alias for createElement is a common convention in the Vue ecosystem, and is actually required by JSX. = =
This is createElement, so let’s take a closer look at it
3. date with Render
3.1 createElement method parameter
CreateElement (TagName, Option, Content) takes three parameters createElement(” element defined “, {element properties}, “element contents “/[element contents])
- The official documentation
/ / @ returns {VNode} createElement method (/ / {String | Object | Function} / / an HTML tag name, component options Object, Or // resolve an async function of any of the above. Required fields.'div'// {Object} // A data Object corresponding to the attributes in the template. Optional. {/ / (see the next section 3.2 in-depth data objects)}, / / {String | Array} / / child level (VNodes), virtual node by ` createElement method () is constructed from the `, / / you can also use the String to generate the "text" virtual node. Optional. ['Write some words first.',
createElement('h1'.'A headline'),
createElement(MyComponent, {
props: {
someProp: 'foobar'}})])Copy the code
3.2 Delve into data objects
{// Same API as' v-bind:class ', // accepts a string, an object, or an array of strings and objects'class': {
foo: true,
bar: false}, // Same API as' v-bind:style ', // accept a string, an object, or an array of objects style: {color:'red',
fontSize: '14px'}, // Plain HTML attrs: {id:'foo'}, // prop props: {myProp:'bar'}, // DOM properties domProps: {innerHTML:'baz'}, // Event listeners are in the 'on' property, // but modifiers such as' V-on :keyup.enter 'are no longer supported. // keyCode needs to be checked manually in the handler. 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}}], / / scope of slot format for / / {name: props = > VNode | Array < VNode >} scopedSlots: {default: props = > createElement method ('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'// If you apply the same ref name to multiple elements in the render function, // then '$refsMyRef 'becomes an array. refInFor:true
}
Copy the code
3.3 Give me a chestnut
render:(h) => {
return h('div',{       // to div props: {value:' '},       // bind div style       style:{           width:'30px'      },        // bind the div click event     on: { click: () => { console.log('Click event')}},})}Copy the code
3.4 the constraint
He has a temper, too. Remember this restriction
- The VNode must be unique
All VNodes in the component tree must be unique. This means that the following render functions are not valid:
render: function (createElement) {
var myParagraphVNode = createElement('p'.'hi')
return createElement('div', [// Error - Repeated VNode myParagraphVNode, myParagraphVNode])}Copy the code
If you really need to repeat elements/components a lot, you can use factory functions to do it. For example, the following render function renders 20 identical paragraphs in a perfectly legal way:
render: function (createElement) {
return createElement('div',
Array.apply(null, { length: 20 }).map(function () {
return createElement('p'.'hi')}}))Copy the code
The above are the basics, you should keep in mind yo, here are some of its features
Fourth, Render the small personality
4.1 v – if and v – for
Vue’s rendering functions do not provide proprietary alternatives to what can easily be done in native JavaScript. For example, v-if and v-for are used in templates:
<ul v-if="items.length">
<li v-for="item in items">{{ item.name }}</li>
</ul>
<p v-else>No items found.</p>
Copy the code
These can be overridden in the render function using JavaScript’s if/else and map:
props: ['items'],
render: function (createElement) {
if (this.items.length) {
return createElement('ul', this.items.map(function (item) {
return createElement('li', item.name)
}))
} else {
return createElement('p'.'No items found.')}}Copy the code
4.2 v – model
There is no direct counterpart to the V-Model in the rendering function — you have to implement the logic yourself:
props: ['value'],
render: function (createElement) {
var self = this
return createElement('input', {
domProps: {
value: self.value
},
on: {
input: function (event) {
self.$emit('input', event.target.value)
}
}
})
}
Copy the code
That’s the price of going deep, but it gives you a lot more control over the interaction details than a V-Model.
4.3 Event & key modifier
For.passive,.capture, and.once event modifiers, Vue provides prefixes that can be used with on:
The modifier | The prefix |
---|---|
.passive |
& |
.capture |
! |
.once |
~ |
.capture.once or.once.capture |
~! |
Such as:
on: {
'! click': this.doThisInCapturingMode,
'~keyup': this.doThisOnce,
'~! mouseover': this.doThisOnceInCapturingMode
}
Copy the code
For all other modifiers, private prefixes are not required, because you can use event methods in event handlers:
The modifier | Handle equivalent operations in functions |
---|---|
.stop |
event.stopPropagation() |
.prevent |
event.preventDefault() |
.self |
if (event.target ! == event.currentTarget) return |
Keys:.enter .13. |
if (event.keyCode ! == 13) return For other key modifiers, it can be13 Change to another keycode) |
Modifier keys:.ctrl ..alt ..shift ..meta |
if (! event.ctrlKey) return (will bectrlKey Change toaltKey ,shiftKey ormetaKey ) |
Here is an example using all modifiers:
on: {
keyup: function(event) {// Returns if the element that triggers the event is not an element of the event bindingif(event.target ! == event.currentTarget)return// If the press is not Enter or // is not simultaneously pressedshiftThe key // returnsif(! event.shiftKey || event.keyCode ! = = 13)return// Prevent event bubblings event.stopPropagation() // Prevent the element's default keyup event.preventDefault() // preventDefault... }}Copy the code
4.4 slot
You can access the contents of static slots via this.$slots, where each slot is an array of vNodes:
render: function (createElement) {
// `<div><slot></slot></div>`
return createElement('div', this.$slots.default)
}
Copy the code
You can also access the scope slots via this.$scopedSlots. Each scope slot is a function that returns a number of VNodes:
props: ['message'],
render: function (createElement) {
// `<div><slot :text="message"></slot></div>`
return createElement('div', [
this.$scopedSlots.default({
text: this.message
})
])
}
Copy the code
To pass a scope slot to a child component using a render function, you can use the scopedSlots field in the VNode data object:
render: function (createElement) {
return createElement('div', [
createElement('child'{/ / in the data object transfer ` scopedSlots ` / / format for {name: props = > VNode | Array < VNode >} scopedSlots: {default:function (props) {
return createElement('span', props.text)
}
}
})
])
}
Copy the code
Five, the actual combat
Element in the Tree
RenderContent (h, {node, data, store}) {let aa = () => {
console.log(data)
}
return h('span', [
h('span', {
class: "custom-tree-node"
}, [
h('i', { class: "icon-folder" }), h('span', { props: { title: node.label }, class: "text ellipsis" }, node.label),
h('el-popover', {
props: {
placement: "bottom",
title: "",
width: "61",
popperClass: "option-group-popover",
trigger: "hover"
}
}, [
h('ul', { class: "option-group" }, [
h('li', {
class: "pointer-text",
on: {
click: aa
}
}, 'edit'),
h('li', { class: "pointer-text" }, 'delete'),
h('li', { class: "pointer-text" }, 'add')
]),
h('i', { slot: "reference", class: "el-icon-more fr more-icon", on: { click: (e) => { e.stopPropagation(); }}})])])]))},Copy the code
Extension -JSX
If you write a lot of render functions, you might find the following code a pain to write:
createElement(
'anchored-heading', {
props: {
level: 1
}
}, [
createElement('span'.'Hello'),
' world! '])Copy the code
Especially if the corresponding template is so simple:
<anchored-heading :level="1">
<span>Hello</span> world!
</anchored-heading>
Copy the code
That’s why there’s a Babel plug-in for using JSX syntax in Vue, which brings us back to a more template-like syntax.
import AnchoredHeading from './AnchoredHeading.vue'
new Vue({
el: '#demo',
render: function (h) {
return (
<AnchoredHeading level={1}>
<span>Hello</span> world!
</AnchoredHeading>
)
}
})
Copy the code