In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-01 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article introduces you how to understand the rendering function and JSX, the content is very detailed, interested friends can refer to, hope to be helpful to you.
I. Foundation
Vue recommends using templates to create your HTML in most cases. In some scenarios, however, you really need the full programming capabilities of JavaScript. At this point, we can use the rendering function, which is closer to the compiler than the template.
Let's go into a simple example where the render function is very useful. Suppose we want to generate some headings with anchors:
Hello world!
For the HTML above, we decided to define the component interface as follows:
Hello world!
When you start writing a component that can only dynamically generate headings (heading) through level prop, you may quickly think of this:
Vue.component ('anchored-heading', {template:' # anchored-heading-template', props: {level: {type: Number, required: true})
Using a template is not the best choice here: not only is the code verbose, but it is repeated at each level of the title, again when you want to insert an anchor element.
Although templates are very useful in most components, it is obviously not appropriate 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 this.$slots.default / / child node array)}, props: {level: {type: Number, required: true}})
It looks a lot easier! The code is much simpler, but you need to be very familiar with the instance property of Vue. In this example, you need to know that when passing child nodes without v-slot instructions to a component, such as Hello worldnodes in anchored-heading, these child nodes are stored in $slots.default in the component instance. If you don't already know it, it is recommended to read the instance property API before delving into the rendering function.
2. Nodes, trees and virtual DOM
Before diving into rendering functions, it is important to understand how some browsers work. Take the following HTML as an example:
My title Some text content
When the browser reads the code, it creates a "DOM node" tree to keep track of everything, just as you draw a family tree to track the development of family members.
The DOM node tree corresponding to the above HTML is shown in the following figure:
Each element is a node. Each paragraph of text is also a node. Even comments are nodes. A node is a part of the page. Just like a family tree, each node can have a child node (that is, each part can contain other parts).
It can be difficult to update all of these nodes efficiently, but fortunately you don't have to do it manually. You just need to tell Vue what you want the HTML on the page to be, which can be in a template:
{{blogTitle}}
Or in a rendering function:
Render: function (createElement) {return createElement ('H2, this.blogTitle)}
In both cases, Vue automatically keeps the page up-to-date, even if blogTitle changes.
1. Virtual DOM
Vue tracks how he wants to change the real DOM by creating a virtual DOM. Please look at this line of code carefully:
Return createElement ('H2, this.blogTitle)
What exactly will createElement return? It's not really an actual DOM element. Its more accurate name may be createNodeDescription because it contains information that tells the Vue page what nodes to render, including descriptions of their child nodes. We describe such a node as "virtual node" and often abbreviate it as "VNode". "Virtual DOM" is what we call the entire VNode tree built by the Vue component tree.
3. CreateElement parameters
The next thing you need to be familiar with is how to use those functions in the template in the createElement function. Here are the parameters accepted by createElement:
/ / @ returns {VNode} createElement (/ / {String | Object | Function} / / a HTML signature, component option object, or / resolve contains an async function of any of the above. Required. 'div', / / {Object} / / A data object corresponding to the attribute in the template. Optional. {/ / (see next section for details)}, / / {String | Array} / / Child virtual node (VNodes), which is constructed from `virtual node () `. / / you can also use strings to generate "text virtual nodes". Optional. ['write some text first', createElement ('H2,'a headline'), createElement (MyComponent, {props: {someProp: 'foobar'}})]) 1. Go deep into the data object
One thing to note: just as v-bind:class and v-bind:style are treated specially in template syntax, they also have corresponding top-level fields in the VNode data object. This object also allows you to bind a normal HTML attribute as well as a DOM property such as innerHTML (which overrides the v-html instruction).
{/ / is the same as the API of `v-bind: class`, / / accepts a string, object or an array of strings and objects' class': {foo: true, bar: false}, / / same as the API of `style`, / / accepts a string or object Or an array of objects style: {color: 'red', fontSize:' 14px'}, / / ordinary HTML attribute attrs: {id: 'foo'}, / / component prop props: {myProp:' bar'}, / / DOM property domProps: {innerHTML: 'baz'}, / / event listener is in `on` / / but modifiers such as `keyup.enter` are no longer supported. / / you need to check the keyCode manually in the handler. On: {click: this.clickHandler}, / / is only used for components to listen for native events, rather than events triggered by / / `vm.$ emit` within the component. NativeOn: {click: this.nativeClickHandler}, / / Custom directive. Note that you cannot assign a value to `oldValue` / / in `binding` because Vue has automatically synchronized it for you. Directives: [{name: 'my-custom-directive', value:' 2', expression:'1 + 1', arg: 'foo', modifiers: {bar: true}}], / / the format of the scope slot is / / {name: props = > VNode | Array} scopedSlots: {default: props = > createElement (' span', props.text)} / / if the component is a subcomponent of another component You need to specify the name of the slot slot: 'name-of-slot', / / other special top-level property key:' myKey', ref: 'myRef', / / if you apply the same ref name to multiple elements in the rendering function, / / then `$ refs.myRef` will become an array. RefInFor: true} 2, complete example
With this knowledge, we can now complete the components we originally wanted to implement:
Var getChildrenTextContent = function (children) {return children.map (function (node) {return node.children? GetChildrenTextContent (node.children): node.text}) .join ('')} Vue.component ('anchored-heading', {render: function (createElement) {/ / create kebab-case style ID var headingId = getChildrenTextContent (this.$slots.default) .toLowerCase (). Replace (/\ Whiplash g,' -'). Replace (/ (^-|-$) / g,'') return createElement ('h' + this.level) [createElement ('type, {attrs: {name: headingId, href:' #'+ headingId}}, this.$slots.default)]}, props: {level: {type: Number, required: true}}) 3, constraint
VNode must be unique
All VNode in the component tree must be unique. This means that the following rendering functions are illegal:
Render: function (createElement) {var myParagraphVNode = createElement ('paired,' hi') return createElement ('div', [/ / error-duplicate VNode myParagraphVNode, myParagraphVNode])}
If you really need to repeat the element / component many times, you can use the factory function to implement 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 (' packs, 'hi')})) IV. Use JavaScript instead of template function 1, v-if and v-for
Vue's rendering functions do not provide proprietary alternatives as long as they can be easily done in native JavaScript. For example, v-if and v-for are used in templates:
{{item.name}} No items found.
These can be overridden with JavaScript's if/else and map in the render function:
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 (' packs,'No items found.')} 2, v-model
There is no direct correspondence to v-model in the rendering function-you must implement the corresponding 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)}})})}
This is the price of going deep into the bottom, but it gives you more control over the details of the interaction than v-model.
3. Event & key modifier
For event modifiers such as .passive, .capture, and .once, Vue provides the appropriate prefixes that can be used for on:
The modifier prefix .passive & .capture! .once ~ .capture.once or .once.capture ~!
For example:
On: {'! click': this.doThisInCapturingMode,'~ keyup': this.doThisOnce,'~! mouseover': this.doThisOnceInCapturingMode}
For all other modifiers, private prefixes are not required because you can use event methods in event handlers:
The modifier handles the equivalent operation in the function .stopevent.stopPropagation (). Selfif (event.target! = = event.currentTarget) return key: .enter, .13if (event.keyCode! = = 13) return (for other key modifiers, 13 can be changed to another key code) modifier: .ctrl, .alt, .shift, .metaif (! event.ctrlKey) return (modify ctrlKey to altKey, shiftKey, or metaKey, respectively)
Here is an example of using all modifiers:
On: {keyup: function (event) {/ / return if (event.target! = = event.currentTarget) return / / if the element triggering the event is not an event bound element / / return if (! event.shiftKey | | event.keyCode! = = 13) return / / if the enter key is not pressed or / / the shift key / / is not pressed at the same time Event bubbling event.stopPropagation () / / blocks the element's default keyup event event.preventDefault () / /.} 4, Slot
You can access the contents of static slots through this.$slots, each of which is a VNode array:
Render: function (createElement) {/ / ``return createElement ('div', this.$slots.default)}
Scope slots can also be accessed through this.$scopedSlots, where each scope slot is a function that returns several VNode:
Props: ['message'], render: function (createElement) {/ / ``return createElement (' div', [this.$scopedSlots.default ({text: this.message})])}
If you want to use the rendering function to pass scope slots to the subcomponents, you can take advantage of the scopedSlots field in the VNode data object:
Render: function (createElement) {/ / `{props.text}} `return createElement ('div', [createElement (' child', {/ / passing `scopedSlots` / / format in data object: {name: props = > VNode | Array} scopedSlots: {default: function (props) {return createElement ('span', props.text)}})])} V, JSX
If you write a lot of render functions, you may find it painful to write code like this:
CreateElement ('anchored-heading', {props: {level: 1}}, [createElement (' span', 'Hello'),' worldview'])
Especially if the corresponding template is so simple:
Hello world!
This is why there is a Babel plug-in for using JSX syntax in Vue, which brings us back to syntax that is closer to templates.
Import AnchoredHeading from'. / AnchoredHeading.vue'new Vue ({el:'# demo', render: function (h) {return (Hello world!)}})
H as an alias for createElement is a common practice in the Vue ecosystem and is actually required by JSX. Starting with version 3.4.0 of Vue's Babel plug-in, we will automatically inject const h = this.$createElement into any method and getter that contains JSX declared in ES2015 syntax (not in a function or arrow function) so that you can remove the (h) parameter. For earlier versions of plug-ins, if h is not available in the current scope, the application will throw an error.
VI. Functional components
The anchor header component created earlier is relatively simple, without managing any state, listening for any state passed to it, and without lifecycle methods. In fact, it's just a function that accepts some prop. In such a scenario, we can mark the component as functional, which means that it is stateless (no responsive data) and no instance (no this context). A functional component looks like this:
Vue.component ('my-component', {functional: true, / / Props is optional props: {/ /...}, / / to make up for the missing instance / / provide a second parameter as the context render: function (createElement, context) {/ /.})
Note: in versions prior to 2.3.0, the props option was required if a functional component wanted to receive prop. In version 2.3.0 or above, you can omit the props option, and attribute on all components is automatically implicitly parsed to prop.
When using functional components, the reference will be HTMLElement because they are stateless and instantiate.
In version 2.5.0 and above, if you use a single-file component, template-based functional components can be declared as follows:
Everything the component needs is passed through the context parameter, which is an object that includes the following fields:
Props: an object that provides all prop
An array of children:VNode child nodes
Slots: a function that returns an object containing all slots
ScopedSlots: (2.6.0 +) an object that exposes incoming scope slots. Normal slots are also exposed as functions.
Data: the entire data object passed to the component, passed into the component as the second parameter of createElement
Parent: reference to the parent component
Listeners: (2.3.0 +) an object that contains all event listeners registered by the parent component for the current component. This is an alias for data.on.
Injections: (2.3.0 +) if the inject option is used, the object contains the property that should be injected.
After adding functional: true, we need to update the render function of our anchor title component, add the context parameter to it, update this.$slots.default to context.children, and then update this.level to context.props.level.
Because functional components are just functions, the rendering overhead is much lower.
They are also very useful as packaging components. For example, when you need to do this:
Programmatically select one of multiple components to render instead
Manipulate children, props, and data before passing them to child components.
Here is an example of a smart-list component that renders a more specific component based on the value passed in prop:
Var EmptyList = {/ *... * /} var TableList = {/ *... * /} var OrderedList = {/ *... * /} var UnorderedList = {/ *... * /} Vue.component ('smart-list', {functional: true, props: {items: {type: Array, required: true}, isOrdered: Boolean}, render: function (createElement) Context) {function appropriateListComponent () {var items = context.props.items if (items.length = 0) return EmptyList if (typeof items [0] = 'object') return TableList if (context.props.isOrdered) return OrderedList return UnorderedList} return createElement (appropriateListComponent (), context.data, context.children)}) 1, passing attribute and events to child elements or subcomponents
In a normal component, an attribute that is not defined as prop is automatically added to the root element of the component, replacing or intelligently merging an existing attribute with the same name.
However, functional components require you to explicitly define the behavior:
Vue.component ('my-functional-button', {functional: true, render: function (createElement, context) {/ / completely transmits any attribute, event listeners, child nodes, etc. Return createElement ('button', context.data, context.children)}})
By passing context.data to createElement as the second parameter, we pass all the attribute and event listeners on my-functional-button. In fact, this is so transparent that those events do not even require the .native modifier.
If you use template-based functional components, you also need to add attribute and listeners manually. Because we have access to its independent context content, we can pass any HTML attribute using data.attrs or any event listener using listeners (that is, an alias for data.on).
2. Comparison between slots () and children
You may wonder why you need both slots () and children. Isn't slots (). Default similar to children? In some scenarios, this is true-- but what about the following functional components with child nodes?
First
Second
For this component, children gives you two paragraph tags, while slots (). Default passes only the second anonymous paragraph tag, and slots (). Foo passes the first named paragraph tag. It has both children and slots (), so you can choose whether to make the component aware of a slot mechanism or simply pass the children and hand it over to other components to handle.
VII. Template compilation
You may be interested to know that the Vue template is actually compiled into a rendering function. This is an implementation detail and usually does not need to be concerned about. But if you want to see exactly how the functionality of the template is compiled, you may find it very interesting. Here is a simple example of using Vue.compile to compile a template string in real time:
I'm a template! {{message}}
No message.
Render:
Function anonymous () {with (this) {return _ c ('div', [_ m (0), (message)? _ c (' packs, [_ v (_ s (message))]): _ c ('packs, [_ v ("No message.")])}
StaticRenderFns:
_ m (0): function anonymous () {with (this) {return _ c ('header', [_ c (' h _ 2), [_ v ("I'm a template!")])}} so much about how to understand the rendering function and JSX. I hope the above can be helpful and learn more. If you think the article is good, you can share it for more people to see.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.