关键词不能为空

当前您在: 主页 > 英语 >

Vue 源码解析(中)

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-02-28 05:38
tags:

-

2021年2月28日发(作者:发挥余热)


Vue


源码解析:深入响应式原理(中)



Directive


Vue


指令类 型很多,


限于篇幅,


我们不会把所有指令的解析过程都介绍一遍 ,


这里结合前面的例子只介绍



v-text


指令的解析过程,


其他 指令的解析过


程也大同小异。



前面我们提到了



Vue


实例创建的生命周期,


在给



data


添加



Observer


之后,


有一个过程是调用



e


方法对模板进行编译。


compile



法的源码定义如下:




源码目录:


src/instance/in ternal/-->


ype._compile = function (el) {


var options = this.$$options


// transclude and init element


// transclude can potentially replace original


// so we need to keep reference; this step also injects


// the template and caches the original attributes


// on the container node and replacer node.


var original = el


el = transclude(el, options)


this._initElement(el)


// handle v-pre on root node (#2026)


if (pe === 1 && getAttr(el, 'v-pre') !== null) {


return


}


// root is always compiled per- instance, because


// container attrs and props can be different every time.


var contextOptions = this._context && this._context.$$options


var rootLinker = compileRoot(el, options, contextOptions)


// resolve slot distribution


resolveSlots(this, options._content)


// compile and link the rest


var contentLinkFn


var ctor = uctor


// component compilation can be cached


// as long as it's not using inline-template


if (options._linkerCachable) {


contentLinkFn =


if (!contentLinkFn) {


contentLinkFn = = compile(el, options)


}


}


// link phase


// make sure to link root with prop scope!


var rootUnlinkFn = rootLinker(this, el, this._scope)


var contentUnlinkFn = contentLinkFn


? contentLinkFn(this, el)


: compile(el, options)(this, el)


// register composite unlink function


// to be called during instance destruction


this._unlinkFn = function () {


rootUnlinkFn()


// passing destroying: true to avoid searching and


// splicing the directives


contentUnlinkFn(true)


}


// finally replace original


if (e) {


replace(original, el)


}


this._isCompiled = true


this._callHook('compiled')


}



我们可以通过下图来看一下这个方法编译的主要流程:




这个过程通过



el = transclude(el, option)


方法把



template


编译成一段



document fragment


,拿到



el


对象。而指令解析部分就是通过



compile(el, options)


方法实现的。接下来我们看一下



compile


方法的实现,它的源码定义如下:



< !-


源码目录:


src/compiler/-->


export function compile (el, options, partial) {


// link function for the node itself.


var nodeLinkFn = partial || !options._asComponent


? compileNode(el, options)


: null


// link function for the childNodes


var childLinkFn =


!(nodeLinkFn && al) &&


!isScript(el) &&


ldNodes()


? compileNodeList(odes, options)


: null


/**


* A composite linker function to be called on a already


* compiled piece of DOM, which instantiates all directive


* instances.


*


* @param {Vue} vm


* @param {Element|DocumentFragment} el


* @param {Vue} [host] - host vm of transcluded content


* @param {Object} [scope] - v-for scope


* @param {Fragment} [frag] - link context fragment


* @return {Function|undefined}


*/


return function compositeLinkFn (vm, el, host, scope, frag) {


// cache childNodes before linking parent, fix #657


var childNodes = toArray(odes)


// link


var dirs = linkAndCapture(function compositeLinkCapturer () {


if (nodeLinkFn) nodeLinkFn(vm, el, host, scope, frag)


if (childLinkFn) childLinkFn(vm, childNodes, host, scope, frag)


}, vm)


return makeUnlinkFn(vm, dirs)


}


}



compile


方法主要通过



compileNode(el, options)


方法完 成节点的解析,


如果节点拥有子节点,


则调用

< br>


compileNodeList(odes, options)


方法完成子节点的解析。


compileNodeList


方法其实就是遍历子节点,递归调用



compileNode


方法。因为



DOM


元素本身就是树结构,这种递归


方法也就是常见的树的深度遍历方法,


这样就可以完成整个



DOM


树节点的解析。


接下来我们看一下



compileNode


方法的实现,


它的源码定义如下:


< /p>



源码目录:


src/compil er/-->


function compileNode (node, options) {


var type = pe


if (type === 1 && !isScript(node)) {


return compileElement(node, options)


} else if (type === 3 && ()) {


return compileTextNode(node, options)


} else {


return null


}


}



compileNode


方法对节点的



nodeType


做判断,如果是一个非



script


普通的元素(


div



p


等);则调用



compileElement(node, options)


法解析;如果是一个非空的文本节点,则调用



compileTextNode(node, options)


方法解析。我们在前面的例子中解析的是非空文本节点



count:


{{times}}


,这实际上是



v-text


指令,它的解析是通过



compileTextNode


方法实现的。接下来我们看一下



compileTextNode


方法,它的源码定


义如下:




源码目录:


src/compiler/ -->


function compileTextNode (node, options) {


// skip marked text nodes


if (node._skip) {


return removeText


}


var tokens = parseText(ext)


if (!tokens) {


return null


}


// mark adjacent text nodes as skipped,


// because we are using ext to compile


// all adjacent text nodes together. This fixes


// issues in IE where sometimes it splits up a single


// text node into multiple ones.


var next = bling


while (next && pe === 3) {


next._skip = true


next = bling


}


var frag = DocumentFragment()


var el, token


for (var i = 0, l = i < l; i++) {


token = tokens[i]


el =


? processTextToken(token, options)


: TextNode()


Child(el)


}


return makeTextNodeLinkFn(tokens, frag, options)


}



compileTextNode


方法首先调用了



parseText


方法对



ext


做解析。主要通过正则表达式解析



count: {{times}}


部分,我们看一下


解析结果,如下图所示:




解析后的



tokens


是一个数组,


数组的每个元素则是一个



Object



如果是



count:


这样的普通文本,


则返回的对象只有



value


字段;


如果是



{{times}}


这样的插值,则返回的对象包含



ht ml



onTime



tag



value


等字段。



接下来创建



document fragment


,遍历



tokens


创建



DOM


节点插入到这个



fragment


中。在遍历过程中,如果



token




tag


字段,则调




TextNode()


方法创建



DOM


节点;否则调用


proces sTextToken(token, options)


方法创建



DOM


节点和扩




token


对象。我们看一下调用后的结果,如下图所示:


-


-


-


-


-


-


-


-



本文更新与2021-02-28 05:38,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/678988.html

Vue 源码解析(中)的相关文章