写文章不容易,点个赞呗兄弟
专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧
研究基于 Vue版本 【2.5.17】
如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧
哈哈哈,今天终于到了属性解析的部分了,之前已经讲过了 parse 流程,标签解析,最后就只剩下 属性解析了 (´・ᴗ・`)
如果你对 compile 不感兴趣的就先不看把,毕竟不会马上起到什么作用~~ヾ(●´∀`●)
如果你们没看过前面两篇文章的,十分建议看一下~
Compile 之 Parse 主要流程
Compile 之 标签解析
如果看了,你们应该知道《属性解析》在哪部分中,没错,在处理 头标签的 部分 parse-start 中
那么我们就来到 parse - start 这个函数中!
看到下面的源码中,带有 process 的函数都是用于处理 属性的
function parse(template){
parseHTML(template,{
start:(...抽出放下面)
})
}
function start(tag, attrs, unary) {
// 创建 AST 节点
var element = createASTElement(tag, attrs, currentParent);
// 节点需要解析,并没有还没有处理
if (!element.processed) {
processFor(element);
processIf(element);
processSlot(element);
for (var i = 0; i < transforms.length; i++) {
element = transforms[i](element, options) || element;
}
processAttrs(element);
}
.... 省略部分不重要代码
// 父节点就是上一个节点,直接放入 上一个节点的 children 数组中
if (currentParent) {
// 说明前面节点有 v-if
if (element.elseif || element.else) {
processIfConditions(element, currentParent);
} else {
currentParent.children.push(element);
element.parent = currentParent;
}
}
}
看完了吧,上面处理属性的函数大概有几个
没啥难的,就是内容多了点
1、processFor,解析 v-for
2、processIf,解析 v-if
3、processSlot,解析 slot
4、processAttrs,解析其他属性
5、transforms,解析样式属性
并且只有 element.processed 为 false 的时候,才会进行解析
因为 element.processed 表示属性已经解析完毕,一开始 element.processed 的值是 undefined
下面就会逐个说明上面的方法
先明确下 element 是什么?
parse 流程中说过了,element 是 通过解析得到的 tag 信息,生成的 ast
下面会逐个分析下上面的四个函数,并会附上相应的 element 例子作为参考
其实还有很多其他处理函数,为了维持文章的长度,所以我去掉了
开篇之前,大家需要先了解 getAndRemoveAttr 这个函数,下面很多地方都会使用到
作用就是从 el.attrList 中查找某个属性,返回返回属性值
function getAndRemoveAttr(el, name, removeFromMap) {
var val =el.attrsMap[name];
if (removeFromMap) {
delete el.attrsMap[name];
}
return val
}
parse-start 中的 tramsforms
在parse -start 这个函数的 开头,我们看到有一个 transfroms 的东西
transforms 是一个数组,存放两个函数,一个是处理 动静态的 class,一个处理 动静态的 style
两种处理都很简单的,我们来简单看看处理结果就好了
处理 class
function transformNode(el, options) {
var staticClass = getAndRemoveAttr(el, 'class');
if (staticClass) {
el.staticClass = JSON.stringify(staticClass);
}
// :class="b" 直接返回 b
var classBinding = getBindingAttr(el, 'class', false);
if (classBinding) {
el.classBinding = classBinding;
}
}