You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
可以看到 modifiers 是一个空对象,但是事件名字由 click 变成了 ~click。实际上对于一个使用了 once 修饰符的事件绑定,解析器会在原始事件名称前添加 ~ 符并将其作为新的事件名称,接着会忽略 once 修饰符,所以 once 修饰符不会出现在 modifiers 对象中。为什么要忽略 once 修饰符呢?因为对于后面的程序来讲,该修饰符已经没有使用的必要的,因为通过检查事件名称的第一个字符是否为 ~ 即可判断该事件是否为 once 的。除了 once 修饰符之外,以下列出的修饰符也不会出现在 modifiers 对象中:
1、事件名称为 click 并使用了 right 修饰符,则 right 修饰符不会出现在 modifiers 对象中,因为在解析阶段使用了 right 修饰符的 click 事件会被重写为 contextmenu 事件,假如有如下模板:
Vue 模板 AST 详解
type
节点元素描述对象的
type
属性用来标识一个节点的类型。它有三个可取值,分别是
1
、2
、3
,分别代表的含义是:1
:代表当前节点类型为标签2
:包含字面量表达式的文本节点3
:普通文本节点或注释节点expression
当节点类型为
2
时,该节点的元素描述对象会包含expression
属性。tokens
与
expression
类似,当节点类型为2
时,该节点的元素描述对象会包含tokens
属性。节点元素描述对象的
tokens
属性是用来给weex
使用的,这里不做过多解释。tag
只有当节点类型为
1
,即该节点为标签时其元素描述对象才会有tag
属性,该属性的值代表标签的名字。attrsList
只有当节点类型为
1
,即该节点为标签时其元素描述对象才会有attrsList
属性,它是一个对象数组,存储着原始的html
属性名和值。attrsMap
节点元素描述对象的
attrsMap
属性与attrsList
属性一样,不同点在于attrsMap
是以键值对的方式保存html
属性名和值的。attrs
节点元素描述对象的
attrs
属性也是一个数组,并且也只有当节点类型为1
,即节点为标签的时候,其元素描述对象才会包含这个属性。attrs
属性不同于attrsList
属性,具体表现在:attrsList
属性仅用于解析阶段,而attrs
属性则用于代码生成阶段,甚至运行时阶段。attrsList
属性所包含的内容作为元素材料被解析器使用,而attrs
属性所包含的内容在运行时阶段会使用原生DOM
操作方法setAttribute
真正将属性设置给DOM
元素简单来说
attrs
属性会包含以下内容:v-bind
(或其缩写:
) 指令绑定的属性会被添加到attrs
数组中。为什么说大部分而不是全部呢?因为在
Vue
中有个Must Use Prop
的概念,对于一个属性如果它是Must Use Prop
的,则该属性不会被添加到attrs
数组中,而是会被添加到元素描述对象的props
数组中。如下
html
模板所示:最终
attrs
数组将为:attrs
数组中。如下
html
模板所示:最终
attrs
数组将为:大家观察绑定属性和非绑定属性在
attrs
数组中的却别?很容易能够发现,非绑定属性的属性值是经过JSON.stringify
的,我们已经不止一次的提到过这么做的目的。slot
特性会被添加到attrs
数组中。如下
html
模板所示:最终
attrs
数组将为:当然了由于
slot
本身是可绑定的属性,所以如果html
模板如下:最终
attrs
数组将为:区别在于
value
值是非JSON.stringify
化的。实际上,并不是出现在
attrs
数组中的属性就一定会使用setAttribute
函数将其添加到DOM
上,例如在运行时阶段,组件会根据该组件自身的props
定义,从attrs
中抽离出那些作为组件props
的属性元素。props
节点元素描述对象的
props
属性也是一个数组,它的格式与attrs
数组类似。就像attrs
数组中的属性在运行时阶段会使用setAttribute
函数将其添加到DOM
上一样,props
数组中的属性则会直接通过DOM
元素对象访问并添加,举个例子,假设props
数组如下:则在运行时阶段,会使用如下代码操作
DOM
:其中
elm
为DOM
节点对象。那么那些属性会被当做
props
呢?有两种,第一种是在绑定属性时使用了prop
修饰符,例如:由于绑定
some
属性的时候使用了prop
修饰符,所以some
属性不会出现在元素描述对象的attrs
数组中,而是会出现在元素描述对象的props
数组中。第二种是那些比较特殊的属性,在绑定这些属性时,即使没有指定
prop
修饰符,但是由于它属于Must Use Prop
的,所以这些属性会被强制添加到元素描述对象的props
数组中,只有那些属性是Must Use Prop
,可以查看附录:mustuseproppre
节点元素描述对象的
pre
属性是一个布尔值,它的真假代表着标签是否使用了v-pre
指令,既然是标签,所以只有当节点的类型为1
的时候其元素描述对象才会拥有pre
属性。ns
标签的
Namespace
,如果一个标签是SVG
标签,则该标签的元素描述对象将会拥有ns
属性,其值为'svg'
,如果一个标签是<math>
标签,则该标签元素描述对象的ns
属性值为字符串'math'
。forbidden
节点元素描述对象的
forbidden
属性是一个布尔值,其真假代表着该节点是否是在Vue
模板中禁止被使用的。在Vue
模板中满足以下条件的标签为禁止使用的标签:<style>
标签禁止出现在模板中。type
属性的<script>
标签,或type
属性值为'text/javascript'
的<script>
标签。parent
节点元素描述对象的
parent
属性是父节点元素描述对象的引用。children
节点元素描述对象的
children
属性是一个数组,存储着该节点所有子节点的元素描述对象。当然了有些节点是不可能拥有子节点的,比如普通文本节点,对于不可能拥有子节点的节点,其元素描述对象没有children
属性。ifConditions
如果一个标签使用
v-if
指令,则该标签的元素描述对象将会拥有ifConditions
属性,它是一个数组。如果一个标签使用v-else-if
或v-else
指令,则该标签不会被添加到其父节点元素描述对象的children
数组中,而是会被添加到相符的带有v-if
指令节点的元素描述对象的ifConditions
数组中。假设有如下模板:
则
<div>
标签元素描述对象将是:可以发现一个节点元素描述对象的
ifConditions
数组中也会包含节点自身的元素描述对象。slotName
只有
<slot>
标签的元素描述对象才会拥有slotName
属性,代表该插槽的名字,假设模板如下:则元素描述对象为:
注意
<slot>
标签的name
属性可以是绑定的:则元素描述对象为:
如果没有为
<slot>
标签指定name
属性,则其元素描述对象的slotName
属性为:slotTarget
如果一个标签使用了
slot
特性,则说明该标签将会被作为插槽的内容,为了标识该标签将被插入的位置,该标签的元素描述对象会拥有slotTarget
属性,假如有如下模板:则其元素描述对象为:
我们来对比一下使用
name
属性的<slot>
标签的元素描述对象:可以发现
slotTarget
和slotName
是一一对象的,这将会在运行时阶段用来寻找合适的插槽内容。另外
slot
特性也可以是绑定的:则其元素描述对象为:
如果没有为
slot
特性指定属性值,则该标签元素描述对象的slotTarget
属性的值为:slotScope
我们可以使用
slot-scope
特性来指定一个插槽内容是作用域插槽,此时该标签的元素描述对象将拥有slotScope
属性,假如有如下模板:其元素描述对象为:
scopedSlots
同常情况下我们插槽是作为一个组件的子节点去书写的,如下:
如上代码所示我们有自定义组件
<copm>
,并为该自定义组件提供了插槽内容。普通插槽会出现在组件元素描述对象的children
数组中,如下是以上模板的AST
:但如果一个插槽不是普通插槽,而是作用域插槽,则该插槽节点的元素描述对象不会作为组件的
children
属性存在,而是会被添加到组件元素描述对象的scopedSlots
属性中,假设有如下模板:则其生成的
AST
为:可以发现
scopedSlots
对象的键值是作用域插槽元素描述对象的slotTarget
属性的值。for、alias、iterator1、iterator2
当标签使用了
v-for
指令时,其元素描述对象将会拥有以上这四个属性,在如上四个属性中,其中for
、alias
这两个属性是肯定存在的,而iterator1
和iterator2
这两个属性不一定会存在。如果模板如下:
则其元素描述对象为:
如果模板如下:
则其元素描述对象为:
如果模板如下:
则其元素描述对象为:
if、elseif、
else
如果一个标签使用了
v-if
指令,则该标签元素描述对象就会拥有if
属性,假如有如下模板:则其元素描述对象为:
如果一个标签使用了
v-else-if
指令,则该标签元素描述对象就会拥有elseif
属性,假如有如下模板:则其元素描述对象为:
如果一个标签使用了
v-else
指令,则该标签元素描述对象就会拥有else
属性,假如有如下模板:则其元素描述对象为:
once
使用标签使用了
v-once
指令,则该标签的元素描述对象就会包含once
属性,它是一个布尔值,如下:key
如果标签使用
key
特性,则该标签的元素描述对象就会包含key
属性,假设有如下模板:则其元素描述对象为:
key
特性可以是绑定的:则其元素描述对象为:
ref
与
key
类似,假设有如下模板:则其元素描述对象为:
ref
特性可以是绑定的:则其元素描述对象为:
refInFor
元素描述对象的
refInFor
是一个布尔值。如果一个使用了ref
特性的标签是使用了v-for
指令标签的子代节点,则该标签元素描述对象的checkInFor
属性将会为true
,否则为false
component
如果标签使用
is
特性,则其元素描述对象将会拥有component
属性,假设有如下模板:则其元素描述对象为:
is
特性也可以是非绑定的:则
<tr>
标签的元素描述对象为:inlineTemplate
节点元素描述对象的
inlineTemplate
属性是一个布尔值,标识着一个组件使用使用内联模板,假设我们有如下模板:则其元素描述对象为:
hasBindings
节点元素描述对象的
hasBindings
属性是一个布尔值,用来标签当前节点是否拥有绑定,所谓绑定指的就是指令。所以如果一个标签使用了指令(包括自定义指令),则其元素描述对象的hasBindings
属性就会为true
。这里要强调一点,事件本身也是指令(
v-on
指令),绑定的属性也是指令(v-bind
指令)。events、nativeEvents
如果标签使用了
v-on
指令(或缩写@
)绑定了事件,则该标签元素描述对象中将包含events
属性,假如有如下模板:则其元素描述对象为:
如果在绑定事件的时候使用了修饰符,如下模板所示:
则其元素描述对象为:
可以看到多出了
modifiers
对象。但并不是所有修饰符都会出现在
modifiers
对象中,如下模板所示:如上模板中我们使用了
once
修饰符,但它并不会出现在modifiers
对象中,其最终生成的元素描述对象如下:可以看到
modifiers
是一个空对象,但是事件名字由click
变成了~click
。实际上对于一个使用了once
修饰符的事件绑定,解析器会在原始事件名称前添加~
符并将其作为新的事件名称,接着会忽略once
修饰符,所以once
修饰符不会出现在modifiers
对象中。为什么要忽略once
修饰符呢?因为对于后面的程序来讲,该修饰符已经没有使用的必要的,因为通过检查事件名称的第一个字符是否为~
即可判断该事件是否为once
的。除了once
修饰符之外,以下列出的修饰符也不会出现在modifiers
对象中:click
并使用了right
修饰符,则right
修饰符不会出现在modifiers
对象中,因为在解析阶段使用了right
修饰符的click
事件会被重写为contextmenu
事件,假如有如下模板:其元素描述对象为:
capture
、passive
修饰符不会出现在modifiers
对象中,原因与once
修饰符一样,capture
、passive
修饰符也会修改事件的名称,其中capture
修饰符会在原始事件名称之前添加!
,passive
修饰符会在事件名称之前添加&
,假如有如下模板则对于的元素描述对象分别为:
native
修饰符也不会出现在modifiers
对象中,原因很简单,native
修饰符是用来给解析器使用的,当解析器遇到使用了native
修饰符的事件,则会将事件信息添加到元素描述对象的nativeEvents
属性中,而不是events
属性中,例如:则其元素描述对象为:
除了以上修饰符之外,其他所有修饰符都会出现在
modifiers
对象中。directives
节点元素对象的
directives
属性是一个数组,用来保存标签中所有指令信息。但并不是所有指令信息都会保存在directives
数组中,比如v-for
指令和v-if
指令等等,因为这些指令在之前的处理中已经被移除掉。总的来说,指令分为内置指令和自定义指令,真正会出现在directives
数组中的只有部分内置指令以及全部自定义指令。不会出现在
directives
数组中的内置指令有:v-pre
、v-for
、v-if
、v-else-if
、v-else
以及v-once
。会出现在
directives
数组中的内置有:v-text
、v-html
、v-show
、v-model
以及v-cloak
。另外
v-on
、v-bind
是两个比较特殊的指令,当这两个指令拥有参数时,则不会出现在directives
数组中,比如:以上这两中写法,由于
v-on
和v-bind
指令拥有参数,所以这两个指令不会出现在directives
,但是我们知道v-on
和v-bind
指令可以直接绑定对象,此时他们是没有参数的:这时候
v-on
和v-bind
指令都会出现在directives
数组中。为什么同样指令不同的使用方式会得到不同的对待呢?其实正是由于使用方式的不同,才需要不同的处理,在代码生成阶段,我们会更加理解这一点。一个完整的指令由四部分组成,分别是:
指令的名称
、指令表达式
、指令参数
以及指令修饰符
,假设有如下模板:如上模板展示了一个完整的指令,最终其生成的元素描述对象为:
staticClass
如果以标签使用了静态
class
,即非绑定的class
,那么该标签的元素描述对象将拥有staticClass
属性,假设有如下模板:则其元素描述对象为:
classBinding
staticClass
属性中存储的是静态class
,而元素描述对象的classBinding
属性中所存储的则是绑定的class
,假设有如下模板:则其元素描述对象为:
staticStyle、styleBinding
节点元素描述对象的
staticStyle
属于包含的是静态style
内联样式信息,假设有如下模板:则其元素描述对象为:
可以发现
staticStyle
属性的值不是简单的把style
内联样式拷贝下来,而是将其解析成了对象的样子。styleBinding
属性类似于classBinding
属性。假设有如下模板:则其元素描述对象为:
plain
节点元素描述对象的
plain
属性是一个布尔值,plain
属性的真假将影响代码生成阶段对于VNodeData
的生成。什么是VNodeData
呢?在Vue
中一个VNode
代表一个虚拟节点,而VNodeData
就是用来描述该虚拟节点的管家信息。在代码生成节点我们会发现AST
中元素的大部分信息都用来生成VNodeData
。对于一个节点的元素描述对象来讲,如果其plain
属性值为true
,该节点所对应的虚拟节点将不包含任何VNodeData
。1、如果一个标签是使用了
v-pre
指令标签的子代标签,则该标签元素描述对象的plain
属性将使用为true
。但要注意的是,使用了v-pre
指令的那个标签的元素描述对象的plain
属性不为true
。2、如果你标签既没有使用特性
key
,又没有任何属性,那么该标签的元素描述对象的plain
属性将始终为true
。其实,我们完全可以认为,只有使用了
v-pre
指令的标签的子待节点其元素描述对象的plain
属性才会为true
。isComment
节点元素描述对象的
isComment
属性是一个布尔值,用来标识当前节点是否是注释节点。所以只有注释节点的元素描述对象才会有这个属性,并且其值为true
。The text was updated successfully, but these errors were encountered: