This article mainly introduces the analysis of the vue data control view source code. It has a certain reference value. Now I share it with you. Friends in need can refer to it.
Analysis of how vue implements data changes and updates view.
Preface
Three months ago I read the vue source code to analyze how to achieve responsive data. The article is called vue source code for responsive data. , and finally analyzed that the update() method of Watcher will be called after the data changes. So let’s continue to see what update() does after three months. (In the past three months, I have used react-native to build a project, but I have no intention of doing so. Summarized, because it seems too simple).
The narrative method of this article is to follow the logic of looking at the source code. The version of vue I checked is 2.5.2. I forked a copy of the source code. Used to record comments.
Purpose
Only by clarifying the direction of investigation can we reach the goal. Let’s talk about the target behavior first: what method is executed to update the view after the data changes. Then prepare to start looking for answers in this direction and start from the entrance of vue source code.
Start from the previous conclusion
Let’s review the previous conclusion first:
When Vue is constructed, an Observer object will be created on the data (and some other fields). The getter and setter are intercepted. The getter triggers dependency collection and the setter triggers notify.
Another The object is Watcher. When registering a watch, the watch object will be called once, which triggers the getter of the watch object and collects the dependencies into the deps of the current Watcher. When any setter of the dep is triggered, the current Watcher will be notified to call the update of the Watcher. () method.
Then here we start by registering the rendering-related Watcher.
The file is found in src/core/instance/lifecycle.js.
new Watcher(vm, updateComponent, noop, null, true /* isRenderWatcher */)
mountComponent
The rendering-related Watcher is called in the mountComponent() method, so let’s search where this method is called. There are only 2 places, respectively. They are src/platforms/web/runtime/index.js and src/platforms/weex/runtime/index.js. Take web as an example:
Vue.prototype.$mount = function ( el?: string | Element, hydrating?: boolean ): Component { el = el && inBrowser ? query(el) : undefined return mountComponent(this, el, hydrating) }
It turns out that it is the $mount() method that calls mountComponent( ), (or specifying the el field during vue construction will automatically call the $mount() method), because the rendering objects of web and weex (what is weex? I have introduced it in other articles before) are different, so when publishing, it should be After introducing different files, different dists cannot be sent (this problem is left to study the entire process of vue later).
The following is the mountComponent method:
export function mountComponent ( vm: Component, el: ?Element, hydrating?: boolean ): Component { vm.$el = el // 放一份el到自己的属性里 if (!vm.$options.render) { // render应该经过处理了, 因为我们经常都是用template或者vue文件 // 判断是否存在render函数, 如果没有就把render函数写成空VNode来避免红错, 并报出黄错 vm.$options.render = createEmptyVNode if (process.env.NODE_ENV !== 'production') { /* istanbul ignore if */ if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') || vm.$options.el || el) { warn( 'You are using the runtime-only build of Vue where the template ' + 'compiler is not available. Either pre-compile the templates into ' + 'render functions, or use the compiler-included build.', vm ) } else { warn( 'Failed to mount component: template or render function not defined.', vm ) } } } callHook(vm, 'beforeMount') let updateComponent /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && config.performance && mark) { // 不看这里的代码了, 直接看else里的, 行为是一样的 updateComponent = () => { const name = vm._name const id = vm._uid const startTag = `vue-perf-start:${id}` const endTag = `vue-perf-end:${id}` mark(startTag) const vnode = vm._render() mark(endTag) measure(`vue ${name} render`, startTag, endTag) mark(startTag) vm._update(vnode, hydrating) mark(endTag) measure(`vue ${name} patch`, startTag, endTag) } } else { updateComponent = () => { vm._update(vm._render(), hydrating) } } // we set this to vm._watcher inside the watcher's constructor // since the watcher's initial patch may call $forceUpdate (e.g. inside child // component's mounted hook), which relies on vm._watcher being already defined // 注册一个Watcher new Watcher(vm, updateComponent, noop, null, true /* isRenderWatcher */) hydrating = false // manually mounted instance, call mounted on self // mounted is called for render-created child components in its inserted hook if (vm.$vnode == null) { vm._isMounted = true callHook(vm, 'mounted') } return vm }
This code actually only does 3 things:
Call the beforeMount hook
Create Watcher
Call the mounted hook
(Hahaha) So actually the core is to create a Watcher.
Look at the parameters of the Watcher: vm is this, updateComponent is a function, noop is empty, null is empty , true means RenderWatcher.
Looked at isRenderWatcher in Watcher:
if (isRenderWatcher) { vm._watcher = this }
Yes, I just made a copy to judge something when the watcher patches for the first time (from the comments I read it in, I still don’t know what it is for).
The only problem that has not been solved is what updateComponent is.
updateComponent
If the function is passed as the second parameter of the Watcher constructor, then this function becomes the getter of the watcher. If you are smart, you should have guessed that all the data in the view must be called in this updateComponent. Getter can establish dependencies in the watcher so that the view can respond to data changes.
updateComponent = () => { vm._update(vm._render(), hydrating) }
Then go to vm._update() and vm._render().
In src/core/ instance/render.js found the ._render() method.
Vue.prototype._render = function (): VNode { const vm: Component = this const { render, _parentVnode } = vm.$options // todo: render和_parentVnode的由来 // reset _rendered flag on slots for duplicate slot check if (process.env.NODE_ENV !== 'production') { for (const key in vm.$slots) { // $flow-disable-line vm.$slots[key]._rendered = false } } if (_parentVnode) { vm.$scopedSlots = _parentVnode.data.scopedSlots || emptyObject } // set parent vnode. this allows render functions to have access // to the data on the placeholder node. vm.$vnode = _parentVnode // render self let vnode try { vnode = render.call(vm._renderProxy, vm.$createElement) } catch (e) { // catch其实不需要看了, 都是做异常处理, _vnode是在vm._update的时候保存的, 也就是上次的状态或是null(init的时候给的) handleError(e, vm, `render`) // return error render result, // or previous vnode to prevent render error causing blank component /* istanbul ignore else */ if (process.env.NODE_ENV !== 'production') { if (vm.$options.renderError) { try { vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e) } catch (e) { handleError(e, vm, `renderError`) vnode = vm._vnode } } else { vnode = vm._vnode } } else { vnode = vm._vnode } } // return empty vnode in case the render function errored out if (!(vnode instanceof VNode)) { if (process.env.NODE_ENV !== 'production' && Array.isArray(vnode)) { warn( 'Multiple root nodes returned from render function. Render function ' + 'should return a single root node.', vm ) } vnode = createEmptyVNode() } // set parent vnode.parent = _parentVnode return vnode } }
This method does:
Generate VNode based on the render method of the current vm. (render method It may be compiled based on the template or vue file, so it is inferred that writing the render method directly is the most efficient)
If there is a problem with the render method, then call the renderError method first, and if it fails, read it. The vnode of this time is either null.
If there is a parent node, put it in its own .parent attribute.
Finally return VNode
So the core is this sentence:
vnode = render.call(vm._renderProxy, vm.$createElement)
I don’t know what render(), vm._renderProxy, vm.$createElement are.
First Look at vm._renderProxy: it is set during initMixin(). It returns vm in the production environment and returns the proxy in the development environment. Then we think it is a vm that can be debugged (that is, vm). We will look at the details later.
## The code of #vm.$createElement is in the vdom folder. After looking at it, it is a method that returns a VNode. render is a bit complicated. Is it possible to study it later? In short, it is to combine the template or vue single file with mount The target parse becomes the render function.Small summary: The return value of vm._render() is VNode, based on the render function of the current vmLet’s look at vm._update()Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) { const vm: Component = this if (vm._isMounted) { callHook(vm, 'beforeUpdate') } // 记录update之前的状态 const prevEl = vm.$el const prevVnode = vm._vnode const prevActiveInstance = activeInstance activeInstance = vm vm._vnode = vnode // Vue.prototype.__patch__ is injected in entry points // based on the rendering backend used. if (!prevVnode) { // 初次加载, 只有_update方法更新vm._vnode, 初始化是null // initial render vm.$el = vm.__patch__( // patch创建新dom vm.$el, vnode, hydrating, false /* removeOnly */, vm.$options._parentElm, vm.$options._refElm ) // no need for the ref nodes after initial patch // this prevents keeping a detached DOM tree in memory (#5851) vm.$options._parentElm = vm.$options._refElm = null } else { // updates vm.$el = vm.__patch__(prevVnode, vnode) // patch更新dom } activeInstance = prevActiveInstance // update __vue__ reference if (prevEl) { prevEl.__vue__ = null } if (vm.$el) { vm.$el.__vue__ = vm } // if parent is an HOC, update its $el as well if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) { vm.$parent.$el = vm.$el } // updated hook is called by the scheduler to ensure that children are // updated in a parent's updated hook. }The part we care about is actually the __patch() part. __patch() operates on the dom. In _update(), it is judged whether it is the first call. If so, create a new dom. If not, pass it in. Compare the old and new nodes before operating.
Conclusion
Vue's view rendering is a special kind of Watcher. The content of the watch is a function. The render function is called during the running process of the function. The render is compiled by the template or el's dom (the template contains some observed objects). data). Therefore, changes in the observed data in the template trigger the Watcher's update() method to re-render the view.
Legacy
Where is the render function compiled?
What is the process of introducing different platforms when vue source code is released and finally typing it into dist
Analysis of __patch__ and VNode
The above is the entire content of this article. I hope it will be useful to you. Everyone’s learning is helpful. For more related content, please pay attention to the PHP Chinese website!
Related recommendations:
About Vue’s ideas for solving cross-domain routing conflicts
About Vue’s dynamic setting of routing parameters Introduction
#About vue virtual dom patch source code analysis
The above is the detailed content of Analysis of the source code of vue data control view. For more information, please follow other related articles on the PHP Chinese website!

The main uses of JavaScript in web development include client interaction, form verification and asynchronous communication. 1) Dynamic content update and user interaction through DOM operations; 2) Client verification is carried out before the user submits data to improve the user experience; 3) Refreshless communication with the server is achieved through AJAX technology.

