1. V-bind key source code analysis
1. Where are the v-bind attributes stored uniformly: attrsMap and attrsList
<p v-bind:title="vBindTitle"></p>
Assume p tagv-bind
It's meltedtitle
Attributes, let's analyzetitle
The attribute isvue
How is it processed?
After vue gets this html tag, it will do the following steps:
- Analysis
HTML
, parse out the attribute collectionattrs
,existstart
Return in the callback - Create in start callback
ASTElement,createASTElement(... ,attrs, ...)
- After creation
ASTElement
Will generateattrsList
andattrsMap
As for how to deal with it after creationv-bind:title
For such ordinary attribute values, you can find out in the v-bind:src source code analysis below.
2. Parses HTML, parse out attribute collection attrs, and return in the start callback
function handleStartTag (match) { ... const l = const attrs = new Array(l) for (let i = 0; i < l; i++) { const args = [i] ... attrs[i] = { name: args[1], value: decodeAttr(value, shouldDecodeNewlines) } } ... if () { // Upload to the start function here (tagName, attrs, unary, , ) } }
3. Create ASTElement in the start callback, createASTElement(... ,attrs, ...)
// parse HTMLparseHTML(template, { ... start(tag, attrs, unary, start, end) { let element: ASTElement = createASTElement(tag, attrs, currentParent) // Note the attrs here } })
4. After creation, ASTElement will generate attrsList and attrsMap.
// Create AST elementexport function createASTElement ( tag: string, attrs: Array<ASTAttr>, // Array of attribute objects parent: ASTElement | void // The parent element is also ASTElement): ASTElement { // The return is also ASTElement return { type: 1, tag, attrsList: attrs, attrsMap: makeAttrsMap(attrs), rawAttrsMap: {}, parent, children: [] } }
5. Attrs data type definition
// Declare an ASTAttr attribute abstract syntax tree object data typedeclare type ASTAttr = { name: string; // Attribute name value: any; // Attribute value dynamic?: boolean; // Is it a dynamic attribute? start?: number; end?: number };
6. Binding attribute acquisition function
Binding attribute get function getBindingAttr and attribute operation function getAndRemoveAttr
getBindingAttr
Its subfunctionsgetAndRemoveAttr
In dealing with specific scenariosv-bind
Very useful, that is,"v-bind
How to deal with different binding properties" chapter is very useful. Here is a list of them for the following articlev-bind:key
Source code analysis;v-bind:src
Source code analysis;v-bind:class
Source code analysis;v-bind:style
Source code analysis;v-bind:
Source code analysis Source code analysis reference.
export function getBindingAttr ( el: ASTElement, name: string, getStatic?: boolean ): ?string { const dynamicValue = getAndRemoveAttr(el, ':' + name) || getAndRemoveAttr(el, 'v-bind:' + name) if (dynamicValue != null) { return parseFilters(dynamicValue) } else if (getStatic !== false) { const staticValue = getAndRemoveAttr(el, name) if (staticValue != null) { return (staticValue) } } }
// note: this only removes the attr from the Array (attrsList) so that it // doesn't get processed by processAttrs. // By default it does NOT remove it from the map (attrsMap) because the map is // needed during codegen. export function getAndRemoveAttr ( el: ASTElement, name: string, removeFromMap?: boolean ): ?string { let val if ((val = [name]) != null) { const list = for (let i = 0, l = ; i < l; i++) { if (list[i].name === name) { (i, 1) // Delete an attribute from attrsList, not deleted from attrsMap break } } } if (removeFromMap) { delete [name] } return val }
2. How to get the value of v-bind
The following code is an example from the source code analysisvue
How to get itv-bind
value.
I will analyze it by recording several scenarios:
- Common
key
property - Bind a normal
html attribute:title
- Bind
class
andstyle
- Bind one
html DOM property:textContent
vBind:{ key: +new Date(), title: "This is a HTML attribute v-bind", class: "{ borderRadius: isBorderRadius }" style: "{ minHeight: 100 + 'px' , maxHeight}" text-content: "hello vue v-bind" } <div v-bind:key="" v-bind:title="" v-bind:class="" v-bind:style="" v-bind:="" /> </div>
1. v-bind:key source code analysis
function processKey (el) { const exp = getBindingAttr(el, 'key') if(exp){ ... = exp; } }
processKey
Used in functionsgetBindingAttr
Function, since we usev-bind
, useless:, soconst dynamicValue = getAndRemoveAttr(el, 'v-bind:'+'key')
;,getAndRemoveAttr(el, 'v-bind:key')
Function toattrsMap
Determine whether it exists'v-bind:key'
, take the value of this property as val and assign it fromattrsList
Delete, but will notattrsMap
Delete, finally'v-bind:key'
The value of val isdynamicValue
, then return the parsed filtered result, and finally the result isset
forprocessKey
The element of thekey property
. Then store it insegments
In, as forsegments
What is it, you can see in the source code above.
2. v-bind:title source code analysis
title
It's a kind of "non-vue
Special "that is ordinaryHTML attribute
。
function processAttrs(el){ const list = ; ... if ((name)) { // v-bind name = (bindRE, '') value = parseFilters(value) ... addAttr(el, name, value, list[i], ...) } } export const bindRE = /^:|^\.|^v-bind:/ export function addAttr (el: ASTElement, name: string, value: any, range?: Range, dynamic?: boolean) { const attrs = dynamic ? ( || ( = [])) : ( || ( = [])) (rangeSetItem({ name, value, dynamic }, range)) = false }
By reading the source code, we can see that for native attributes, such as title, vue will first parse out the original attributes, such as title.name
andvalue
, and then do a series of whether there ismodifiers
The judgment ofmodifier
The part of the article will be explained in detail below), and finally updatedASTElement
ofattrs
,therebyattrsList
andattrsMap
Also synchronously updated.
3. v-bind:class source code analysis
css
ofclass
It is a very important level in the presentation level of front-end development. thereforevue
In Forclass
The attributes have also been treated with a lot of special treatments.
function transformNode (el: ASTElement, options: CompilerOptions) { const warn = || baseWarn const staticClass = getAndRemoveAttr(el, 'class') if (staticClass) { = (staticClass) } const classBinding = getBindingAttr(el, 'class', false /* getStatic */) if (classBinding) { = classBinding } }
existtransfromNode
In the function, it will passgetAndRemoveAttr
Get staticclass
, that is, class="foo";getBindingAttr
Get the bound class, that isv-bind:class="
"Right nowv-bind:class="{ borderRadius: isBorderRadius
}", assign the classBinding of ASTElement to the attribute we bind for subsequent use.
4. v-bind:style source code analysis
Style is the priority of direct operation styles after important
, a more intuitive operation style than classHTML attribute
. vue also handles this property in special terms.
function transformNode (el: ASTElement, options: CompilerOptions) { const warn = || baseWarn const staticStyle = getAndRemoveAttr(el, 'style') if (staticStyle) { = (parseStyleText(staticStyle)) } const styleBinding = getBindingAttr(el, 'style', false /* getStatic */) if (styleBinding) { = styleBinding } }
existtransfromNode
In the function, it will passgetAndRemoveAttr
Get a static style, that isstyle="{fontSize: '12px'
}";existgetBindingAttr
Get the bound style, that isv-bind:style=""i.e. v-bind:class={ minHeight: 100 + 'px' , maxHeight
}", where maxHeight is a variable,ASTElement
ofstyleBinding
Assign the attributes we bind for subsequent use.
5. v-bind: Source code analysis
textContent
It is a native property of the DOM object, so it can be identified through prop. If we want to set a DOM prop directly through vue, we can make modifications on the DOM node.
Let's look at the source code below.
function processAttrs (el) { const list = ... if ((name)) { // v-bind if (modifiers) { if ( && !isDynamic) { name = camelize(name) if (name === 'innerHtml') name = 'innerHTML' } } if (modifiers && ) { addProp(el, name, value, list[i], isDynamic) } } } export function addProp (el: ASTElement, name: string, value: string, range?: Range, dynamic?: boolean) { ( || ( = [])).push(rangeSetItem({ name, value, dynamic }, range)) = false } props?: Array<ASTAttr>;
Through the above source code, we can see thatv-bind:
In-housetext-content
First, it was humped intotextContent
(This is becauseDOM property
All are camel formats), vue is correctinnerHtml
The error writing method is compatible and it is also intentional. Then, the textContent attribute is added to theASTElement's props
, and here props are essentially an ASTATtr.
There is a question worth thinking about:Why do it? What are the similarities and differences with HTML attribute?
- No
HTML attribute
You can directly modify the text content of the DOM, so you need to identify it separately - It is faster than manually updating the DOM text node through js, eliminating the steps of querying the dom and replacing the text content.
- You can see which attribute we v-bind on the tag, which is very intuitive
- In fact, v-bind:title can be understood as
v-bind:,v-bind:
onlyvue
HTML is a default not to add modifiersattribute
Forget it
6. V-bind modifier.camel.sync source code analysis
.camel
It's just camel, it's very simple. But .sync is not that simple, it will be expanded into a v-on listener that updates the parent component's binding value.
Actually, when I first saw this .sync modifier, I was confused, but if I read the .sync of the component carefully and combined with actual work, I will find that it is powerful.
<Parent v-bind:foo="" v-on:updateFoo=" = $event" ></Parent>
In vue, the parent component passes the child componentprops
It cannot be passed directly by subcomponents = newFoo
Go to modify. Unless we are in the componentthis.$emit("updateFoo", newFoo),
Then use v-on to listen on the parent componentupdateFoo
event. If you want better readability, you can$emit
Change the name to update:foo, and thenv-on:update:foo
。
Is there a simpler way to write it? ? ? That is our .sync operator. It can be abbreviated as:
<Parent v-bind:=""></Parent>
Then in the subcomponent passesthis.$emit("update:foo", newFoo
); to trigger, note that the event name here must be in the format of update:xxx, because in the source code of vue, using the .sync modifier attribute will be used to generate a customv-on:update:xxx
monitor.
Let's look at the source code below:
if ( && !isDynamic) { name = camelize(name) } if () { syncGen = genAssignmentCode(value, `$event`) if (!isDynamic) { addHandler(el,`update:${camelize(name)}`,syncGen,null,false,warn,list[i]) // Hyphenate is a hyphenate function, where camelize is a camelize function 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) } }
By reading the source code, we can see:v-bind:
vue will determine whether the attribute is a dynamic attribute. If it is not a dynamic property, first add a camel listening, and then add a hyphen to it, for examplev-bind:
,firstv-on:update:fooBar
,Thenv-on:update:foo-bar
. v-on listening is throughaddHandle
r plus. If it is a dynamic attribute, it will not be camel or hyphenated, throughaddHandler(el,update:${name}, ...),
Listen honestly to the event of that dynamic attribute.
A summary in one sentence.sync
: .sync
is a syntactic sugar, simplifying v-bind and v-on toand
this.$emit('update:xxx'
). It provides us with a way for child components to quickly update parent component data.
This is all about this article about how to understand v-bind in vue. This is the end of this article. For more related v-bind content in vue, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!