vue中的指令
简述
vue的指令系统是非常实用的功能,vue不仅提供多种常用的指令功能,例如v-model,还提供自定义指令,来提高开发效率。
vue中常见的指令有:
指令的设计
在模板编译一章说过,vue其实是将模板template解析并转换成渲染函数render,而解析模板的时候是用正则表达式来解析标签名、属性、文本等,对于指令来说,其实本身就可以当做是一个以v-
开头的HTML属性(@
、:
、ref
除外),这个时候只要利用正则表达式就可以判断使用了哪些指令,来调用对应的函数。
// 获取指令
export const onRE = /^@|^v-on:/;
export const dirRE = process.env.VBIND_PROP_SHORTHAND
? /^v-|^@|^:|^\.|^#/
: /^v-|^@|^:|^#/;
const argRE = /:(.*)$/;
export const bindRE = /^:|^\.|^v-bind:/;
const slotRE = /^v-slot(:|$)|^#/;
// ...
function processAttrs(el) {
const list = el.attrsList;
let i, l, name, rawName, value, modifiers, syncGen, isDynamic;
for (i = 0, l = list.length; i < l; i++) {
name = rawName = list[i].name;
value = list[i].value;
if (dirRE.test(name)) {
// mark element as dynamic
el.hasBindings = true;
// modifiers
modifiers = parseModifiers(name.replace(dirRE, ""));
// support .foo shorthand syntax for the .prop modifier
if (process.env.VBIND_PROP_SHORTHAND && propBindRE.test(name)) {
(modifiers || (modifiers = {})).prop = true;
name = \`.\` + name.slice(1).replace(modifierRE, "");
} else if (modifiers) {
name = name.replace(modifierRE, "");
}
if (bindRE.test(name)) {
// v-bind
name = name.replace(bindRE, "");
value = parseFilters(value);
isDynamic = dynamicArgRE.test(name);
if (isDynamic) {
name = name.slice(1, -1);
}
if (modifiers) {
if (modifiers.prop && !isDynamic) {
name = camelize(name);
if (name === "innerHtml") name = "innerHTML";
}
if (modifiers.camel && !isDynamic) {
name = camelize(name);
}
if (modifiers.sync) {
syncGen = genAssignmentCode(value, \`$event\`);
if (!isDynamic) {
addHandler(
el,
\`update:${camelize(name)}\`,
syncGen,
null,
false,
warn,
list[i]
);
if (hyphenate(name) !== camelize(name)) {
addHandler(
el,
\`update:${hyphenate(name)}\`,
syncGen,
null,
false,
warn,
list[i]
);
}
} else {
// handler w/ dynamic event name
addHandler(
el,
\`"update:"+(${name})\`,
syncGen,
null,
false,
warn,
list[i],
true // dynamic
);
}
}
}
if (
(modifiers && modifiers.prop) ||
(!el.component && platformMustUseProp(el.tag, el.attrsMap.type, name))
) {
addProp(el, name, value, list[i], isDynamic);
} else {
addAttr(el, name, value, list[i], isDynamic);
}
} else if (onRE.test(name)) {
// v-on
name = name.replace(onRE, "");
isDynamic = dynamicArgRE.test(name);
if (isDynamic) {
name = name.slice(1, -1);
}
addHandler(el, name, value, modifiers, false, warn, list[i], isDynamic);
} else {
// normal directives
// 去掉前缀
name = name.replace(dirRE, "");
// parse arg
const argMatch = name.match(argRE);
let arg = argMatch && argMatch[1];
isDynamic = false;
if (arg) {
name = name.slice(0, -(arg.length + 1));
if (dynamicArgRE.test(arg)) {
arg = arg.slice(1, -1);
isDynamic = true;
}
}
addDirective(
el,
name,
rawName,
value,
arg,
isDynamic,
modifiers,
list[i]
);
}
} else {
// literal attribute
if (process.env.NODE_ENV !== "production") {
const res = parseText(value, delimiters);
}
addAttr(el, name, JSON.stringify(value), list[i]);
// #6887 firefox doesn't update muted state if set via attribute
// even immediately after element creation
if (
!el.component &&
name === "muted" &&
platformMustUseProp(el.tag, el.attrsMap.type, name)
) {
addProp(el, name, "true", list[i]);
}
}
}
}