vue responsive principle
Data driven
Data responsive: according to the model, it is just a common JavaScript object. When we modify the data, the view will be updated, avoiding frequent DOM operations and improving development efficiency. This is different from Jquery, which operates DOM frequently
Bidirectional binding:
Data changes, view changes, view changes, data changes( Bidirectional binding contains the content of data response) We can use`v-model` Create a two-way data binding on a form element
Data driven is one of Vue's most unique features
In the development process, we only need to pay attention to the data itself, not how the data is rendered to the view. Mainstream`MVVM`Frameworks have implemented data responsive and two-way binding, so data can be bound to`DOM`Come on.
Responsive core principles
vue2 principle
Official documents: https://cn.vuejs.org/v2/guide/reactivity.html
In vue2 The implementation of response in X is through object Defineproperty. Note that this property cannot be shimmed, so Vue does not support IE8 and earlier browsers.
Data changes are reflected in the guide map
Declarative change view:
Render the value of the name attribute in data as text into the p tag marked with v-text. In vue, we call this marked declarative rendering instruction
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <p v-text='name'></p> <p v-text='age'></p> </div> <script> let data = { name: 'Li Bai', age: 12 } Object.keys(data).forEach(key => { define(data, key, data[key]) }); function define(data, key, value) { Object.defineProperty(data, key, { get() { return value }, set(newValue) { value = newValue compile() } }) } function compile() { let app = document.querySelector('#app') let nodes = app.childNodes // console.log(nodes); nodes.forEach(item => { if (item.nodeType === 1) { let arr = item.attributes console.log(arr); Array.from(arr).forEach(node => { let name = node.nodeName let value = node.nodeValue if (name === 'v-text') { item.innerHTML = data[value] } }) } }) } compile() </script> </body> </html>
Command change view:
Through the original operation of dom, the latest value of name can be displayed inside the p element every time
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <p></p> </div> <script> let p = document.querySelector("#app p") let data = { name: 'Li Bai', age: 12 } // console.log(Object.keys(data)); Object.keys(data).forEach(key => { console.log(data); console.log(key); define(data, key, data[key]) }); function define(data, key, value) { // console.log(data, key, value); Object.defineProperty(data, key, { get() { return value }, set(newValue) { value = newValue p.innerHTML = value } }) } p.innerHTML = data.name </script> </body> </html>
View changes reflect data
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <input type="text" v-model="name"> </div> <script> let data = { name: 'Li Bai', age: 18 } Object.keys(data).forEach(key => { defineReactiveProperty(data, key, data[key]) }) function defineReactiveProperty(data, key, value) { console.log(); Object.defineProperty(data, key, { get() { return value }, set(newValue) { if (newValue === value) { return } value = newValue // When using declarative rendering, it is necessary to facilitate all nodes to see which node has our custom binding attributes compile() } }) } function compile() { let app = document.querySelector('#app') // Get all child elements under the app const nodes = app.childNodes nodes.forEach(node => { if (node.nodeType === 1) { const attrs = node.attributes Array.from(attrs).forEach(attr => { const nodeName = attr.nodeName const nodeValue = attr.nodeValue if (nodeName === 'v-model') { // When the data in the data changes, change the value attribute of the text box to update the value of the text box node.value = data[nodeValue] // When the content of the text box changes, the value of the attribute in data is updated node.addEventListener('input', e => { data[nodeValue] = e.target.value }) } }) } }) } compile() </script> </html>
Vue3 responsive principle
Vue3's responsive principle is accomplished through Proxy.
Proxy listens directly to objects rather than attributes, so there is no need to use loops when converting multiple attributes into getters / setters.
Proxy is newly added in ES6 course and is not supported by IE
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Proxy</title> </head> <body> <div id="app">hello</div> <script> //Simulate the data option in Vue let data = { msg: "hello", count: 0, }; //Simulate Vue instances //Create a proxy object vm for data so that you can use vm msg to get the value of msg attribute in data, and the get method will be executed at this time let vm = new Proxy(data, { // Is executed when a member of the vm is accessed //target represents the proxy object (data object here), and key represents the attribute in the proxy object get(target, key) { console.log("get key:", key, target[key]); return target[key]; }, //When setting the members of vm set(target, key, newValue) { console.log("set key:", key, newValue); if (target[key] === newValue) { return; } target[key] = newValue; document.querySelector("#app").textContent = target[key]; }, }); //test vm.msg = "aaaa"; console.log(vm.msg); </script> </body> </html>
Bidirectional data binding
Bidirectional data binding includes two parts: data change updates the view, and view change updates the data.
Realize bidirectional data binding
The basic idea is that we can add an input event to the text box (the first text box) and trigger the event after inputting data, At the same time, the data entered by the user in the text box is assigned to the attributes in data (the view changes and the data is updated. When the data changes, the set method in observer.js will be executed to update the view, that is, the responsive mechanism is triggered).
//Processing v-model modelUpdater(node, value, key) { //v-model is the attribute of the text box. Assigning a value to the text box requires the value attribute node.value = value; new Watcher(this.vm, key, (newValue) => { node.value = newValue; }); //Realize bidirectional binding node.addEventListener("input", () => { this.vm[key] = node.value; }); }
An input event is added to the current text box node. This event will be triggered when content is entered in the text box. At the same time, the value entered by the user in the text box node is re assigned to the corresponding attribute in data.
Enter a value in the text box, and the corresponding difference expression and the content in v-text will change. At the same time, output VM. In the console The value of MSG will find that the data has also changed.
After assigning a value to the attribute in data, it will execute observer The set method in JS updates the view, which triggers a responsive mechanism.