The following code and analysis process need to be viewed in conjunction with vue.js source code, by comparing the break points one by one.

A code.

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
    <div id="app">
        <! --this is comment--> {{ message }}
    </div>
    <div id="app1">
        <div>
            <! --count={{count}}-->
            <! --reversedCount={{reversedCount}}-->
        </div>
    </div>

    <script>
        debugger;
        var app = new Vue({
            el: '#app'.beforeCreate() {},
            created() {},
            beforeMount() {},
            mounted: () = > { // Mount the element to get the DOM node
                setTimeout(() = > {
                    //this.count+=1;
                    //console.log('this.count='+this.count)
                }, 1000)},beforeUpdate() {},
            updated() {},// Mount the element to get the DOM node
            beforeDestroy() {},
            destroyed() {},
            data: function () {
                return {
                    count: 0.message: 'Hello Vue! 1111111 '}}})})</script>

</body>

</html>
Copy the code

2. Procedure

1. InitMixin, initialize vUE, and mount _init method

Execute initMixin(Vue). Vue is a constructor.

Mount a _init method on the Vue prototype. This step only mounts the method and is not performed.

2. StateMixin, data binding, $watch method

2 – (1)stateMixin(Vue)Vue is a constructor.

Mount a _init method on the Vue prototype. This step only mounts the method and is not performed.

Define a data object and a props object, and add the get and set properties to each object.

2-2. Then run the commandObject.definePropertyTo listen for changes in data by setting the set/get method of the object property.

Dependencies are collected through GET, and each set method is an observer that notifies the subscriber to update the view when the data changes.

 Object.defineProperty(Vue.prototype, '$data', dataDef); 
 Object.defineProperty(Vue.prototype, '$props', propsDef);
Copy the code

At this point, vue. prototype only has the newly mounted _init method

The dataDef has only get and set methods

Object.defineproperty (); object.defineProperty (); object.defineProperty (); object.defineProperty ();

2-3 Then run

  Vue.prototype.$set = set;
  Vue.prototype.$delete = del;
Copy the code

We’ll look at the definitions of the set and del methods when we call them later.

2-4 Then mount it$watch

This method will also be examined later. Ok, now let’s see what methods Vue has mounted:

The stateMixin execution is complete

EventsMixin: initializes the event binding method

3-1. Mount them in sequence$on, $once, $off, $emit, method properties

These methods are only mounts, which we will analyze later

Vue now mounts these properties:

4 lifecycleMixin, initialize the update destruction function

4-1. Mount them in sequence_update, $forceUpdate, $$destroy, method properties

These methods are only mounts, which we will analyze later

  • _update in [14. Defining instructions]

Vue now mounts these properties:

RenderMixin: initializes the functions that vue needs to render

5-1. Run installRenderHelpers

Install installRenderHelpers on Vue prototypes (Prototype)Copy the code

The input parameter of the function is the prototype of vue, as shown below:

After the installRenderHelpers function is executed, the Vue prototype has the render tool method property

5-1. Then mount$nextTickand_render

  • NextTick delays the callback
  • _render Render function

6 Declare some variables

  • PatternTypes // Array of types
  • KeepAlive // Defines built-in component properties in component format
  • BuiltInComponents // Built-in component to save state

InitGlobalAPI (Vue), which initializes the global API and exposes static methods

7-1 Mount basic properties

Mount a get property to configDef, a function that returns the previously defined config object. It is mounted, not executed, so there is only one get method.

Then mount a set method that prompts some warning.

Then perform

/** * Here, add a config property to the Vue constructor to listen on via Object.defineProperty, and * associate the set and get methods in configDef to config. * Vue does not want us to directly replace or change the entire config object. * Vue does not want us to directly replace or change the entire config object. */ object.defineProperty (Vue, 'config', configDef);Copy the code
  • Then mount the util, set, delete, nextTick methods on the Vue constructor, and mount an empty options.

  • It then iterates through the instruction collection, mounts the corresponding instruction in vue. options, and sets the _base property value to Vue

Merge KeepAlive components into components

extend(Vue.options.components, builtInComponents)
Copy the code

7-2 initUse

Initialize the vUE installation plug-in function

Mount a use method on Vue.

7-3 initMixin$1

initMixin$1(Vue); // Initialize the vue mixin function

Mount a mixin method on Vue that overwrites the mixin passed in (at execution time) to the options TAB.

Mount a use method on Vue.

7-4 initExtend

InitExtend // Initializes the vue extend function

Mount a extend method on Vue,

7-5 initAssetRegisters

InitAssetRegisters // Add static methods component, directive, filter to vue

At this point, the initGlobalAPI method completes execution.

8. Object.defineproperty Responds to some attributes

// Listen to whether the server environment
    Object.defineProperty(Vue.prototype, '$isServer', {
        get: isServerRendering // Check whether it is node server environment
    });
    / / get $ssrContext
    Object.defineProperty(Vue.prototype, '$ssrContext', {
        get: function get() {
            return this.$vnode && this.$vnode.ssrContext
        }
    });

    // create virtual dom vonde render slots for the SSR runtime helper installation to expose the FunctionalRenderContext
    Object.defineProperty(Vue, 'FunctionalRenderContext', {
        value: FunctionalRenderContext
    });
Copy the code

Prototype:

9. Set the version number

Vue. Version = '2.5.16'; / / version numberCopy the code

10. Define attribute correlation functions

// The makeMap function returns a function to find if val exists in the map, true if val exists, false otherwise
isReservedAttr / / determine 'style, the class'
acceptValue    / / judgment 'input, textarea, option, select and progress'
mustUseProp    // Check whether attributes and tags match
isEnumeratedAttr    // Judge 'contenteditable (edit),draggable (drag),spellcheck '
isBooleanAttr  // Check if it is a Boolean attribute in HTML (attribute values are true and false only)
isXlink        // Check if it is an XMLNS attribute
getXlinkProp   // Get the attributes of the XML link
isFalsyAttrValue   // Check whether val is null or false
var namespaceMap = {
     svg: 'http://www.w3.org/2000/svg'.// The SVG tag names the XMLNS attribute
      math: 'http://www.w3.org/1998/Math/MathML' // The XMLNS attribute in math declares the XHTML file
};
isFalsyAttrValue   // Determine if val is the original tag in HTML
isSVG              // Determine SVG tags and SVG child tags
isPreTag           // Check whether the tag is pre
isReservedTag      // Check whether it is an HTML native tag or an SVG tag
getTagNamespace    // Check whether it is SVG or math tag
unknownElementCache    // Check whether it is SVG or math tag
isTextInputType    / / judge whether text input box to judge attributes: text, number, password, search, email, tel, url
Copy the code

11. NodeOps Freezes a node

The object.freeze () method freezes an Object.

  • A frozen object can no longer be modified.
  • You cannot add new properties to an object if you freeze it
  • An existing attribute cannot be deleted
  • You cannot modify the enumerability, configurability, or writability of existing properties of the object
  • And cannot change the value of an existing attribute.
  • In addition, the stereotype of an object cannot be modified after it is frozen.
  • Freeze () returns the same object as the argument passed in.