Understanding how JavaScript engine works internally is important to developers because it helps write more efficient code and understand performance bottlenecks and optimization strategies. 1) The engine's workflow includes three stages: parsing, compiling and execution; 2) During the execution process, the engine will perform dynamic optimization, such as inline cache and hidden classes; 3) Best practices include avoiding global variables, optimizing loops, using const and lets, and avoiding excessive use of closures.

Python is more suitable for beginners, with a smooth learning curve and concise syntax; JavaScript is suitable for front-end development, with a steep learning curve and flexible syntax. 1. Python syntax is intuitive and suitable for data science and back-end development. 2. JavaScript is flexible and widely used in front-end and server-side programming.

Python and JavaScript have their own advantages and disadvantages in terms of community, libraries and resources. 1) The Python community is friendly and suitable for beginners, but the front-end development resources are not as rich as JavaScript. 2) Python is powerful in data science and machine learning libraries, while JavaScript is better in front-end development libraries and frameworks. 3) Both have rich learning resources, but Python is suitable for starting with official documents, while JavaScript is better with MDNWebDocs. The choice should be based on project needs and personal interests.

The shift from C/C to JavaScript requires adapting to dynamic typing, garbage collection and asynchronous programming. 1) C/C is a statically typed language that requires manual memory management, while JavaScript is dynamically typed and garbage collection is automatically processed. 2) C/C needs to be compiled into machine code, while JavaScript is an interpreted language. 3) JavaScript introduces concepts such as closures, prototype chains and Promise, which enhances flexibility and asynchronous programming capabilities.

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.

JavaScript's applications in the real world include server-side programming, mobile application development and Internet of Things control: 1. Server-side programming is realized through Node.js, suitable for high concurrent request processing. 2. Mobile application development is carried out through ReactNative and supports cross-platform deployment. 3. Used for IoT device control through Johnny-Five library, suitable for hardware interaction.

I built a functional multi-tenant SaaS application (an EdTech app) with your everyday tech tool and you can do the same. First, what’s a multi-tenant SaaS application? Multi-tenant SaaS applications let you serve multiple customers from a sing


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

ZendStudio 13.5.1 Mac
Powerful PHP integrated development environment

VSCode Windows 64-bit Download
A free and powerful IDE editor launched by Microsoft

MantisBT
Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

SecLists
SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.