VUE data control view source code resolution

Analysis VUE How to achieve data change update view.


Seeing the VUE source code three months to analyze how to do Responsive data, the article name is the response data of the VUE source, and finally analyzed, the Watcher’s update () method will be called after the data changes. So, I will continue to see what Update () did. (This Three months have made a project with React-Native, because it seems to be too simple).

This article is the narrative of tree vine, walking through the logic of the source code, viewed Vue version is 2.5.2. My Fork has been used to record comments.


clear investigation direction can only go to the target, first Target Behavior: What method has been executed after data changes to update the view. So ready to start looking for answers from the entrance to the VUE source in this direction.

From previous conclusions


First review the previous conclusion:

When the VUE is constructed, the OBServer object is created on the DATA (and some other fields), Getter and Setter have been intercepted, Getter triggers the collection, setter Trigger notify.

Another object is Watcher, when the logch will call a Watch object, which triggered the Getter of the Watch object, and collected dependencies to the current Watcher’s DEPS, when any DEP Setter is triggered, will call Watcher’s update () method.

Then start from the registered rendering related Watcher.

Find files in SRC / Core / Instance / Lifecycle.js.

New Watcher (VM, UpdateComponent, NOOP, NULL, TRUE / * ISRENDERWATCHER * /)
   
MountComponent

Rendered Watcher is called in the MountComponent () method, then we have called where this method is called. Only 2, respectively, SRC / Platforms / Web / Runtime / INDEX.JS and SRC / Platforms / WeEx / Runtime / INDEX.JS, with 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 turned out that The $ mount () method calls MountComponent (), (or specifying the EL field when the VUE constructor will also call the $ mount () method), because Web and WeEx (What is WEEX? More than other articles introduced by other articles) Rendered The subject matter is different, so the different files should be introduced when publishing DIST (after this problem is left behind).  
The following is the MountComponent method:

Export Function MountCompoNENT (VM: Component, El:? Element, hydrating ?: Boolean: Component {VM. $ EL = EL // Put a version of EL to your own properties IF (! VM. $ Options.Render) {// Render It should be handled, because we often use the template or Vue file // to determine if there is a render function, if you don’t write the render function to avoid red and wrong, and report a yellow-based 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 FUENCTIONS, OR Use the compiler-include build. ‘, vm)} else {warn (‘ Failed to Mount Component: Template Or Render Function Not De defined. ‘, VM)}}} Callhook (VM,’ BeforemouNT ‘) let updateComponent / * iStanbul ignore if * / if (process.env.node_env! ==’ production ‘&& config.performance && mark) {// Do not look at the code here, directly see Else, behavior is The same 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}) Mark (StartTag) VM._UPDATE (VNODE, HYDRANG) 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 (Eg Inside Child // Component’s Mounted Hook, WHIch relies on vm._watcher being already defined // register a 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 component in its inserted hook if (vm. $ vnode == null) {vm._ismounted = true callhook (vm, ‘mounted’)} returnv}

 This code actually only made 3 things:   Call the beforemount hook 
Create Watcher

call mounted hook

  • (Hahaha) So, the core is to build Watcher.
  • Look at Watcher’s parameters: vm is this, UpdateComponent is a function, NOOP is empty, NULL is empty, the True representative is renderwatcher.
  • Looked ISRENDERWATCHER:
{vm._watcher = this}

Yes, just copy a copy of Watcher first PATWhen CH, I judge something (see it from the comment, I don’t know what it is now).

So only one problem is not solved is UpdateComponent is something.
  UpdateComponent  
The second parameter of Watcher’s constructor passed Function, then this function became a Watcher’s getter. Smart, you should already guess, in this UpdateComponent Be sure to call all the data in the view to establish dependencies in Watcher to make the view response data change.

UpdateComponent = () => {vm._update (vm._render ()}

So to find VM._UPDATE () and VM._RENDER ().

In SRC / Core / Instance / Render.js found ._render () method.
   
Vue.Prototype._render = function (): vNode {const vm: Component = this const { RENDER, _PARENTVNODE} = VM. $ Options // Todo: Render and _ParentVNode’s origin // 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 In fact, it is not necessary to see, it is doing an abnormality, _vnode is saved when VM._UPDATE, which is the last state or 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.Renderrror.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 is made:

Generates vnode based on the current VM’s render method. (Render method may be compiled according to the template or Vue file, so inference Direct write render method is the highest)
  If the render method has a problem, then the rendererror method is first called, and if you don't read the last VNODE or NULL.  
If you have a parent node, put it in your .parent property.
Last return to VNODE

So the core is this sentence:
  • vnode = render.call (VM._RenderProxy, VM. $ CreateElement)
  • Where RENDER (), VM._RENDERPROXY, VM. $ CreateElement doesn’t know what.
  • See VM._RenderProxy first: It is setting in initmixin (), returning VM in the production environment, the development environment returns a proxy, then we think he is a debug’s VM (already VM), and then see again.

VM. $ CREATEEEMENT The code under the VDOM folder, looks a way, return value a vNode.

Render is a bit complicated, can you learn later, in short, it is a render function to the Template or Vue single file and mount target PARSE
 Summary: The return value of VM._Render () is vNode, according to the current VM's render function   Next, VM._UPDATE () 

vue.prototype._update = function (vnode: vNode, hydrating ?: boolean) {const vm: Component = this if (vm._ismounted) {callhook (vm, ‘beforeupdate’)} // Record Update Previous state const prevel = vm. $ El const prevvnode = VM._VNode ConstprevActiveInstance = activeInstance activeInstance = vm vm._vnode = vnode // Vue.prototype .__ patch__ is injected in entry points // based on the rendering backend used. if (! prevVnode) {// initial load, only _update method update vm. _vnode, initialization is Null // Initial Render VM. $ EL = VM .__ Patch __ (// Patch Create a new DOM VM. $ EL, HYDRANG, 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 update 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 is updated hook.}

We care about the part of __patch () Part, __patch () made actions to the DOM, judge whether it is initially called in _Update (), if it is, create a new DOM, not, incoming new Node to compare again.

Vue view rendering is a special Watcher, the content of Watch is a function, the process runs the render function, and Render is called by Template. Or the DOM compiled by EL (Template contains data of Observe). So Template is changed to trigger the Watcher’s Update () method to re-rendering the view.

  The render function is the process of introducing different platforms when the DIST is introduced when it is compiled  VUE source code 
__ patch__ and vNode analysis
© Copyright Notice
THE END
Just support it if you like
like0
share
comment Grab the couch

Please log in to comment