Mind mapping
preface
In the last article we went through the process of rendering individual root component data to the page. Vue source preliminary exploration (three) single component mount (rendering).
Now let’s do one thing, change the properties and manually call the _update() function to make the page trigger an update. We noticed that the page has also been updated.
<body>
<div id="app">
<li>{{name}}</li>
<li>{{age}}</li>
</div>
<script src="./vue.js"></script>
<! -- < script SRC = "https://cdn.jsdelivr.net/npm/[email protected]" > < / script > -- >
<! -- <script src="./test.js"></script> -->
<script>
var vm = new Vue({
el: '#app'.data: {
name: 'Ming'.age: 20
}
})
vm.name = 'morning'
vm._update(vm._render())
</script>
</body>
Copy the code
The body of the
Rely on collection and trigger updates
function defineReactive(data, key, value){
// If the key of the current object is another object, perform deep monitoring
// Add a dep to each attribute
let dep = new Dep()
observe(value)
Object.defineProperty(data, key,{
get() {
if(Dep.target){ //dep.target now saves watcher
dep.depend()
}
return value
},
set(newValue) {
// If the new value is equal to the old value, no processing is done
if(value === newValue) return
// If an object is set, the new object is hijacked again.
observe(newValue)
value = newValue
// Tell all watcher updates are available
dep.notify()
}
})
}
Copy the code
Dep for each attribute
let id = 0;
class Dep{
constructor() { // Put watcher in deP
this.subs = []
this.id = id++
}
depend() {
Dep.target.addDep(this) // Make Watcher remember deP
}
addSub(watcher){ // Make deP remember Watcher
this.subs.push(watcher)
}
notify(){
this.subs.forEach((watcher) = >{
watcher.update()
})
}
}
// Make a mark to store watcher
Dep.target = null // Create a global variable, a static attribute
export default Dep
Copy the code
Watcher per view
import Dep from "./dep"
let id = 0
class Watcher {
constructor(vm, fn, cb, options) {
this.vm = vm;
this.fn = fn;
this.cb = cb;
this.options = options;
this.id = id++;
this.depsId = new Set(a)this.deps = [] / / store dep
this.getter = fn; //fn is the external render logic
this.get(); // Do component rendering for the first time
}
addDep(dep) {
let did = dep.id
if(!this.depsId.has(did)){
this.depsId.add(did)
this.deps.push(dep)
dep.addSub(this) // Make deP remember Watcher}}get() {
// Perform render logic
Dep.target = this;
this.getter(); // When executing the render logic, invoke the render function, which triggers the get function in the data response
Dep.target = null;
}
update() {
// Will be updated several times
console.log('update')
this.get()
}
}
export default Watcher
Copy the code
Dep and Watcher diagram
conclusion
- Vue uses observer mode. The default component creates a Watcher when rendering (and renders the view).
- Let the deP of the property record the current watcher when the render function passes the get method in the response.
- Also remind Watcher of this DEP (not yet used) because deP and Watcher are many-to-many, because one property may correspond to multiple views, and one view to multiple data.
- If the data changes, the DEP of the corresponding property is notified, which in turn notifies the stored Watcher to update the page.
Subsequent write operations are required when the same attribute value is modified multiple times on the page. nextTick()
Links to a series of articles (constantly updated…)
Vue source exploration (a) responsive principle
Vue source exploration (two) template compilation
A preliminary study of Vue source code (3) Single component mount (rendering)
Vue source exploration (four) dependent (object) collection process
Object asynchronous update nextTick()