我們先打開文件src\compiler\parser
。
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 (
process.env.NODE_ENV !== 'production' &&
value.trim().length === 0
) {
warn(
`The value for a v-bind expression cannot be empty. Found in "v-bind:${name}"`
)
}
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])
if (process.env.NODE_ENV !== 'production' && name === 'model') {
checkForAliasModel(el, value)
}
}
} else {
// literal attribute
if (process.env.NODE_ENV !== 'production') {
const res = parseText(value, delimiters)
if (res) {
warn(
`${name}="${value}": ` +
'Interpolation inside attributes has been removed. ' +
'Use v-bind or the colon shorthand instead. For example, ' +
'instead of <div id="{{ val }}">, use <div :id="val">.',
list[i]
)
}
}
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])
}
}
}
}
在調用processAttrs函數之前已經調用過模板解析了,el參數的結構如下:
image.png
可以看到el.attrsList
的結構包含了所有DOM節點上的屬性,而不僅僅限于通過vue指令綁定的。
image.png
dirRE.test(name)
可以看到接下來就就會遇到dirRE(/^v-|^@|^:|^#/)
正則來匹配,我們這里是主要匹配 v-
開頭或者 :
開頭。
// 檢查是否存在修飾符
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, '') //清空修飾符
}
緊接著又會來查找指令上面是否有修飾符,在bind指令上面修飾符,比較少,一般是在v-on上面比較多,比如:
.stop
阻止單擊事件繼續傳播
.prevent
// 阻止默認行為
.capture
// 事件捕獲
.self
//捕獲本身的事件
.once
//一次性事件
if (bindRE.test(name)) { // v-bind
// 去掉“:”或者“v-bind:”指令(例子中是把“:title”變成title“”)
name = name.replace(bindRE, '')
// 格式解析,bind綁定可以通過單引號'、雙引號"、字符串模板``、大括號()、中括號[]
value = parseFilters(value)
// dynamicArgRE /^\[.*\]$/ 匹配大括號里面的任何字符串
isDynamic = dynamicArgRE.test(name)
if (isDynamic) {
name = name.slice(1, -1)
}
if ( process.env.NODE_ENV !== 'production' && value.trim().length === 0 ) {
warn(
`The value for a v-bind expression cannot be empty. Found in "v-bind:${name}"`
)
}
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 {
// 給el對象的attr屬性添加
addAttr(el, name, value, list[i], isDynamic)
}
}
以上代碼就是處理v-bind指令的了,通過上面的分析我們看到所有的屬性不管是否通過vue指令綁定的屬性都是在內部的attrs數組里面。
bind綁定可以通過單引號'、雙引號"、字符串模板``、大括號()、中括號[]