There are already a lot of articles on the Internet, so take advantage of 3.0 to follow the trend
preface
Github pages is the most effective version of github/ vue-learning-source-code
Object.defineProperty
DefineProperty lets us hijack getters and setters for a property, for example:
var person = {
firstName: 'meimei'.lastName: 'han'
};
Object.defineProperty(person, 'fullName', {
get() {
return this.lastName + ' ' + this.firstName;
},
set(val) {
let arr = val.split(' ');
this.lastName = arr[0];
this.firstName = arr[1]; }});Copy the code
After hijacking the fullName, changing firstName or lastName updates the fullName and vice versa
The target
The goal of this article is to emulate the VUE implementation to update the DOM after changing the data so that the following code can work:
<div id="app">
<p>firstName: {{firstName}}</p>
<p>lastName: {{lastName}}</p>
<p>fullName: {{fullName}}</p>
</div>
<script src="./vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data() {
return {
firstName: 'meimei',
lastName: 'han'
};
},
computed: {
fullName: {
get: function(a) {
return this.lastName + ' ' + this.firstName;
},
set: function(val) {
let arr = val.split(' ');
this.lastName = arr[0];
this.firstName = arr[1]; }}}});</script>
Copy the code
Observer model
All we need to do is update the DOM when the data changes. The observer mode works well for the data. We only need to collect dependencies when the data changes.
class Dep {
constructor() {
this.subs=[]
}
addSub(item) {
this.subs.push(item);
}
notify() {
this.subs.forEach(item= >{ item.update(); }); }}Copy the code
Dom depends on data, so data get needs to be used in the process of obtaining DOM. Dependencies can be collected when data GET is performed. Data dependent data needs to be recorded when DOM update get data is performed when set data. Add a target attribute to class Dep as a logging tool and defineProperty as follows:
Dep.target = undefined;
function defineReactive(obj, key) {
let dep = new Dep();
let val = obj[key];
Object.defineProperty(obj, key, {
get: function() {
if (Dep.target) {
// Collect dependencies in get
dep.addSub(Dep.target);
}
return val;
},
set: function(value) {
val = value;
// Set triggers an updatedep.notify(); }})}Copy the code
Now that the tools are in place, it’s time to iterate through data’s properties, using defineReactive
Data, computed, AND DOM dependencies
Parsing the DOM uses data and computed, computed GET uses data
- Through the data
function initData(vm) {
let data = vm.$options.data;
data = typeof data === 'function' ? data() : data;
Object.keys(data).forEach(key= > {
defineReactive(data, key);
});
// Proxies the attributes of data to the VM instance
proxy(data, vm);
}
Copy the code
- Traverse the computed
function initComputed(vm) {
let computed = vm.$options.computed;
let defaultSetter = function(key) {
console.error(this.' has no setter for ', key)
}
Object.keys(computed).forEach(key= > {
let getter = typeof computed[key] === 'function' ? computed[key] : computed[key].get;
let setter = typeof computed[key] === 'function' ? defaultSetter.bind(computed) : computed[key].set;
Object.defineProperty(computed, key, {
get: getter.bind(vm),
set: setter.bind(vm)
})
})
// Proxies computed attributes to vm instances
proxy(computed, vm);
}
Copy the code
- Parsing the dom
function mount(vm) {
let update = compile(vm);
let watcher = new Watcher(update);
// Set target to dom
Dep.target = watcher;
update();
Dep.target = undefined;
}
function compile(vm) {
let el = vm.$options.el;
el = document.querySelector(el);
vm.$el = el;
let innerHTML = el.innerHTML;
let getter = function() {
return innerHTML.replace(/ {{(. *?) }}/g.function() {
// This uses data computed GET to collect dependencies
return vm[arguments[1]]}); };let update = function() {
let iHTML = getter();
el.innerHTML = iHTML;
}
return update;
}
Copy the code
Many say
When collecting dependencies, we add a target attribute to the Dep class, combined with targetStack in vUE. This collection approach can be buggy if managed carelessly, as mentioned in another article: Familiar with Vue? Can you explain this endless cycle? . Cheer for their own filling hole ~