Var nodeOps = object. freeze({createElement: createElement$1, // Create a real dom createElementNS: CreateElementNS, // Create a real DOM SVG createTextNode: createTextNode, // Create a text node createComment: CreateComment, // Create a comment node insertBefore: insertBefore, // insert a node in front of XXX DOM removeChild: ParentNode: parentNode, // Get parent child dom nextSibling: SetTextContent: setTextContent, // // Set the dom text setStyleScope: SetStyleScope // set stylesheet scope});Copy the code

The following sections examine each item of the object one by one

11-1 createElement$1

Create a real DOM

function createElement$1(tagName, vnode) {
        // Create a real DOM
        var elm = document.createElement(tagName);
        // If it is not a select tag, return the DOM and exit the function
        if(tagName ! = ='select') { 
            return elm
        }
        // false or null will remove the attribute but undefined will not
        // False or null will delete attributes, but undefined will not
        // Otherwise, if it is the select tag, the multiple attribute is set. Reset if set
        if(vnode.data && vnode.data.attrs && vnode.data.attrs.multiple ! = =undefined) {
            elm.setAttribute('multiple'.'multiple');
        }
        return elm
    }
Copy the code

11-2 createElementNS

To create a real DOM SVG, the document.createElementns method creates element nodes with the specified namespace.

    // Create a real DOM SVG
    function createElementNS(namespace, tagName) {
        / * * namespaceMap, previously defined values for {SVG: 'http://www.w3.org/2000/svg', math: 'http://www.w3.org/1998/Math/MathML'}; For example: the document createElementNS (' http://www.w3.org/2000/svg ', 'SVG); * / 
        return document.createElementNS(namespaceMap[namespace], tagName)
    }
Copy the code

Document. The createElementNS usage:

var c=document.createElementNS('http://www.w3.org/2000/svg'.'svg') // Create an SVG node
document.body.appendChild(c);
Copy the code

You can see that a pair of SVG tags are inserted into the DOM

11-3 createTextNode

Creating a text node

function createTextNode(text) {
   return document.createTextNode(text)
}
Copy the code

11-4 createComment

Creating a comment node

function createTextNode(text) {
   return document.createTextNode(text)
}
Copy the code

Document. The createComment usage:

var c=document.createComment("My personal comments"); // Create a comment
document.body.appendChild(c); // Insert the node
Copy the code

You can see that a comment has been inserted into the DOM

11-5 insertBefore

Inserts a new node before one of the children of the parent node

function insertBefore(parentNode, newNode, referenceNode) {
        parentNode.insertBefore(newNode, referenceNode);
}
Copy the code

InsertBefore usage:

/** node.insertBefore(newNode, existingNode) inserts a new child node before an existing one. Node: the parent node to be inserted. Newnode: must be. The node object existingNode must be inserted. The child node before the new node is added. For example: * /
<ul id="List">
    <li>Shanghai</li>
    <li>shenzhen</li>
</ul>
var newCity = document.createElement("li")  // Create the element
var textnode = document.createTextNode("Beijing") // Create the element
newCity.appendChild(textnode)  // Add text
var list = document.getElementById("List")
// Add a newCity node before the first li node of the parent ul node
list.insertBefore(newCity,list.childNodes[0]); After the command is executed: <ul ID ="List">
    <li>Beijing</li>
    <li>Shanghai</li>
    <li>shenzhen</li>
</ul>
Copy the code

11-6 Perform operations on other nodes

The rest of them are easy, so let’s put them together

Function removeChild(node, child) {node.removechild (child); Function appendChild(node, child) {node.appendChild(child); Dom function parentNode(node) {return node.parentNode} function nextSibling(node) {return Function tagName(node) {return node.tagName} // set dom text function setTextContent(node, text) { node.textContent = text; } function setStyleScope(node, scopeId) {node.setAttribute(scopeId, ''); }Copy the code

At this point, nodeOps freezes the node

12. Define ref to create update and destroy events

var ref = {
        create: function create(_, vnode) {
            // create a registered ref
            registerRef(vnode);
        },
        update: function update(oldVnode, vnode) {
            / / update the ref
            if(oldVnode.data.ref ! == vnode.data.ref) { registerRef(oldVnode,true); / / delete first
                registerRef(vnode);  / / in the add}},destroy: function destroy(vnode) {
            registerRef(vnode, true); // delete destroy ref}}Copy the code

12-1. create

Ref is used to register reference information for an element or child component. The reference information will be registered with the parent component’s $refs object. If used on a normal DOM element, the reference refers to the DOM element. If used on a child component, the reference refers to the component instance.

/** * register ref or delete ref. For example, if ref=' ABC '* is set on the tag, this.$refs. ABC registers ref to store the actual DOM in */
    function registerRef(
        vnode, // Virtual DOM object
        isRemoval // Whether to destroy the ref
    ) {
        debugger
        var key = vnode.data.ref;  // Get the string of vnode ref
        if(! isDef(key)) {// If there is no definition, exit the function
            return
        }
        var vm = vnode.context; / / the context context
        // Get the component instance of vonde first (for the component), or el(for the DOM node corresponding to the Vnode, for the non-component)
        var ref = vnode.componentInstance || vnode.elm; 
        var refs = vm.$refs;
        // If you need to destroy the ref
        if (isRemoval) {
            if (Array.isArray(refs[key])) {
                remove(refs[key], ref); 
            } else if (refs[key] === ref) { 
                refs[key] = undefined; }}else {
            if (vnode.data.refInFor) {  // When inside v-for, it is saved as an array
                if (!Array.isArray(refs[key])) { //refs[key] becomes an array if it is not an array
                    refs[key] = [ref];
                } else if (refs[key].indexOf(ref) < 0) { // add refs if ref does not exist
                    // $flow-disable-linerefs[key].push(ref); }}else {
                refs[key] = ref; // If it is a single direct assignment}}}Copy the code

isDef:

// Determine if the data is defined (note! 0 or false is also defined.)
function isDef(v) {
    returnv ! = =undefined&& v ! = =null
}
Copy the code

12-2. update

update: function update(oldVnode, vnode) {
            // If the old ref does not match the old one, update the ref
            if(oldVnode.data.ref ! == vnode.data.ref) { registerRef(oldVnode,true); / / delete first
                registerRef(vnode);  / / in the add}},Copy the code

12-3. destroy

destroy: function destroy(vnode) {
            // delete destroy ref
            registerRef(vnode, true); 
        }
Copy the code

13. Define empty vNode (emptyNode) and hooks

Let’s look at the attributes of a vNode:

Var hooks = ['create', 'activate', 'update', 'remove', 'destroy'];Copy the code

14. Define instructions

Var cache = {create: updatecache, // create directive update: updatecache, // destroy: Function unbindDirectives(vnode) {// Dispose the directive updateDirectives(vnode, emptyNode); }}Copy the code

These three properties actually use the same function, updateDirectives

Function updateDirectives(oldVnode, //oldVnode old data vnode //vnode new data) {// As long as the old and new directives exist, Just update the if (oldVnode. Data. Directives | | vnode. Data. The directives) {_update (oldVnode vnode); }}Copy the code

Next, the _update function, which is a long one, will be examined in detail

  /** * Update compares oldVnode and VNode, and triggers the hook functions bind, update, INSERTED, INSERT, componentUpdated, unbind hook functions */
    function _update(
        oldVnode, / / oldVnode old data
        vnode     / / vnode new data
    ) {
        // If the old node is empty, the current operation is created, the first time
        var isCreate = oldVnode === emptyNode;
        // If the new node is empty, the current operation is destroy
        var isDestroy = vnode === emptyNode;
        // The normalized instruction becomes the normalized instruction data for the instruction attribute modification. Returns a collection of instruction data
        // For this method, see the following parsing
        var oldDirs = normalizeDirectives$1(
            oldVnode.data.directives, // A collection of vonde directive objects
            oldVnode.context // the vm vNE instantiates the object, or the object instantiated by the component
        );
        // The normalized instruction becomes the normalized instruction data for the instruction attribute modification. Returns a collection of instruction data
        var newDirs = normalizeDirectives$1(
            vnode.data.directives, // A collection of vonde directive objects
            vnode.context // the vm vNE instantiates the object, or the object instantiated by the component
        );

        var dirsWithInsert = []; // List of instructions that trigger the INSERTED instruction hook function.
        var dirsWithPostpatch = []; // Triggers the list of directives for the componentUpdated hook function.

        var key, oldDir, dir;
        for (key in newDirs) {      // Loop through the new instruction set
            oldDir = oldDirs[key];  // Get the old single instruction value
            dir = newDirs[key];     // Get a new single instruction value

            if(! oldDir) {// Add a new instruction to trigger bind
                // new directive, bind
                callHook$1(  // Example: the bind function of the V-focus directive
                    dir, // New instruction value
                    'bind'.// Trigger the bind hook function
                    vnode,/ / new vonde
                    oldVnode / / the old vonde
                );
                if (dir.def && dir.def.inserted) {
                    // If there are insert instructions, add to the listdirsWithInsert.push(dir); }}else {
                // The directive already exists to trigger the update
                // Existing directive, update existing directive, update
                
      
value=123. If you update 123, you're updating it
dir.oldValue = oldDir.value; callHook$1( dir, 'update'.// Triggers the update hook function vnode, oldVnode ); // If there is an update instruction, add to the list if(dir.def && dir.def.componentUpdated) { dirsWithPostpatch.push(dir); }}}// Bind and update hook functions are completed if (dirsWithInsert.length) { // Define a function that executes every function in dirsWithInsert var callInsert = function () { for (var i = 0; i < dirsWithInsert.length; i++) { callHook$1( dirsWithInsert[i], // The new instruction value is the same as the above dir (new single instruction value) 'inserted'.// Triggers the inserted hook function vnode, / / new vonde oldVnode / / the old vonde); }};if (isCreate) { // If it is initialized mergeVNodeHook( vnode, 'insert'.// merge hook functions callInsert ); } else{ callInsert(); }}if (dirsWithPostpatch.length) { mergeVNodeHook(vnode, 'postpatch'.function () { for (var i = 0; i < dirsWithPostpatch.length; i++) { callHook$1( dirsWithPostpatch[i], 'componentUpdated', vnode, oldVnode); }}); }if(! isCreate) {for (key in oldDirs) { if(! newDirs[key]) {// There are no commands in the new vonde // No longer present, unbind callHook$1( oldDirs[key], 'unbind'.// Triggers the unbind hookoldVnode, oldVnode, ); }}}}Copy the code

Then analyze normalizeDirectives$1, which corrects the directive properties to the canonical directive data and returns the directive data set

function normalizeDirectives$1(
        dirs, // Set of vonde directives
        vm // the vm vNE instantiates the object, or the object instantiated by the component
    ) {
        // Create an empty object
        var res = Object.create(null);
        // Return an empty object if the directive name dirs does not exist
        if(! dirs) {// $flow-disable-line
            return res
        }

        var i, dir;
        for (i = 0; i < dirs.length; i++) { // Loop over the instruction set
            dir = dirs[i];
            if(! dir.modifiers) {// Check whether there are modifiers
                // $flow-disable-line
                dir.modifiers = emptyModifiers; / / null objects
            }
            // Return the directive name or attribute name name + modifier
            res[getRawDirName(dir)] = dir;
            /** * Mounts custom directive attributes to the current directive, which are user-defined */ bind, INSERTED, Update, componentUpdated, unbind
            dir.def = resolveAsset(vm.$options, 'directives', dir.name, true);
        }
        // $flow-disable-line
        return res
    }
Copy the code

Then look at the getRawDirName function, which returns either the directive name or the attribute name name + modifier

    function getRawDirName(dir) {
        // Directives in rawName views such as 
      
are v-hello
A directive in the name view such as
is hello
A directive in the name view is hello. Native if it has the modifier
/ / modifiers modifier return dir.rawName || ((dir.name) + "." + (Object.keys(dir.modifiers || {}).join('. ')))}Copy the code

At this point, res[getRawDirName(dir)] = dir already has the command name as an attribute of res and the instruction as an attribute value.

It then checks if the directive is on the component object and returns the registered directive or component object

    function resolveAsset(
        options, // Parameter example: vm.$options
        type, // Type example: 'directives', 'filters', 'components'
        id,   // directive, component key property example: dir.name
        warnMissing // Enable warning information: true
    ) {
        /* Istanbul ignore if id is not a string, exit function */
        // return logic [1]
        if (typeofid ! = ='string') {
            return
        }
        var assets = options[type]; / / example: vm. $options [' components']
        // check local registration variations first
        /** * Check whether the id(component name) is an asset property * if the id is humped, the key is an asset property */
        // Example: Determine whether the V-modal directive is in options['directives']
        // Example: Check whether the my-header component is in options['components']
        /** * So, when we introduce a component in Vue, we can write the component label in template as a hump, or we can capitalize the component, or we can use the component name as the component label, because of this extension */

        // Execute return logic [2]
        if (hasOwn(assets, id)) {
            return assets[id]
        }

        // It is possible to make such a property v-model to vModel to hump
        var camelizedId = camelize(id);
        // Execute return logic [3]
        if (hasOwn(assets, camelizedId)) {
            return assets[camelizedId]
        }

        // Uppercase vModel to vModel
        var PascalCaseId = capitalize(camelizedId);
        // Execute return logic [4]
        if (hasOwn(assets, PascalCaseId)) {
            return assets[PascalCaseId]
        }

        // fallback to prototype chain
        var res = assets[id] || assets[camelizedId] || assets[PascalCaseId];
        // Warning if none of the above is true and it is a development environment
        if ("development"! = ='production'&& warnMissing && ! res) { warn('Failed to resolve ' + type.slice(0, -1) + ':' + id,
                options
            );
        }
        // Return the register instruction or the constructed object (on the prototype)
        return res
    }
Copy the code

Here is the utility function hasOwn:

  /** * Check whether the object has the property. * Checks whether the object property is on itself or on the prototype, returns true */ on itself
    var hasOwnProperty = Object.prototype.hasOwnProperty;

    function hasOwn(obj, key) {
        return hasOwnProperty.call(obj, key)
    }
Copy the code

Then we change our instruction name to a hump,camelize:

/** This re allows properties like v-model to be vModel and names like "xx-xx" to be "xxXx", which receives the current props property value, a string */
    var camelizeRE = /-(\w)/g;
    var camelize = cached(function (str) {
        return str.replace(camelizeRE, function (_, c) {
            /** * var str="Hello World!" str.toUpperCase() //HELLO WORLD! Change lowercase to uppercase */
            return c ? c.toUpperCase() : ' '; })});Copy the code

Now look at the cached function:

// It encapsulates the functions we need to call into an object, which can be fetched when needed
function cached(fn) {
        var cache = Object.create(null); // This creates an empty object with no prototype
        return (function cachedFn(str) {
            var hit = cache[str];
            return hit || (cache[str] = fn(str))
        })
    }
Copy the code

To get a more direct look at the Camelize function, let’s introduce cached. Go back to the camelizeRE function and see if it’s much clearer:

var camelizeRE = /-(\w)/g;
    var camelize = function () {
        var cache = Object.create(null); // This creates an empty object with no prototype
        // This STR is the key of some attributes, such as ID, V-modal
        If there is a function corresponding to the id attribute in the object cache, return it; if there is no function corresponding to the id attribute, set it
        return (function cachedFn(str) {
            var hit = cache[str];
            return hit
            || (cache[str] =  str.replace(camelizeRE, function (_, c) { // This is the cached input parameter fn
                return c ? c.toUpperCase() : ' ';
            })(str))
        })
        
    };
Copy the code

Ok, now that we have parsed the Camelize function, the resolveAsset is now parsed and has the instruction set. NormalizeDirectives $1 are also executed and the directive property is modified to become the standard directive data.

Going back to our _update function, we have both the old and new instruction sets:

At this point, we walk through the old and new instruction set, which involves several tool functions, we analyze in turn

_update->callHook$1

    // Triggers the instruction hook function
    function callHook$1(
        dir,  // New instruction value
        hook, // Example of the hook function: bind
        vnode, / / new vnode
        oldVnode, / / the old vnode
        isDestroy  // Whether to destroy: true
    ) {
        var fn = dir.def && dir.def[hook]; // Get the hook function on the property
        if (fn) {
            try {
                fn(
                    vnode.elm, / / true dom
                    dir, // New instruction value
                    vnode, / / new vond
                    oldVnode, / / the old vonde
                    isDestroy // Whether to destroy the tag
                );
            } catch (e) {
                handleError(e, vnode.context, ("directive " + (dir.name) + "" + hook + " hook")); }}}Copy the code

_update->mergeVNodeHook, merges the vue vnode hook function

 /* * Def [hookKey] = invoker; /* * Def [hookKey] = invoker; // Store the hook function as an object * */

function mergeVNodeHook(
        def,  // vnode
        hookKey,  // function instruction example: 'insert'
        hook // callInsert()
        ) {
        // Reset it to vnode.data.hook if vnode.data.hook does not exist
        // The normal vnode.data. hook does not exist.
        if (def instanceof VNode) {
            def = def.data.hook || (def.data.hook = {});
        }

        var invoker;
        // Get the old oldHook hook
        var oldHook = def[hookKey];

        function wrappedHook() {
            // Execute the hook function
            hook.apply(this.arguments);
            // important: remove merged hook to ensure it's called only once
            // and prevent memory leak
            // Important: Remove merge hook to ensure that it is called only once
            // And prevent memory leaks
            // Delete the wrappedHook item from the invoker. FNS array
            remove(invoker.fns, wrappedHook);
        }

        // If the old hook function is not empty, create a hook function
        if (isUndef(oldHook)) { 
            // no existing hook
            invoker = createFnInvoker([wrappedHook]);
        } else {
            // istanbul ignore if  
            // If there are old hook functions, and FNS hook functions exist and have been merged
            if (isDef(oldHook.fns) && isTrue(oldHook.merged)) {
                // merged invoker already a merged invoker
                invoker = oldHook; // The old hook function overwrites the new hook function
                // Add a function to the FNS of the hook function
                invoker.fns.push(wrappedHook);
            } else {
                // existing plain hook
                invoker = createFnInvoker([oldHook, wrappedHook]);
            }
        }

        invoker.merged = true;
        // Store the hook function as an object
        def[hookKey] = invoker;
    }
Copy the code

_update->mergeVNodeHook->createFnInvoker to create a hook function

    // Add a static class for the event if the event is just a function, invoker. FNS = FNS; Put the real event in FNS.
    // Invoker escapes FNS and then runs FNS
    function createFnInvoker(
        fns Invoker = createFnInvoker([wrappedHook]); invoker = createFnInvoker([wrappedHook]);
        ) {
        // Look at the assignment, then look at the function definition
        function invoker() {
            var arguments$1 = arguments;

            // The function passed in by the static method is assigned to FNS
            var fns = invoker.fns;

            // Check whether FNS is an array
            if (Array.isArray(fns)) {
                // If it is a shallow copy of the array
                var cloned = fns.slice();
                // Execute the functions in the FNS array and pass invoker arguments$1 to the FNS function one by one
                for (var i = 0; i < cloned.length; i++) {

                    cloned[i].apply(null, arguments$1); }}else {
                // return handler return value for single handlers
                // If FNS is just a function, call arguments$1 to the FNS function one by one
                return fns.apply(null.arguments)}}// Mount the array of functions passed in to the invoker FNS property
        invoker.fns = fns;
        return invoker  / / static class
    }
Copy the code

Back to the _update function, which we have already analyzed, it implements the update instruction and the hook function. Go back, and the directives are analyzed, as well as the chapter.

15. Define a global object with some directives and attributes

// Define an empty directive modifier object
var emptyModifiers = Object.create(null);
var baseModules = [
        ref,  // Create, update, destroy functions
        directives // Create, update, and destroy custom instructions
]
// Attribute correlation
var attrs = {
    create: updateAttrs, // Create a property
    update: updateAttrs  // Update attributes
}
/ / class
var klass = {
        create: updateClass,
        update: updateClass
}
Copy the code

15-1: Now run the attrs= updateAttrs command to update the attributes and compare the values of the attributes in the new VNode and the old oldVnode

  • If not, set the property;
  • Delete the new VNode property if it does not exist
    function updateAttrs(oldVnode, vnode) {
        debugger
        var opts = vnode.componentOptions;  // Get component extension parameters
        // Exit the function
        if (isDef(opts) && opts.Ctor.options.inheritAttrs === false) { 
            return
        }
        // Exit the function
        if (isUndef(oldVnode.data.attrs) && isUndef(vnode.data.attrs)) {
            return
        }
        var key, cur, old;
        var elm = vnode.elm;
        var oldAttrs = oldVnode.data.attrs || {};  / / old properties
        var attrs = vnode.data.attrs || {}; / / new properties
        // clone observed objects, as the user probably wants to mutate it
        // Clone the observed object, as the user may wish to mutate it

        if (isDef(attrs.__ob__)) {  // Create a new clone
            attrs = vnode.data.attrs = extend({}, attrs);
        }

        // If not, set the property
        for (key in attrs) { 
            cur = attrs[key];  // New attribute value
            old = oldAttrs[key]; // Old attribute value
            if(old ! == cur) {// Set the propertiessetAttr(elm, key, cur); }}// #4391: in IE9, setting type can reset value for input[type=radio] 
        // #6666: IE/Edge forces progress value down to 1 before setting a max 
        /* istanbul ignore if */
        // In IE9, setting type can reset the input value [type=radio]
        IE/Edge will lower the progress value to 1 before setting the maximum value

        // If it is Internet Explorer or edge, the new value and the old value are not equal
        if((isIE || isEdge) && attrs.value ! == oldAttrs.value) { setAttr(elm,'value', attrs.value); // Set a new value
        }

        // If the old attribute is not in the new attribute, it should be deleted
        for (key in oldAttrs) { 
            if (isUndef(attrs[key])) {
                if (isXlink(key)) { // Check whether it is XML
                    elm.removeAttributeNS(xlinkNS, getXlinkProp(key)); // Set the properties
                }/ / if not 'contenteditable, draggable, spellcheck' properties
                else if(! isEnumeratedAttr(key)) { elm.removeAttribute(key);// Set the properties}}}}Copy the code

Attrs= updateAttrs=>setAttr

Function setAttr(el, // vnode.elm key, // If (el.tagName.indexof ('-') > -1) {// Set attribute baseSetAttr(el, key, value); } // Check whether the HTML Boolean attribute is true or false. Else if (isBooleanAttr(key)) {// set attribute for blank value // e.g. <option disabled>Select  one</option> if (isFalsyAttrValue(value)) { el.removeAttribute(key); } else { // technically allowfullscreen is a boolean attribute for <iframe> // but Flash expects a value of "true" when Allowfullscreen is technically a Boolean attribute, but Flash wants to use it on the <embed> tag. Value = key === 'allowFullScreen' && el.tagName === 'EMBED'? 'true' : key; el.setAttribute(key, value); }} else if (contenteditable, draggable, spellCheck) (10. Define determine attribute correlation function 】 【 isEnumeratedAttr (key)) {el. SetAttribute (key, isFalsyAttrValue (value) | | value = = = 'false'? 'false' : 'true'); } else if // check whether it is XMLNS attribute example: The < bookstore XMLNS: xlink = "http://www.w3.org/1999/xlink" > (isXlink (key)) {if (isFalsyAttrValue (value)) {/ / the value of no value El.removeattributens (xlinkNS, getXlinkProp(key)); } else {// Set the XML attribute el.setattributens (xlinkNS, key, value); }} else {// Set baseSetAttr(el, key, value); }}Copy the code

Attrs= updateAttrs=>setAttr=>baseSetAttr =>setAttr=>baseSetAttr

    function baseSetAttr(
        el,   / / the dom node
        key,  // The key of the property
        value // Attribute value
    ) {
        // Check whether val is null,undefined,false
        if (isFalsyAttrValue(value)) {
            el.removeAttribute(key);  // Remove the attribute from the DOM
        } else {
            // # 798: IE10 & 11 FIRES INPUT event when setting placeholder on IE10 & 11
            // 
            // immediately.
            /* istanbul ignore if */
            if (
                isIE &&  // If it is is! isIE9 &&// If not, IE9 does not support IE9
                el.tagName === 'TEXTAREA' &&  // If the tag is TEXTAREA(TEXTAREA)
                key === 'placeholder' && 
                !el.__ieph
            ) {
                var blocker = function (e) {
                    /** * If there are multiple event listeners of the same type of event bound to the same element, when events of that type are fired, * they are executed in the order they were added. If one monitor function performs the event stopImmediatePropagation () method, * is the rest of the current element to monitor function will not be executed. * /
                    // stopImmediatePropagation prevents events from bubping
                    e.stopImmediatePropagation();
                    // Delete the input event
                    el.removeEventListener('input', blocker);
                };
                // Add a new input event
                el.addEventListener('input', blocker);
                // $flow-disable-line
                // Indicates that input events have been added or updated
                el.__ieph = true;
                /* IE placeholder patched */
            }
            // Set the propertiesel.setAttribute(key, value); }}Copy the code

Set the properties and update updateAttrs.

Klass = “updateClass” to update the calss of the real DOM

    function updateClass(oldVnode, vnode) {
        var el = vnode.elm;  // Get the new DOM node
        var data = vnode.data; // Get the [new] vNode data
        var oldData = oldVnode.data; // Get the old oldVnode data
        // select * from ();
        if (
            isUndef(data.staticClass) && // if no staticClass is defined
            isUndef(data.class) && // Calss is not defined
            (
                isUndef(oldData) ||
                (
                    isUndef(oldData.staticClass) && isUndef(oldData.class)
                )
            )
        ) {
            // Exit the function
            return
        }
        StaticClass and dynamic class in vonde are escaped into the class format required by the real dom. It then returns the class string

        var cls = genClassForVnode(vnode);

        // handle transition classes
        // Process the conversion class
        var transitionClass = el._transitionClasses;
        if (isDef(transitionClass)) {
            cls = concat(cls, stringifyClass(transitionClass));
        }

        // Set the class _prevClass indicates whether the CSS has been updated
        if(cls ! == el._prevClass) { el.setAttribute('class', cls); el._prevClass = cls; }}Copy the code

Klass = “updateClass=” genClassForVnode “; Then return the class string:

    function genClassForVnode(vnode) {
        var data = vnode.data;  // Get vNode. data data label attribute data
        var parentNode = vnode; // Get the parent node
        var childNode = vnode; // Get the child node

        while (isDef(childNode.componentInstance)) { 
            // If you define componentInstance, recursively merge the classes of the subcomponents
            childNode = childNode.componentInstance._vnode; // Last vnode
            if(childNode && childNode.data) { data = mergeClassData(childNode.data, data); }}while (isDef(parentNode = parentNode.parent)) { // parent merges the parent class
            if (parentNode && parentNode.data) {
                // Merge calSS datadata = mergeClassData(data, parentNode.data); }}return renderClass(data.staticClass, data.class) / / render calss
    }
Copy the code

Klass = “updateClass=” genClassForVnode= “mergeClassData” to merge calSS data

    function mergeClassData(child, parent) {
        return {
            staticClass: concat(child.staticClass, parent.staticClass), / / static calss
            class: isDef(child.class)  // Dynamic calss in data
                ? [child.class, parent.class]
                : parent.class
        }
    }
Copy the code

Klass = “updateClass=” genClassForVnode= “renderClass” calss

    function mergeClassData(child, parent) {
        return {
            staticClass: concat(child.staticClass, parent.staticClass), / / static calss
            class: isDef(child.class)  // Dynamic calss in data
                ? [child.class, parent.class]
                : parent.class
        }
    }
Copy the code

Klass = “updateClass=” genClassForVnode= “renderClass=” stringifyClass, transcoding class, converting calSS of array format and object format to string format

    function stringifyClass(value) {
        if (Array.isArray(value)) { // If it is an array
            // The array becomes a string, which is then concatenated with Spaces to make a string
            // The nature of the call is recursive, with each entry of the array calling stringifyClass
            return stringifyArray(value)
        }
        if (isObject(value)) {
            return stringifyObject(value)
        }
        // The recursion does not end until everything is converted to a string
        if (typeof value === 'string') {
            return value
        }
        /* istanbul ignore next */
        return ' '
    }
Copy the code

Klass = “updateClass=” genClassForVnode= “renderClass=” stringifyClass=>stringifyArray, which turns an array into a string and then splices it together with Spaces to make a string

    function stringifyArray(value) {
        var res = ' ';
        var stringified;
        for (var i = 0, l = value.length; i < l; i++) {
            If value[I] is not matched, then stringifyClass returns '', which means that stringifyClass is set to '' and no concatenation is performed
            if(isDef(stringified = stringifyClass(value[i])) && stringified ! = =' ') {
                if (res) {
                    res += ' '; } res += stringified; }}return res
    }
Copy the code

Klass = “updateClass=” genClassForVnode= “renderClass=” stringifyClass=>stringifyObject, where the object string becomes a string and is then concatenated with Spaces to become a string

    function stringifyObject(value) {
        var res = ' ';
        for (var key in value) {
            if (value[key]) {
                if (res) {
                    res += ' '; } res += key; }}return res
    }
Copy the code

StringifyClass parsed, renderClass executed (got the transcoded class), genClassForVnode executed (got the class format needed to escape into the real DOM), UpdateClass (with calSS of the real DOM)

16. Define the dom update event

var events = {
    create: updateDOMListeners,
    update: updateDOMListeners
}
Copy the code

16-1. UpdateDOMListeners updateDOM events

    function updateDOMListeners(oldVnode, vnode) {
        // boundary processing
        if (isUndef(oldVnode.data.on) && isUndef(vnode.data.on)) {
            return
        }
        var on = vnode.data.on || {};
        var oldOn = oldVnode.data.on || {};
        target$1 = vnode.elm; // Real DOM
        normalizeEvents(on);    // Add the change or input event to the event
        // Update the data source and add functions for new values and delete functions for old values
        updateListeners(
            on, // New event object
            oldOn, // The old event object
            add$1.// Add event functions for the real DOM
            remove$2.// Remove the actual DOM event function
            vnode.context Object instantiated by a new vUE or component constructor
        );
        target$1 = undefined;
    }

Copy the code

Notice 16-1. UpdateDOMListeners =>normalizeEvents

    function normalizeEvents(on) {
        /* istanbul ignore if */
        if (isDef(on[RANGE_TOKEN])) {
            // IE input[type=range] only supports `change` event
            // Check whether it is Internet Explorer, if yes, select the change event, if not, select the input event
            var event = isIE ? 'change' : 'input';  
            // Add the change or input event to it
            on[event] = [].concat(on[RANGE_TOKEN], on[event] || []); 
            delete on[RANGE_TOKEN]; // Delete old events
        }
        // This was originally intended to fix #4521 but no longer necessary
        // after 2.5. Keeping it for backwards compat with generated code from < 2.4
        /* istanbul ignore if */
        // The original purpose was to fix #4521, but that is no longer necessary
        // After 2.5. Reserve it for reverse comparison with the code generated with < 2.4
        // Add the change event
        if (isDef(on[CHECKBOX_RADIO_TOKEN])) {

            on.change = [].concat(on[CHECKBOX_RADIO_TOKEN], on.change || []);
            deleteon[CHECKBOX_RADIO_TOKEN]; }}Copy the code

Update data sources and add functions for new values and old value deletion functions etc

    function updateListeners(
        on,  // New event
        oldOn, // Old events
        add,  // Add an event function
        remove$$1.// Delete the event function
        vm//vue instantiates objects
    ) {
        var name, def, cur, old, event;

        for (name in on) {
            def = cur = on[name];  //on New event value
            old = oldOn[name];  / / the old value
            event = normalizeEvent(name);   //normalizeEvent Filters event modifiers if they are events

            /* istanbul ignore if */
            / / isUndef value is empty undefined | | null
            if (isUndef(cur)) {
                // If not production environment
                "development"! = ='production' && warn(
                    "Invalid handler for event \"" + (event.name) + "\": got " + String(cur),
                    vm
                );
            } else if (isUndef(old)) {

                if (isUndef(cur.fns)) { // Bind the function if it does not exist
                    // The function gets the hook function
                    // Create the function caller and copy it back to cur and on[name]
                    cur = on[name] = createFnInvoker(cur); // Cur.fns exists
                }



                name = '&' + name; // Mark the event as passive
                // Add events
                add(
                    event.name, // Event name
                    cur, // Escaped events execute static classes
                    event.once, // Whether to trigger only once
                    event.capture, // Event capture or bubbling behavior
                    event.passive, // Check whether the event modifier is '&'
                    event.params // Event parameters
                );

            } else if(cur ! == old) {// If the new value is not equal to the old value
                // Update the old and new valuesold.fns = cur; on[name] = old; }}for (name in oldOn) {
            // Loop through the old value when it is empty
            if (isUndef(on[name])) {
                // Get the event
                event = normalizeEvent(name);
                // Delete the old value eventremove$$1(event.name, oldOn[name], event.capture); }}}Copy the code

UpdateDOMListeners analysis is complete.

UpdateDOMProps Updates the props property of the real DOM

Var domProps = {create: updateDOMProps, // Update the props property of the real DOMCopy the code

17-1. UpdateDOMProps: Updates the props properties of the real DOM

function updateDOMProps(oldVnode, vnode) {

        if (isUndef(oldVnode.data.domProps) && isUndef(vnode.data.domProps)) {
            return
        }
        var key, cur;
        var elm = vnode.elm;
        var oldProps = oldVnode.data.domProps || {}; // Get the old props property
        var props = vnode.data.domProps || {}; // Get new props
        // clone observed objects, as the user probably wants to mutate it
        // Clone the observed object because the user may want to modify it
        // If props added the observer, clone it again so it can be modified
        if (isDef(props.__ob__)) { 
            props = vnode.data.domProps = extend({}, props);
        }

        for (key in oldProps) {
            if (isUndef(props[key])) {
                elm[key] = ' '; }}for (key in props) {
            cur = props[key]; 
            // ignore children if the node has textContent or innerHTML,
            // as these will throw away existing DOM nodes and cause removal errors
            // on subsequent patches (#3360)
            // Ignore the child node. If the node has textContent or innerHTML,
            // Because this will discard the existing DOM node and cause a deletion error
            // Subsequent patch (#3360)
            if (
                key === 'textContent' ||
                key === 'innerHTML'
            ) {
                if (vnode.children) {
                    vnode.children.length = 0;
                }
                if (cur === oldProps[key]) {
                    continue
                }
                // #6601 work around Chrome version <= 55 bug where single textNode
                // replaced by innerHTML/textContent retains its parentNode property
                #6601 Fixes Chrome version <= 55 bug where there is only one textNode
                // Replaced with innerHTML/textContent, it retains its parentNode property
                if (elm.childNodes.length === 1) { // Text node
                    elm.removeChild(elm.childNodes[0]); }}if (key === 'value') {
                // store value as _value as well since
                // non-string values will be stringified
                // Store value as _value and since
                // Non-string values will be stringed
                elm._value = cur;
                // avoid resetting cursor position when value is the same
                // Avoid resetting the cursor position when the value is the same
                var strCur = isUndef(cur) ? ' ' : String(cur); // Escape to a string
                if (shouldUpdateValue(
                    elm,   // Real DOM
                    strCur //value
                )) {
                    elm.value = strCur; / / assignment}}else {
                elm[key] = cur; // Assign directly}}}Copy the code

18. Format the style string as an object

Convert the style string to an object such as ‘width:100px; height:200px; ‘convert to {width:100px,height:200px}

var parseStyleText = cached(function (cssText) { var res = {}; // Matches the string; Symbols. But does not belong to (;). If the symbol is in parentheses; Var listDelimiter = /; (? ! [^(]*\))/g; var propertyDelimiter = /:(.+)/; //:+ any string csstext.split (listDelimiter). ForEach (function (item) {if (item) {var TMP = item.split(propertyDelimiter); //:+ any string csstext.split (listDelimiter). tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim()); }}); return res });Copy the code

19. Set properties and styles

    var cssVarRE = / ^ - /; // Start with --
    var importantRE = /\s*! important$/; / / to! Important to end

    var setProp = function (el, name, val) {
        //object.setProperty(propertyname, value, priority)
        // propertyName required. A string representing a property created or modified.
        // value Indicates the new attribute value.
        // priority Optional. String that specifies whether the attribute's priority important needs to be set.
        // Can be :"important", undefined, ""
        /* istanbul ignore if */
        if (cssVarRE.test(name)) { // Start with --
            el.style.setProperty(name, val); // Set the real DOM style
        } else if (importantRE.test(val)) { / / to! Important to end
            el.style.setProperty(
                name,
                val.replace(importantRE, ' '),
                'important'
            );
        } else {
            // Prefixes the CSS
            var normalizedName = normalize(name);
            if (Array.isArray(val)) {
                // Support values array created by autoprefixer, e.g.
                // {display: ["-webkit-box", "-ms-flexbox", "flex"]}
                // Set them one by one, and the browser will only set those it can recognize
                // Support automatic repair of the value array created.
                //{display :[" -webkit-box ", "-ms-flexbox", "flex")}
                // One by one, the browser will only set what it recognizes
                for (var i = 0, len = val.length; i < len; i++) {
                    el.style[normalizedName] = val[i]; // Set the styles one by one}}else{ el.style[normalizedName] = val; }}};var vendorNames = ['Webkit'.'Moz'.'ms'];
    var emptyStyle;
    // Prefixes the CSS. Solve the browser compatibility problem, add prefix
    var normalize = cached(function (prop) {
        emptyStyle = emptyStyle || document.createElement('div').style; // Get the style in the browser
        prop = camelize(prop);
        if(prop ! = ='filter' && (prop in emptyStyle)) { // If the attribute is already in the style
            return prop
        }
        var capName = prop.charAt(0).toUpperCase() + prop.slice(1); // Change the first letter to uppercase
        for (var i = 0; i < vendorNames.length; i++) {
            var name = vendorNames[i] + capName; / / add prefix
            if (name in emptyStyle) {
                return name
            }
        }
    });
Copy the code

19. Update styles

    var style = {
        create: updateStyle,
        update: updateStyle
    }
Copy the code

19-1. UpdateStyle, the CSS of the Vonde virtual DOM is escaped and rendered to the CSS of the real DOM

    function updateStyle(oldVnode, vnode) {
        var data = vnode.data; // Get the label properties of the new virtual DOM
        var oldData = oldVnode.data; // Get the label properties of the old virtual DOM

        if (isUndef(data.staticStyle) && isUndef(data.style) &&
            isUndef(oldData.staticStyle) && isUndef(oldData.style)
        ) {
            return
        }

        var cur, name;
        var el = vnode.elm; // Get the real DOM
        var oldStaticStyle = oldData.staticStyle; // get the old staticStyle
        var oldStyleBinding = oldData.normalizedStyle || oldData.style || {}; // Get the old dynamic style

        // if static style exists, stylebinding already merged into it when doing normalizeStyleData
        // If a static style exists, a styleBinding will already be incorporated into it when normalizeStyleData is executed
        var oldStyle = oldStaticStyle || oldStyleBinding; // Old style


        // Normalize possible array/string values to objects // Convert style strings to objects such as 'width:100px; height:200px; 'convert to {width:100px,height:200px}
        var style = normalizeStyleBinding(vnode.data.style) || {};

        // store normalized style under a different key for next diff
        // make sure to clone it if it's reactive, since the user likely wants
        // to mutate it.
        // Store normalized styles under different keys for the next diff
        // If it is reactive, be sure to clone it, as the user may want to
        // make it mutate
        vnode.data.normalizedStyle = isDef(style.__ob__) ? // If style is added after observer
            extend({}, style) :  // Clone again, can be modified
            style; // Assign directly
        //getStyle loops through the child component and the component's style and merges it all into a style object. Return style object {width:100px,height:200px} returns the string.
        var newStyle = getStyle(
            vnode,
            true
        );

        for (name in oldStyle) { // Get the style of the old virtual DOM
            if (isUndef(newStyle[name])) { // If the new virtual DOM vonde does not exist
                setProp(el, name, ' '); // Set the style to null}}for (name in newStyle) { // Loop the new virtual DOM vonde style
            cur = newStyle[name];
            if(cur ! == oldStyle[name]) {// Set a new style if the old one is different from the new one
                // ie9 setting to null has no effect, must use empty string
                setProp(el, name, cur == null ? ' ': cur); }}}Copy the code

UpdateStyle = normalizeStyleBinding normalizes possible array/string values into objects

function normalizeStyleBinding(bindingStyle) { if (Array.isArray(bindingStyle)) { return toObject(bindingStyle) } if (typeof bindingStyle === 'string') {// Convert the style string to an object such as 'width:100px; height:200px; '// convert to {width:100px,height:200px} Return parseStyleText(bindingStyle)} return bindingStyle}Copy the code

UpdateStyle = “getStyle”, the parent component style should come after the child component style, so that the parent component style can override it, loop through the child component and the component style, merge it all into one style object, Return a style object like {width:100px,height:200px} returns the string.

    function getStyle(
        vnode, / / virtual dom
        checkChild // Boolean value of the marking point
    ) {
        var res = {};
        var styleData; //style data
        if (checkChild) { // Boolean value of the marking point
            var childNode = vnode; // Get the child node
            while (childNode.componentInstance) { // The instantiated child node has vonde
                childNode = childNode.componentInstance._vnode;
                if( childNode && childNode.data && (styleData = normalizeStyleData(childNode.data)) ) { extend(res, styleData); }}}if ((styleData = normalizeStyleData(vnode.data))) {
            extend(res, styleData);
        }

        var parentNode = vnode;
        while ((parentNode = parentNode.parent)) {
            if(parentNode.data && (styleData = normalizeStyleData(parentNode.data))) { extend(res, styleData); }}return res
    }
Copy the code

UpdateStyle = “getStyle=> normalizeStyleData, merge static and dynamic style data on the same VNode

Function normalizeStyleData(data) {// // normalizes possible array/string values into objects; height:200px; 'converts to {width:100px,height:200px} to return the string. var style = normalizeStyleBinding(data.style); // Static style is pre-processed into an object during compilation // and is always a fresh object, So it's safe to merge into it // a staticStyle is preprocessed into an object at compile time // is always a fresh object, so it's safe to merge into it. Return data.staticStyle? Extend (data.staticStyle, style) : // merge staticStyle}Copy the code

UpdateStyle analysis is complete.

20. Encapsulate the tool template

    var platformModules = [
        Attrs contains two methods, create and update, which set the real DOM attribute values
        // {create: updateAttrs, /* Create attributes */ update: updateAttrs /* update attributes */}
        attrs,  
        The klass include class contains two methods, create and update, which update calss.
        // This is the updateClass method. Set the class of the real DOM
        klass, 
        events, // Update the actual DOM event
        domProps, // Update the props property of the real DOM
        // Update the style property of the real DOM. There are two methods create and update, but both updateStyle updates the style property value of the real DOM.
        // The CSS of the vonde virtual DOM is escaped and rendered into the CSS of the real DOM
        style, 
        transition // Overanimate
    ]
    var modules = platformModules.concat(baseModules);
    // Path renders vonde as a real DOM
    var patch = createPatchFunction(
        {
            nodeOps: nodeOps,
            modules: modules
        }
    );
Copy the code

Define the insert update instruction function

    var directive = {
        inserted: function inserted(el, binding, vnode, oldVnode) {

            if (vnode.tag === 'select') {
                / / # 6903
                if(oldVnode.elm && ! oldVnode.elm._vOptions) { mergeVNodeHook(vnode,'postpatch'.function () {
                        directive.componentUpdated(el, binding, vnode);
                    });
                } else {
                    setSelected(el, binding, vnode.context);
                }
                el._vOptions = [].map.call(el.options, getValue);
            } else if (vnode.tag === 'textarea' || isTextInputType(el.type)) {
                el._vModifiers = binding.modifiers;
                if(! binding.modifiers.lazy) { el.addEventListener('compositionstart', onCompositionStart);
                    el.addEventListener('compositionend', onCompositionEnd);
                    // Safari < 10.2&uiWebView doesn't fire compositionEnd When
                    // switching focus before confirming composition choice
                    // this also fixes the issue where some browsers e.g. iOS Chrome
                    // fires "change" instead of "input" on autocomplete.
                    el.addEventListener('change', onCompositionEnd);
                    /* istanbul ignore if */
                    if (isIE9) {
                        el.vmodel = true; }}}},componentUpdated: function componentUpdated(el, binding, vnode) {
            if (vnode.tag === 'select') {
                setSelected(el, binding, vnode.context);
                // in case the options rendered by v-for have changed,
                // it's possible that the value is out-of-sync with the rendered options.
                // detect such cases and filter out values that no longer has a matching
                // option in the DOM.
                var prevOptions = el._vOptions;
                var curOptions = el._vOptions = [].map.call(el.options, getValue);
                if (curOptions.some(function (o, i) {
                    return! looseEqual(o, prevOptions[i]); {}))// trigger change event if
                    // no matching option found for at least one value
                    var needReset = el.multiple
                        ? binding.value.some(function (v) {
                            returnhasNoMatchingOption(v, curOptions); }) : binding.value ! == binding.oldValue && hasNoMatchingOption(binding.value, curOptions);if (needReset) {
                        trigger(el, 'change'); }}}}};Copy the code

22. Define update binding instruction functions

   var show = {
        bind: function bind(el, ref, vnode) {
            var value = ref.value;

            vnode = locateNode(vnode);
            var transition$$1 = vnode.data && vnode.data.transition;
            var originalDisplay = el.__vOriginalDisplay =
                el.style.display === 'none' ? ' ' : el.style.display;
            if (value && transition$$1) {
                vnode.data.show = true;
                enter(vnode, function () {
                    el.style.display = originalDisplay;
                });
            } else {
                el.style.display = value ? originalDisplay : 'none'; }},update: function update(el, ref, vnode) {
            var value = ref.value;
            var oldValue = ref.oldValue;

            /* istanbul ignore if */
            if(! value === ! oldValue) {return
            }
            vnode = locateNode(vnode);
            var transition$$1 = vnode.data && vnode.data.transition;
            if (transition$$1) {
                vnode.data.show = true;
                if (value) {
                    enter(vnode, function () {
                        el.style.display = el.__vOriginalDisplay;
                    });
                } else {
                    leave(vnode, function () {
                        el.style.display = 'none'; }); }}else {
                el.style.display = value ? el.__vOriginalDisplay : 'none'; }},unbind: function unbind(el, binding, vnode, oldVnode, isDestroy) {
            if(! isDestroy) { el.style.display = el.__vOriginalDisplay; }}}Copy the code

23. Encapsulate instructions

    var platformDirectives = {
        model: directive,
        show: show
    }
Copy the code

24. Verify attributes

Vue.config.mustUseProp = mustUseProp; Vue. Config. IsReservedTag = isReservedTag; Vue.config.isReservedAttr = isReservedAttr; Vue.config.getTagNamespace = getTagNamespace; Vue.config.isUnknownElement = isUnknownElement; // install platform runtime directives & components extend(Vue.options.directives, platformDirectives); extend(Vue.options.components, platformComponents); Vue. Prototype.__patch__ = inBrowser? patch : noop;Copy the code

25. Mount $mount

Prototype.$float = function (el, hydrating) {float (el, hydrating) {float (el, hydrating) {float (el, hydrating); float (el, hydrating) {float (el, hydrating); float (el, hydrating); float (el, hydrating); float (el, hydrating); float (el, hydrating); float (el, hydrating) Create a new dev el = el && inBrowser? query(el) : undefined; Return mountComponent(this, // Vue instance el, // real DOM hydrating)};Copy the code

26. Vue development tool configuration

    if (inBrowser) {
        setTimeout(function () {
            if (config.devtools) {
                if (devtools) {
                    devtools.emit('init', Vue);
                } else if (
                    "development"! = ='production' &&
                    "development"! = ='test' &&
                    isChrome
                ) {
                    console[console.info ? 'info' : 'log'] ('Download the Vue Devtools extension for a better development experience:\n' +
                        'https://github.com/vuejs/vue-devtools'); }}// If not production environment
            if ("development"! = ='production' &&
                "development"! = ='test'&& config.productionTip ! = =false &&
                typeof console! = ='undefined'
            ) {
                console[console.info ? 'info' : 'log'] ("You are running Vue in development mode.\n" +
                    "Make sure to turn on production mode when deploying for production.\n" +
                    "See more tips at https://vuejs.org/guide/deployment.html"); }},0);
    }
Copy the code