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.defineProperty
To 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$nextTick
and_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