指令
示例
<template>
<div>
this is a directive
<div id="hook-arguments-example" v-demo:foo.a.b="msg"></div>
<p style="margin-bottom: 20px; border-bottom: 1px solid red;">
do some thing <span @click="chgMsg">chg the msg</span>
</p>
</div>
</template>
<script>
const demoDirect = {
bind: function (el, binding, vnode) {
var s = JSON.stringify
el.innerHTML =
'name: ' + s(binding.name) + '<br>' +
'value: ' + s(binding.value) + '<br>' +
'expression: ' + s(binding.expression) + '<br>' +
'argument: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys: ' + Object.keys(vnode).join(', ')
},
inserted: function () {},
update: function () {
console.log('to update')
},
componentUpdated: function () {},
unbind: function () {}
}
export default {
data () {
return {
msg: 'hello'
}
},
directives: {
'demo' : demoDirect
},
methods: {
chgMsg() {
console.log('click msg')
this.msg = 'wowow' + Date.now();
}
}
}
</script>
我们知道通过指令可以在元素生命周期如挂载、更新或者卸载的时候做一些处理。
通过update方法我们可以看到其中的如bind、update方法的调用
代码如下
function _update (oldVnode, vnode) {
var isCreate = oldVnode === emptyNode;
var isDestroy = vnode === emptyNode;
var oldDirs = normalizeDirectives$1(oldVnode.data.directives, oldVnode.context);
var newDirs = normalizeDirectives$1(vnode.data.directives, vnode.context);
var dirsWithInsert = [];
var dirsWithPostpatch = [];
var key, oldDir, dir;
for (key in newDirs) {
oldDir = oldDirs[key];
dir = newDirs[key];
if (!oldDir) {
// new directive, bind
callHook$1(dir, 'bind', vnode, oldVnode);
if (dir.def && dir.def.inserted) {
dirsWithInsert.push(dir);
}
} else {
// existing directive, update
dir.oldValue = oldDir.value;
dir.oldArg = oldDir.arg;
callHook$1(dir, 'update', vnode, oldVnode);
if (dir.def && dir.def.componentUpdated) {
dirsWithPostpatch.push(dir);
}
}
}
if (dirsWithInsert.length) {
var callInsert = function () {
for (var i = 0; i < dirsWithInsert.length; i++) {
callHook$1(dirsWithInsert[i], 'inserted', vnode, oldVnode);
}
};
if (isCreate) {
mergeVNodeHook(vnode, 'insert', callInsert);
} else {
callInsert();
}
}
if (dirsWithPostpatch.length) {
mergeVNodeHook(vnode, 'postpatch', function () {
for (var i = 0; i < dirsWithPostpatch.length; i++) {
callHook$1(dirsWithPostpatch[i], 'componentUpdated', vnode, oldVnode);
}
});
}
if (!isCreate) {
for (key in oldDirs) {
if (!newDirs[key]) {
// no longer present, unbind
callHook$1(oldDirs[key], 'unbind', oldVnode, oldVnode, isDestroy);
}
}
}
}
v-model
// transform component v-model data into props & events
if (isDef(data.model)) {
transformModel(Ctor.options, data);
}
// transform component v-model info (value and callback) into
// prop and event handler respectively.
function transformModel (options, data) {
var prop = (options.model && options.model.prop) || 'value';
var event = (options.model && options.model.event) || 'input'
;(data.attrs || (data.attrs = {}))[prop] = data.model.value;
var on = data.on || (data.on = {});
var existing = on[event];
var callback = data.model.callback;
if (isDef(existing)) {
if (
Array.isArray(existing)
? existing.indexOf(callback) === -1
: existing !== callback
) {
on[event] = [callback].concat(existing);
}
} else {
on[event] = callback;
}
}
示例代码
<input type="text"
:value="value"
@input="value = $event.target.value"
>
<input v-model="name" type="text">
对应的render函数
t("input",
{ attrs: { type: "text" }, domProps: { value: e.value },
on: { input: function (n) { e.value = n.target.value } } }),
t("input",
{ directives: [{ name: "model", rawName: "v-model", value: e.name, expression: "name" }],
attrs: { type: "text" }, domProps: { value: e.name },
on: { input: function (n) { n.target.composing || (e.name = n.target.value) } } })])
网友评论