Vue3.0源码系列 -- 知识点及问题汇总
文章目录
TODO ShapeFlags 的溯源和用途?
涉及模块: runtime-core
标签(组件)种类(element, component, slot, template)
标签解析时的 TagType 检测
element,原生标签类型,默认值(如:
div
,结合options.isNativeTag()
)component 类型
!options.isNativeTag()
类型有
v-is
指令的core component 类型的(
[Teleport, Suspense, KeepAlive BaseTransition]
)options.isBuiltInComponent()
指定的类型大写字母开头的标签(如:
<Comp></Comp>
)标签名直接是 component 的(
<component></component>
)
slot 类型
template 类型
这些类型的定义和解析均在 parseTag(context, type, parent) 函数中完成
源码:
|
|
指令解析过程
parseChildren(context, mode, ancestors) -> parseElement(context, mode) -> 解析出整个 element parseTag(context, type, parent) -> 解析出标签 parseAttributes(context, type) -> 解析所有属性 parseAttribute(context, nameSet) -> 解析单个属性,结果返回到 props 中
解析的时候会根据映射关系,将缩写转换成名称。
如:
abbrev | name |
---|---|
: | bind |
@ | on |
# | slot |
处理代码:
|
|
属性解析的顺序是,先解析属性值,然后解析指令名称(name
),参数(arg
),修饰符(modifiers
)。
RCDATA/CDATA 类型解析
示例:
|
|
这两种类型数据的解析关键有几点(详情请移步 🛬🛬🛬 ):
重写 getTextMode 在里面对有需要的 tag 类型指定其是什么 mode
1 2 3 4 5 6 7 8 9 10
function parseElement(...) { // ... const mode = context.options.getTextMode(element, parent); // RCDATA 模式,它的内容都会被当做文本来处理 // 如:<textarea></div></textarea> 中的 `</div>` 只是个文本内容 const children = parseChildren(context, mode, ancestors); // ... }
重写 getNamespace 告知 parseChildren 走哪个分支
1 2 3 4 5 6 7 8
else if (s.startsWith("<![CDATA[")) { if (ns !== Namespaces.HTML) { node = parseCDATA(context, ancestors); } else { emitError(context, ErrorCodes.CDATA_IN_HTML_CONTENT); node = parseBogusComment(context); } }
一个较完整的 AST 结构:
|
|
辅助代码
这章主要是一些辅助代码。
parseUrl(url)
parseUrl 实现模拟:
|
|
1. ~/ccc/tmp -> Url { protocol: null, slashes: null, auth: null, host: null, port: null, hostname: null, hash: null, search: null, query: null, pathname: 'ccc/tmp', path: 'ccc/tmp', href: 'ccc/tmp' } 2. ~ccc/tmp/test.png -> Url { protocol: null, slashes: null, auth: null, host: null, port: null, hostname: null, hash: null, search: null, query: null, pathname: 'ccc/tmp/test.png', path: 'ccc/tmp/test.png', href: 'ccc/tmp/test.png' } 3. /ccc/tmp -> Url { protocol: null, slashes: null, auth: null, host: null, port: null, hostname: null, hash: null, search: null, query: null, pathname: '/ccc/tmp', path: '/ccc/tmp', href: '/ccc/tmp' } 4. @ccc/tmp -> Url { protocol: null, slashes: null, auth: null, host: null, port: null, hostname: null, hash: null, search: null, query: null, pathname: '@ccc/tmp', path: '@ccc/tmp', href: '@ccc/tmp' } 5. ~@svg/file.svg#fragment -> Url { protocol: null, slashes: null, auth: null, host: null, port: null, hostname: null, hash: '#fragment', search: null, query: null, pathname: '@svg/file.svg', path: '@svg/file.svg', href: '@svg/file.svg#fragment' } 6. https://www.cheng92.com -> Url { protocol: 'https:', slashes: true, auth: null, host: 'www.cheng92.com', port: null, hostname: 'www.cheng92.com', hash: null, search: null, query: null, pathname: '/', path: '/', href: 'https://www.cheng92.com/' } undefined