MVVM - Introduction and Demo
What is MVVM implemented in Vue?
-
First, the first M refers to the Model, which is also the ** data model. In fact, it refers to the data, which is changed into the Vue. In fact, it refers to the data ** in the Vue component instance. But this data has been defined from the very beginning as responsive data.
-
The second V refers to the View, which is also the ** Page View, in Vue is the DOM object that our template converts to**
-
The third VM refers to the **ViewModel, the manager of views and data, which manages our data-to-view changes. In Vue, it refers to our current Vue instance, a bridge between Model data and View view communication**
- In a nutshell: Data Driven View, Data Change=>View Update
<!-- view --> <template> <div>{{ message }}</div> </template> <script> // Model Common Data Object export default { data () { return { message: 'Hello World' } } } </script> <style> </style>
MVVM-Responsive Principle-Object.defineProperty()-Basic Use
Next, we will focus on the principle and implementation of MVVM. The Vuejs website gives the principle of MVVM.
From the above documents, we can see that Vue's Response Principle (MVVM) is actually the following:
When you pass a normal JavaScript object into a Vue instance as the data option, Vue will iterate through all the properties of the object and use Object.defineProperty Convert all these attributes to getter/setter .Object.defineProperty is a feature of ES5 that does not shim, which is why Vue does not support IE8 and lower browsers.
From the above statement, we find several keywords, Object.defineProperty getter/setter
What is Object.defineProperty?
Definition: The Object.defineProperty() method defines a new property directly on an object, or modifies an existing property of an object and returns the object.
Syntax: Object.defineProperty(obj, prop, descriptor)
Parameter: obj =>Object on which to define properties.
Prop =>Property name to add or modify
Descriptor =>Attribute descriptor to be defined or modified.
Return value: The object passed to the function.That is, the obj object passed in
From the notes above, let's see what parameters we need to learn
obj is an object that can either be a new Object() or {}
prop is the property name, which is also a string
What is a descriptor and what are its properties
There are two main forms of attribute descriptors currently present in objects: data descriptors and access descriptors.A data descriptor is an attribute with a value that may or may not be writable.Access descriptors are properties described by getter-setter functions.Descriptors must be one of these two forms; they cannot be both.
The official description above tells us that there are ** two modes in the defineProterty design, one for data and one for access**
The descriptor must be one of the two, not both, that is, neither a mountain nor a tiger
Let's write an example of the simplest **data descriptor**
var obj = { name: 'Xiao Ming' } var o = Object.defineProperty(obj, 'weight', { value: '280kg' }) console.log(o)
Next, do a detailed analysis
Object.defineProperty() - Data Descriptor Mode
What are the properties of a data descriptor?
- Value =>The value corresponding to this property.It can be any valid JavaScript value (number, object, function, etc.).Default to unfined
- Writable =>value can only be changed by the assignment operator if and only if the property's writable is true.Default to false.
Just these two? Anything else?
- Configurable =>The property descriptor can only be changed if and only if the property's configurable is true, and the property can also be deleted from the corresponding object.Default to false.
- Enumerable =>This property can only appear in the enumeration property of an object if and only if the enumerable of the property is true.Default to false.
Why do configurable and enumerable not write with value and writable at the same time?
Because these two attributes can appear not only in the data descriptor but also in the access descriptor
We write a writeable property and an unwritable property by using the writeable and value properties
var obj = { name: 'Xiao Ming' } Object.defineProperty(obj, 'money', { value: "10k" // Salary is not changeable at this time }) Object.defineProperty(obj, 'Xiao Ming', { value: '150 Jin', // Give 10,000 hairs writable: true }) obj.money = '20k' obj.weight = '200 Jin' console.log(obj)
Next, we want to make an immutable property mutable
var obj = { name: 'Xiao Ming' } Object.defineProperty(obj, 'money', { value: '10k', // Salary is not changeable at this time configurable: true // The writeable property can only be changed if this is true }) Object.defineProperty(obj, 'weight', { value: '150 Jin', // Give 10,000 hairs writable: true }) obj.money = "20k" obj.weight = '200 Jin' console.log(obj) Object.defineProperty(obj, 'money', { writable: true }) obj.money = '20k' console.log(obj)
Next, we want to be able to iterate through the two newly added attributes while traversing
var obj = { name: 'Xiao Ming' } Object.defineProperty(obj, 'money', { value: '10k', // Salary is not changeable at this time configurable: true, enumerable: true }) Object.defineProperty(obj, 'weight', { value: '150 Jin', // Give 10,000 hairs writable: true, enumerable: true }) obj.money = "20k" obj.weight = '200 Jin' console.log(obj) Object.defineProperty(obj, 'money', { writable: true }) obj.money = '20k' console.log(obj) for(var item in obj) { console.log(item) }
Object.defineProperty() - Access Descriptor Mode
In the previous section, the unique attributes of data descriptors are value and writable, which also means that in access description mode
value and writable attributes cannot appear
So what are the properties of the storage descriptor?
- Gett is a method that provides getters to properties, or undefined if there are no getters.When the property is accessed, the method is executed, and no parameters are passed in when the method is executed, but a this object is passed in (where this is not necessarily the object defining the property due to inheritance).
- set is a method that provides a setter to an attribute, or undefined if no setter exists.This method is triggered when the attribute value is modified.The method will accept the unique parameter, which is the new parameter value for the attribute.
get/set is actually our most common read value and set value method This.name read value this.name ='Zhang San'
Call get method when reading value
Call set method when setting value
We do a way to read settings through get and set
var obj = { name: 'Xiao Ming' } var wife = 'Little Joe' Object.defineProperty(obj, 'wife',{ get () { return wife }, set (value) { wife = value } }) console.log(obj.wife) obj.wife= 'Jo' console.log(obj.wife)
But what do we want to do with traversal? Note that, when you store descriptors, you still have configurable and enumerable properties.
Still configurable
// Define an object var person = { name: 'Cao Yang' } var name = 'Little Joe' Object.defineProperty(person, 'wife', { enumerable: true, //Indicates that new attributes can be traversed // Access Descriptor get (){ return name // Returns the properties of wife }, set (value){ name = value } }) console.log(person.wife) person.wife = 'Jo' // value is not required to write to access descriptors console.log(person.wife) for(var item in person) { console.log(item) }
Data descriptor wriable only controls the value when the data is described and cannot be written with access descriptors
Object.defineProperty() - Simulate vm object
You have learned the basic use of defineProperty in two subsections. Next, we will simulate the effect of Vue instantiation through defineProperty
When Vue is instantiated, we explicitly assign data, but it can be accessed and set through **vm instance.property**
How?
var vm = new Vue({ data: { name: 'Zhang San' } }) vm.name = 'Li Si'
This is actually achieved through Object.defineProperty
var person = { name: 'Xiao Fang' } var vm = {} // vm object // Object.defineProperty access descriptor Object.defineProperty(vm, 'name', { // Access descriptor get/set get () { return person.name //Returns the value of the same property as person }, set (value) { debugger // It's time to give the values in person, too person.name = value } }) console.log(vm.name) // Get value=> get method vm.name = 'Curly Bubble Face' // set method called console.log(vm.name)
In the code above, we implemented a data proxy in vm to change name directly from person to vm or person
Summary: We proxied the data in person in the access descriptors of set and get.
MVVM =>Data Agent=> Object.defineProperty =>Access Descriptor get/set =>Agent Data
MVVM not only takes this data, but also updates it to the DOM responsively, that is, when the data changes, we want to reflect the data** to the view
By debugging, we found that we can listen for data changes in the set function, just notify the corresponding view to update when the data changes.
So how do I tell you? What technology do I use? We'll bring up a publish-subscribe model in the next section
Introduction to publish subscription mode
What is the publish subscription model?
Actually, we've used it many times already. Publish/Subscribe means someone ** post a message **, someone subscribes to a message, and at the data level, more=>more
That is, program A can trigger or subscribe to multiple messages
One **eventBus** used in the vue project is a reflection of the publish subscription model
What do we bring this pattern for?
In the last section, we were able to capture changes in our data, and now we're going to try to change our view by publishing subscriptions as the data changes
Let's start with a few elements of the core code for this publishing subscription
First, we want publish subscription objects to be instantiated
Publish message $emit
Subscription Message$on
Based on these ideas, we get the following code
// Create a constructor function Events () {} // Subscription Message Listening Message Events.prototype.$on = function() {} // Publish a message Events.prototype.$emit = function (){}
Implementation of Publish Subscription Mode
<button onclick="emitEvent()">Trigger Event</button> <script> // Create a constructor function Events () { // Constructor // Opening up a space is only valid for the current instance this.subs = {} // The event name and callback function {key (event name): [callback function 1, callback function 2...] value (callback function)} } // Subscription message listens for message eventName event name, fn is the callback function that should be triggered when the event is triggered Events.prototype.$on = function(eventName,fn) { // Event name=>Callback function=>Find the callback function corresponding to this event and execute it when an event is triggered // if(this.subs[eventName]) { // this.subs[eventName].push(fn) // }else { // this.subs[eventName] = [fn] // } this.subs[eventName] = this.subs[eventName] || [] this.subs[eventName].push(fn) } // The first parameter to publish a message must be eventName (the name of the event to trigger)... params represents all parameters after eventName Events.prototype.$emit = function (eventName, ...params ) { // Get the name of the event should go to our open space to find if there is a callback function if(this.subs[eventName]) { // Someone is listening to you // Callback function of others this.subs[eventName].forEach(fn => { // Change this orientation // fn(...params) //Call the callback function and pass parameters // Three ways to change the this point in the callback function // fn.apply(this, [...params]) // apply parameter [parameter list] // Fn.call(this,... Params)//several parameters fn.bind(this, ...params)() // Bind usage bind does not execute a function but changes the function this directly }); } } var event = new Events() // instantiation // Open a listen event.$on("changeName", function(a,b,c, d, e) { console.log(this) alert(a + '-' +b +'-'+ c + '-'+ d +'-'+ e) }) // Listen for an event // Call Trigger Method var emitEvent = function () { event.$emit("changeName", 1,2,3,4,5) } </script>
This uses the call/apply/bind method to modify the this point inside the function
Publish-subscribe mode allows you to notify a lot of people to do things when an event triggers, and what Vue does is update the DOM
MVVM Implementation-DOM Review
We learned Object.defineProperty and Publish-Subscribe modes, and almost had the ability to write an MVVM by hand.
But before we implement MVVM, let's review the meaning and structure of View, Dom
What is DOM?
Document object model document
What does Dom do?
Page elements can be manipulated through ** objects **
What types of object nodes are in the Dom
You can check with a small example below
<div id="app"> <h1>Our wills unite like a fortress,Co-Resistance to Epidemics</h1> <div> <span style='color:red;font-weight: bold;'>Pedestrian A:</span> <span>Wishing all heroes a safe return</span> </div> </div> <script> var app = document.getElementById("app") console.dir(app) </script>
Looking at the output above, we can see that
Node type of element type nodeType is 1 text type 3, Everything inside the document object is **Node**
childNodes is all nodes children refers to all elements => nodeType =1 nodes
All child nodes are placed under the property childNodes, which is a pseudo array=>pseudo array and does not have an array method. Has the len gt h property
What is the set of attributes for all tags?
Attributes =>Places all attributes
What does analysing DOM objects do? The data capture and publishing subscriptions we prepared earlier are meant to update the DOM
Let's start handwriting an MVVM example
Handwrite a simple version of vuejs Object.defineProperty =>Add Attributes.Modify Attribute Data Agent
Publish Subscription=>Publish Event Subscription Events
Dom =>Update View
MVVM Implementation-Implementing Vue's Constructor and Data Proxy
The challenge is to write a simple ** vuejs ** handwriting to enhance our own technical capabilities.
We want to implement the constructor for mvvm
Constructor mimics vuejs with data/el
The data is ultimately proxied to the current vm instance, either through the vm or through this.$data
// Handwriting a simple version of vuejs for mvvm // options is the option that all vue attributes have $ function Vue (options) { this.$options = options // Placement options this.$el = typeof options.el === 'string' ? document.querySelector(options.el) : options.el // Assigning a dom object to $el is consistent with the official vuejs this.$data = options.data || {} // Data proxy wants vm to be able to proxy data for $data // Hope vm.name is $data.name this.$proxyData() // Proxy data } // A good way to proxy data Vue.prototype.$proxyData = function () { // this is the current instance // Key is every key in the data Object.keys(this.$data).forEach(key => { Object.defineProperty(this, key, { // Access Descriptor get () { return this.$data[key] // Return data from $data }, // Setting up the data requires setting the value to the value of $data and determining whether the data is equal before setting it up set (value) { // Value is a new value If the new value equals the old value, there is no need to set it again if (this.$data[key] === value ) return this.$data[key] = value // If you don't wait to set the value again } }) }) } var vm = new Vue({ el: '#app', //and possibly other selectors and possibly dom objects data: { name: 'Lvpu', wife: 'army officer's hat ornaments' } }) vm.wife = 'Xishi' vm.name = 'Xiao Ming' console.log(vm.name)
MVVM Implementation-Data Hijacking Observer
OK, this next step is critical. We want to do ** data hijacking **, who is hijacked and why?
In the code in the last section, we can either use vm.name='value'or vm.$data.name ='value', so where can we capture changes in the data?
Either this.data or this.$data changes the data for $data, so we need to ** hijack ** the data for $data, that is, listen to its set
Data Hijacking means that we want to monitor changes in the data layer of Model s in MVVM
// Data hijacking Vue.prototype.$observer = function () { // Who is to be hijacked? $data // Traverse all key s in $data Object.keys(this.$data).forEach(key => { // Hijacking=>Changes in Hijacking data->Listening for Changes in data=> Set Method // obj / prop / desciptor let value = this.$data[key] // Re-open up a space value Object.defineProperty(this.$data, key, { // How many descriptors are there? Data descriptor (value,writable) access descriptor (get/set) get () { return value }, set (newValue) { if(newValue === value) return value = newValue // Once you enter the set method, the M in MVVM changes and the data changes // MVVVM => Model =>Publish Subscription Mode=>Update Dom View } }) }) }
Complete hijacking of data in constructor
function Vue (options) { this.$options = options // Placement options this.$el = typeof options.el === 'string' ? document.querySelector(options.el) : options.el // Assigning a dom object to $el is consistent with the official vuejs this.$data = options.data || {} // Data proxy wants vm to be able to proxy data for $data // Hope vm.name is $data.name this.$proxyData() // Proxy data proxy data from $data to vm instance this.$observer() // data Hijacking Hijacking $data Changes }
MVVM Implementation-Compiler Compiler-Design Architecture
Proxy: All data in $data is proxied to this
Hijacking: $data changes
Now that we've basically instantiated the data and finished proxying and hijacking it, we need to implement a few methods
When the data changes=>Convert the template to the latest object based on the latest data
Determine whether a node is a text node
Determine whether a node is an element node
Determine if directive v-model / v-text
Processing Element Nodes
Processing text nodes
So let's define the following methods
// Execution of a general method constructor for compiling templates Vue.prototype.$compile = function () { } // Processing text node nodeType =3 Vue.prototype.$compileTextNode = function () {} // Element node when processing element node nodeType = 1 Vue.prototype.$compileElementNode = function () {} // Determine whether a node is a text node Vue.prototype.$isTextNode = function () {} // Determine whether a node is an element node Vue.prototype.$isElementNode = function () {} // Determines whether an attribute is an instruction that all instructions start with v- Vue.prototype.$isDirective = function () {}
MVVM implementation-compile template Compiler implements basic framework logic
Now that we've got $el, the dom element of the page, through the constructor, we can implement the basic logic of compilation
Note: Text nodes no longer have child nodes because text is the final representation
Element node must have children
// Compile Template // Execution of a general method constructor for compiling templates // Rootnode is the root node that passes into this loop=>Find all the child nodes under rootnode=>Child node=>Child node=>Child node=>Child node>Child node... until no child node is found Vue.prototype.$compile = function (rootnode) { let nodes = Array.from(rootnode.childNodes) // Is a pseudo array converting a pseudo array to a true array nodes.forEach(node => { // Loop through each node to determine the node type If you are a text node, use the text node's handling. If an element node requires the element node's handling if(this.$isTextNode(node)) { // If it is a text node this.$compileTextNode(node) // Processing text node Current node No more child nodes Necessary to continue finding } if(this.$isElementNode(node)) { // If it is an element node this.$compileElementNode(node) // Processing Element Nodes // If there must be children beneath the element node, only the text node is the end point // Recursive=>calls itself this.$compile(node) // Pass-through parameter guarantees automatic stop when finding node.chidNodes with length 0 // It guarantees that all nodes under $el will be traversed once } }) } // Processing text node nodeType =3 Vue.prototype.$compileTextNode = function () {} // Element node when processing element node nodeType = 1 Vue.prototype.$compileElementNode = function () {} // Determines whether a node is a text node nodeType ===3 Vue.prototype.$isTextNode = function (node) { return node.nodeType === 3 // Representation is a text node } // Determine whether a node is an element node Vue.prototype.$isElementNode = function (node) { return node.nodeType === 1 // Representation is element node }
The basic logic of the above code is that when a text node is encountered, it is treated as a text node. When an element node is encountered, it is treated as an element node.
If an element node is encountered, it means that ** is not finished ** Need to call the next level of lookup
MVVM Implementation-Compiler Compiler-Processing Text Node
// Processing text node nodeType =3 Vue.prototype.$compileTextNode = function (node) { // console.log(node.textContent) // What to do after getting the contents of the text node {{name}} =>Real value // regular expression const text = node.textContent // Get the contents of the text node to see if there are any interpolation expressions const reg = /\{\{(.+?)\}\}/g // Will match all {{unknown}} if (reg.test(text)) { // If a match can be made to indicate that there is an interpolation expression in this text // The value representing the last matching regular expression const key = RegExp.$1.trim() // Name attribute=>value of name $1 takes the first key node.textContent = text.replace(reg, this[key] ) // Gets the value of the property and replaces the interpolation expression in the text node } }
Tip: You don't need to remember but you need to understand when developing
MVVM Implementation-Compiler Compiler-Processing Element Node
// Element node when processing element node nodeType = 1 Vue.prototype.$compileElementNode = function (node) { // Instruction v-text V-model =>Data change=>View update update update data change // v-text ='value'=> textContent on innerText // Get all the properties of the node let attrs = Array.from(node.attributes) // Convert all attributes to an array // Loop whether each attribute attribute attribute has V-IF v-denotes instructions attrs.forEach(attr => { if (this.$isDirective( attr.name)) { // Judging Instruction Type if(attr.name === 'v-text') { // The v-text directive means that the value expressed after the v-text acts on the innerText or textContent of the element node.textContent = this[attr.value] // assignment } if(attr.name === 'v-model') { // Indicates that I want to bind the current node in both directions node.value = this[attr.value] // v-model assigning value is not textContent } } // If you start with v-it's an instruction }) }
MVVM Implementation-Data Driven View-Publication Subscription Manager
Now that we have responsive data and compilation templates, we need to compile them as the data changes
As mentioned earlier, this step requires publishing subscriptions, so we implement publishing subscriptions on a Vue-based basis
// Handwriting a simple version of vuejs for mvvm // options is the option that all vue attributes have $ function Vue (options) { this.subs = {} // Event Manager this.$options = options // Placement options this.$el = typeof options.el === 'string' ? document.querySelector(options.el) : options.el // Assigning a dom object to $el is consistent with the official vuejs this.$data = options.data || {} // Data proxy wants vm to be able to proxy data for $data // Hope vm.name is $data.name this.$proxyData() // Proxy data proxy data from $data to vm instance this.$observer() // data Hijacking Hijacking $data Changes this.$compile(this.$el) // Template first compilation rendering recursion requirement parameter must be passed in here // Recursion is a simple algorithm=>commonly used for processing tree data, nested data China/Beijing/Haidian/Zhongguancun/Zhichunlu/Haidianqiao/982/person // Recursion is essentially the function itself calling itself=>The condition passed in for the next recursion=>The same condition for two recursions=>Dead Loop } // Publish Subscription Manager for Vue$on $emit // Listen for events Vue.prototype.$on = function (eventName, fn) { // Event name=>Callback function=>Find the callback function corresponding to this event and execute it when an event is triggered // if(this.subs[eventName]) { // this.subs[eventName].push(fn) // }else { // this.subs[eventName] = [fn] // } this.subs[eventName] = this.subs[eventName] || [] this.subs[eventName].push(fn) } // Trigger Event Vue.prototype.$emit = function (eventName, ...params) { // Get the name of the event should go to our open space to find if there is a callback function if(this.subs[eventName]) { // Someone is listening to you // Callback function of others this.subs[eventName].forEach(fn => { // Change this orientation // fn(...params) //Call the callback function and pass parameters // Three ways to change the this point in the callback function // fn.apply(this, [...params]) // apply parameter [parameter list] // Fn.call(this,... Params)//several parameters fn.bind(this, ...params)() // Bind usage bind does not execute a function but changes the function this directly }); } }
MVVM implementation - driving view changes as data changes
Everything is ready now, only the east wind
Our data proxy, data hijacking, template compilation, event publishing subscriptions all work now by publishing through events when data changes, and then
Notification data can be compiled
// Data hijacking Vue.prototype.$observer = function () { // Who is to be hijacked? $data // Traverse all key s in $data Object.keys(this.$data).forEach(key => { // Hijacking=>Changes in Hijacking data->Listening for Changes in data=> Set Method // obj / prop / desciptor let value = this.$data[key] // Re-open up a space value Object.defineProperty(this.$data, key, { // How many descriptors are there? Data descriptor (value,writable) access descriptor (get/set) get () { return value }, set: (newValue) => { if(newValue === value) return value = newValue // Once you enter the set method, the M in MVVM changes and the data changes // MVVVM => Model =>Publish Subscription Mode=>Update Dom View // Global compilation is performed only once to trigger an event view layer to listen for an event by publishing subscription mode // Trigger an event this.$emit(key) // Trigger an event with an attribute as the event name } }) }) }
Listen for data changes
// Compile Template Data Changed=>Update Template Data to Latest // Execution of a general method constructor for compiling templates // Rootnode is the root node that passes into this loop=>Find all the child nodes under rootnode=>Child node=>Child node=>Child node=>Child node>Child node... until no child node is found Vue.prototype.$compile = function (rootnode) { let nodes = Array.from(rootnode.childNodes) // Is a pseudo array converting a pseudo array to a true array nodes.forEach(node => { // Loop through each node to determine the node type If you are a text node, use the text node's handling. If an element node requires the element node's handling if(this.$isTextNode(node)) { // If it is a text node this.$compileTextNode(node) // Processing text node Current node No more child nodes Necessary to continue finding } if(this.$isElementNode(node)) { // If it is an element node this.$compileElementNode(node) // Processing Element Nodes // If there must be children beneath the element node, only the text node is the end point // Recursive=>calls itself this.$compile(node) // Pass-through parameter guarantees automatic stop when finding node.chidNodes with length 0 // It guarantees that all nodes under $el will be traversed once } }) } // Processing text node nodeType =3 Vue.prototype.$compileTextNode = function (node) { // console.log(node.textContent) // What to do after getting the contents of the text node {{name}} =>Real value // regular expression const text = node.textContent // Get the contents of the text node to see if there are any interpolation expressions const reg = /\{\{(.+?)\}\}/g // Will match all {{unknown}} if (reg.test(text)) { // If a match can be made to indicate that there is an interpolation expression in this text // The value representing the last matching regular expression const key = RegExp.$1.trim() // Name attribute=>value of name $1 takes the first key node.textContent = text.replace(reg, this[key] ) // Gets the value of the property and replaces the interpolation expression in the text node this.$on(key, () => { // Update the view in the callback function if the value represented by the key property changes node.textContent = text.replace(reg, this[key] ) // Replace the original bracketed content with the latest value and assign it to textContent }) } } // Element node when processing element node nodeType = 1 Vue.prototype.$compileElementNode = function (node) { // Instruction v-text V-model =>Data change=>View update update update data change // v-text ='value'=> textContent on innerText // Get all the properties of the node let attrs = Array.from(node.attributes) // Convert all attributes to an array // Loop whether each attribute attribute attribute has V-IF v-denotes instructions attrs.forEach(attr => { if (this.$isDirective( attr.name)) { // Judging Instruction Type if(attr.name === 'v-text') { // The v-text directive means that the value expressed after the v-text acts on the innerText or textContent of the element node.textContent = this[attr.value] // Assignment attr.value => v-text="name" this.$on(attr.value, () => { node.textContent = this[attr.value] //The data is now updated }) } if(attr.name === 'v-model') { // Indicates that I want to bind the current node in both directions node.value = this[attr.value] // v-model assigning value is not textContent this.$on(attr.value, () => { node.value = this[attr.value] //The data is now updated }) } } // If you start with v-it's an instruction }) }
Then let's write an example to test one
MVVM Implementation-View Change Update Data
Finally, we want to achieve a two-way binding where the data changes at the same time as the view changes
// Element node when processing element node nodeType = 1 Vue.prototype.$compileElementNode = function (node) { // Instruction v-text V-model =>Data change=>View update update update data change // v-text ='value'=> textContent on innerText // Get all the properties of the node let attrs = Array.from(node.attributes) // Convert all attributes to an array // Loop whether each attribute attribute attribute has V-IF v-denotes instructions attrs.forEach(attr => { if (this.$isDirective( attr.name)) { // Judging Instruction Type if(attr.name === 'v-text') { // The v-text directive means that the value expressed after the v-text acts on the innerText or textContent of the element node.textContent = this[attr.value] // Assignment attr.value => v-text="name" this.$on(attr.value, () => { node.textContent = this[attr.value] //The data is now updated }) } if(attr.name === 'v-model') { // Indicates that I want to bind the current node in both directions node.value = this[attr.value] // v-model assigning value is not textContent this.$on(attr.value, () => { node.value = this[attr.value] //The data is now updated }) node.oninput = () => { // Need to assign the value of the current most recent node to its own data this[attr.value] = node.value // View Occurs=>Data Changes } // If an element is bound to the v-model directive, it should listen for value change events for that element } } // If you start with v-it's an instruction }) }