寫在開頭
本文探索Vue插件開發一系列api ,很重要的一個就是:Vue.util.defineReactive
,它就是Vue監聽current
變量重要執行者
console.log(Vue.util);
執行結果:
Vue.util.defineReactive
很重要的一個就是:Vue.util.defineReactive
,它就是Vue監聽current
變量重要執行者
不妨從源碼來學習:
/**
* Define a reactive property on an Object.
*/
//Vue的data監聽,也是通過這個方法
function defineReactive$$1 (
obj,
key,
val,
customSetter,
shallow
) {
//依賴收集者
var dep = new Dep();
var property = Object.getOwnPropertyDescriptor(obj, key);
if (property && property.configurable === false) {
return
}
// cater for pre-defined getter/setters
var getter = property && property.get;
var setter = property && property.set;
if ((!getter || setter) && arguments.length === 2) {
val = obj[key];
}
var childOb = !shallow && observe(val);
//雙向綁定
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
var value = getter ? getter.call(obj) : val;
if (Dep.target) {
//進行依賴收集
dep.depend();
/*採用依賴收集的原因:*/
//1.data裏面的數據並不是所有地方都要用到
//2.如果我們直接更新整個視圖,會造成資源浪費
//3.將依賴於某個變量的組件收集起來
if (childOb) {
childOb.dep.depend();
if (Array.isArray(value)) {
dependArray(value);
}
}
}
return value
},
set: function reactiveSetter (newVal) {
var value = getter ? getter.call(obj) : val;
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
/* eslint-enable no-self-compare */
if (customSetter) {
customSetter();
}
// #7981: for accessor properties without setter
if (getter && !setter) { return }
if (setter) {
setter.call(obj, newVal);
} else {
val = newVal;
}
childOb = !shallow && observe(newVal);
//觸發依賴的組件產生更新
dep.notify();
}
});
}
雙向綁定
上述關於響應式 雙向綁定,強烈推薦之前寫過的一篇文章:
手寫實現defineReactive
我們可以通過defineReactive
來實現Vue監聽current的監視者,監聽某個第三方的變量
手寫:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
//Vue插件開發一系列api
//console.log(Vue.util.defineReactive);
//test是屬於window的對象
var test={
testa:'計時開始'
}
//設置定時器
setTimeout(function(){
test.testa='計時結束'
},2000)
function a(){
console.log(6);
}
a.install=function(vue){
//console.log(vue);
//監聽testa
Vue.util.defineReactive(test,'testa');
//全局混入vue實例
vue.mixin({
data(){
return {
c:'歡迎訪問超逸の博客'
}
},
methods:{
},
beforeCreate:function(){
this.test=test;
},
//全局生命週期注入
created:function(){
//console.log(this)
}
});
}
Vue.use(a);
new Vue({
router,
render: h => h(App)
}).$mount('#app')
然後我們在HelloWorld組件進行渲染,查看頁面
執行結果:
疑問:爲什麼要寫在beforeCreate
裏面?
解決:因爲create
階段組件已經生成了,this實例已經創建了,而beforeCreate
纔剛開始。這樣HelloWorld組件可以this調用來獲取testa的值
學如逆水行舟,不進則退