In the process of using VUE development, I always focus on the development and implementation of business functions, and seldom pay attention to the bottom things. If the interview is for a position of VUE development, one question will be asked 100% is: Please tell me the principle of vUE responsive implementation; For this reason, I have seen relevant videos and searched relevant materials online, and got a simple summary: Use Object.defineProperty to hijack properties in data. Replace all properties of data with getters and setters. With publisher and subscriber mode, each component has a Watcher instance. The setter notifies watcher, causing its associated components to be rerendered.
Object.defineProerty
Break down
Object.defineProerty
Basic usage of
First of all this makes the object based approach
let obj ={text:' '};
Object.defineProperty(obj, 'name', {
//value: 14,
//writable: true,
configurable: true.enumerable: true.set:function(val){
this.text=val;
},
get: function(){
return this.name; }});Copy the code
value
The value of this property can be any valid JavaScript value (numeric, object, function, etc.)configurable
When the value of ittrue
Can add object attribute description and delete, if the value is changed tofalse
It’s going to be irreversible;writable
When the value of ittrue
To the propertyvalue
Make an assignment changeenumerable
When the value of ittrue
, the property can be enumeratedget
Property, or undefined if there is no getter. This function is called when the property is accessed. No arguments are passed, but this object is passed (because of inheritance, this is not necessarily the object that defines the property). The return value of this function is used as the value of the propertyset
Property, or undefined if there is no setter. This function is called when the property value is modified. This method takes an argument (that is, the new value being assigned) and passes in the this object at the time of assignment.
Here vUE mainly uses attributesgetter
andsetter
methods
Uncaught TypeError: get and set cannot coexist with writable and value. Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, # at Function.defineProperty (
)
Object.defineProerty VS proxy
Vue2.0 uses Object.defineProerty to hijack Object properties and change getters and setters. Vue3.0 uses proxies to replace the core features of 2.0. What’s the difference?
** Object.defineProperty**
- Cannot listen for array length changes;
- Cannot listen for object addition;
- Only properties of objects can be hijacked, so we need to traverse each property of each object.
Proxy
- You can listen for changes to the array length property.
- Can listen to the addition of objects;
- Can proxy the whole object, do not need to traversal the object, greatly improve performance;
- There are as many as 13 interceptions, far more than Object. DefineProperty only has get and set interceptions.
The publisher subscriber pattern is implemented
Observer Model
Is usually referred to as post messages – subscriber mode or mechanism, it defines a one-to-many dependency between objects, as long as when an object’s state is changed, all depend on its object of warning and is automatically updated and solved the main function of the coupling between object and the observer, the state of an object changes to notify other objects.
Create an observer
const Observe =(function(){
let message = {};
return{
// Register messages
on: function (type, fn){
If the message does not exist, create a type for the message to push the execution method to the message execution queue
if(typeof message[type] === 'undefined'){
message[type] = [fn];
}else{
// If the message exists, the execution method is pushed directly to the execution queue corresponding to the message
message[type].push(fn)
}
},
// Publish a message?
emit: function(type, args){
// This message is returned directly if not registered
if(! message[type]){return;
}
// Define the message information
let events={
type: type,
args: args || {}
}
let len = message[type].length;
for(let i=0; i<len; i++){// Execute the corresponding methods of the message in turn
message[type][i].call(this, events)
}
},
// Remove the message interface
remove:function(type){
// If message execution queue exists
if(message[type] instanceof Array) {for(let i=message[type].length-1; i>=0; i--){ message[type].splice(i,1); }}}}}())Copy the code
Subscribe to a message
Observe.on('add'.function(data){
console.log(data.args.text);
})
Observe.on('newadd'.function (data) {
console.log(data.args.text+'~~~~~');
})
Copy the code
news
Observe.emit('add', {text:'I made the announcement.'})
Observe.emit('add', { text: 'I've made another announcement.' })
Observe.emit('newadd', { text: 'I just posted another message.' })
Copy the code
Remove message events
Observe.remove('newadd')
Observe.emit('newadd', { text: 'I just posted another message.' })
Copy the code
That’s all for the observer mode, but how to implement vUE’s bidirectional binding code can be seen in this reference: From vue source view observer mode
VUE responsive Precautions
There are some limitations to the use of responsiveness. Understanding Vue’s responsive principles can help you figure out these limitations, or you can simply memorize them. Because there are only a few restrictions, it is not difficult to remember them
Adds a new genus for the object
Because getter/setter methods are added at Vue instance initialization, only properties that already exist are reactive; When you add a new property to an object, adding it directly does not make the property responsive;
let app = new Vue({
data(){
return {
mydata: {firstName:'li'
}
}
}
})
app.mydata.lastName = 'jie'
Copy the code
In this case lastName will not be responded to
The solution
-
- Define this property on the object and set its value to
undefined
- Define this property on the object and set its value to
mydata:{
firstName:'li'
lastNmae: undefined
}
Copy the code
-
- use
Object.assign()
To create a new object and then overwrite the original object, which has the advantage of changing multiple properties at once
- use
app.mydata = Object.assign({},app.mydata,{
lastName: 'jie'
})
Copy the code
-
- Use vUE official
Vue.set()
, which can set the property to reactive
- Use vUE official
Vue.set(mydata,'lastName'.'jie')
Copy the code
This method can be called in a component using this.$set()
Setting array elements
Vue cannot detect changes to the following arrays:
- When you set an array item directly using an index, for example:
vm.items[indexOfItem] = newValue
- When you modify the length of an array, for example:
vm.items.length = newLength
Example:
var vm = new Vue({
data: {
items: ['a'.'b'.'c']
}
})
vm.items[1] = 'x' // Not responsive
vm.items.length = 2 // Not responsive
Copy the code
The solution
- Vue.set
Vue.set(vm.items, indexOfItem, newValue)
Copy the code
- Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
Copy the code
Vue.nextTick(callback)
When we change the array, the DOM is updated asynchronously. If we need to call the updated event or content of the DOM, we need to call vue.nexttick (). Simply put, the view is not updated immediately after the Vue changes the data. Then the view is updated uniformly
The official website says as follows:
Vue is executed asynchronously when updating the DOM. As long as it listens for data changes, Vue opens a queue and buffers all data changes that occur in the same event loop. If the same watcher is triggered more than once, it will only be pushed into the queue once. This removal of duplicate data while buffering is important to avoid unnecessary computation and DOM manipulation. Then, in the next event loop, “TICK,” Vue refreshes the queue and performs the actual (de-duplicated) work. Vue internally attempts to use native Promise.then, MutationObserver, and setImmediate for asynchronous queues, and setTimeout(fn, 0) instead if the execution environment does not support it.
For example, when you set vm.someData = ‘new value’, the component does not immediately re-render. When the queue is refreshed, the component is updated in the next event loop “TICK”. In most cases we don’t need to worry about this process, but if you want to do something based on the updated DOM state, it can be tricky. While vue.js generally encourages developers to think in a “data-driven” way and avoid direct contact with the DOM, sometimes we have to. To wait for Vue to finish updating the DOM after the data changes, use vue.nexttick (callback) immediately after the data changes. This callback will be called after the DOM update is complete.
<div id="example">{{message}}</div>
Copy the code
var vm = new Vue({
el: '#example'.data: {
message: '123'
}
})
vm.message = 'new message' // Change the data
vm.$el.textContent === 'new message' // false
Vue.nextTick(function () {
vm.$el.textContent === 'new message' // true
})
Copy the code
You can write this.$nextTick(callback}) in the component
conclusion
Well, about vUE’s responsivity principle and need to pay attention to points introduced here, which is mainly related to attribute hijacking and observer mode in the paper is also detailed clearly.