說明
v-sync
是用來同步組件的prop
和它上下文中的變量的,這里面有一個(gè)非常有趣的小技巧:$watch
會(huì)返回一個(gè)unwatch
的函數(shù)來取消監(jiān)聽裳仆。
源碼解讀
const SYNC_HOOK_PROP = '$v-sync';
/**
* v-sync directive
*
* Usage:
* v-sync:component-prop="context prop name"
*
* If your want to sync component's prop "visible" to context prop "myVisible", use like this:
* v-sync:visible="myVisible"
*/
export default {
bind(el, binding, vnode) {
const context = vnode.context; // 獲取上下文羡棵,即組件渲染的作用域中
const component = vnode.child; // 返回組件實(shí)例
const expression = binding.expression; // 返回表達(dá)式
const prop = binding.arg; // 返回傳參
if (!expression || !prop) { // 如果沒有表達(dá)式或者傳參
console.warn('v-sync should specify arg & expression, for example: v-sync:visible="myVisible"');
return;
}
if (!component || !component.$watch) { // 判斷是否包含 watch 來確保是 Vue 的組件
console.warn('v-sync is only available on Vue Component');
return;
}
// 將組件的 prop 與上下文中的信息同步筝野,返回取消 watch 的函數(shù)
const unwatchContext = context.$watch(expression, (val) => {
component[prop] = val;
});
// 將上下文中的信息和組件的 prop嫌松,返回取消 watch 的函數(shù)
const unwatchComponent = component.$watch(prop, (val) => {
context[expression] = val;
});
// 保存到組件實(shí)例中
Object.defineProperty(component, SYNC_HOOK_PROP, {
value: {
unwatchContext,
unwatchComponent
},
enumerable: false
});
},
unbind(el, binding, vnode) {
const component = vnode.child;
if (component && component[SYNC_HOOK_PROP]) { // 取消監(jiān)聽
const { unwatchContext, unwatchComponent } = component[SYNC_HOOK_PROP];
unwatchContext && unwatchContext();
unwatchComponent && unwatchComponent();
}
}
};