日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > vue >内容正文

vue

.9-Vue源码之AST(5)

發布時間:2025/5/22 vue 135 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .9-Vue源码之AST(5) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  上節跑完了超長的parse函數:

// Line-9261function baseCompile(template, options) {// Done!var ast = parse(template.trim(), options);// go! optimize(ast, options);var code = generate(ast, options);return {ast: ast,render: code.render,staticRenderFns: code.staticRenderFns}}

  返回一個ast對象,包括attrs、attrsList、attrsMap、children、plain、tag、type等屬性,如圖:。

  包含了DOM字符串中節點類型、屬性、文本內容,接下來進入優化函數:optimize。

// Line-8648function optimize(root, options) {if (!root) {return}// 緩存靜態標簽isStaticKey = genStaticKeysCached(options.staticKeys || '');isPlatformReservedTag = options.isReservedTag || no;// 標記非靜態節點markStatic$1(root);// 標記靜態節點markStaticRoots(root, false);}

  首先函數會對靜態屬性進行緩存:

// Line-8558function genStaticKeys$1(keys) {return makeMap('type,tag,attrsList,attrsMap,plain,parent,children,attrs' +(keys ? ',' + keys : ''))}

  可以看到,上面的好像全是靜態的屬性。

  

  接下來調用markStatic$1標記非靜態節點:

// Line-8648function markStatic$1(node) {// 判斷是否是靜態節點node.static = isStatic(node);if (node.type === 1) {// 靜態節點不包括slot和template標簽if (!isPlatformReservedTag(node.tag) &&node.tag !== 'slot' &&node.attrsMap['inline-template'] == null) {return}for (var i = 0, l = node.children.length; i < l; i++) {var child = node.children[i];// 遞歸處理子節點markStatic$1(child);// 子節點為false 父節點也是falseif (!child.static) {node.static = false;}}}}

  函數對節點做了三重判斷,首先用isStatic方法判斷類型。

// Line-8621function isStatic(node) {if (node.type === 2) { // expressionreturn false}if (node.type === 3) { // textreturn true}return !!(node.pre || (!node.hasBindings && // no dynamic bindings!node.if && !node.for && // not v-if or v-for or v-else!isBuiltInTag(node.tag) && // not a built-inisPlatformReservedTag(node.tag) && // not a component!isDirectChildOfTemplateFor(node) && // 判斷是否v-for的子節點Object.keys(node).every(isStaticKey) // 遍歷判斷屬性是否靜態 ))}

  排除type為2的表達式和3的文本,然后對屬性進行遍歷,若存在v-的動態屬性,則會出現對應的屬性,注釋已經寫出來了,這里就不做說明了。

  由于本案例只有一個動態文本,所以這里返回的是true。

?

  接著判斷標簽是否是slot或者template,此類動態標簽不屬性靜態節點。

  最后對子節點,即children屬性中的內容進行遞歸處理。

  函數完成后,ast對象會多一個屬性,即static:false。

?

  剩下一個是對靜態節點進行標記:

// Line-8587function markStaticRoots(node, isInFor) {if (node.type === 1) {if (node.static || node.once) {node.staticInFor = isInFor;}// 作為靜態節點 必須保證有子節點并且不為純文本 否則更新消耗較大if (node.static && node.children.length && !(node.children.length === 1 &&node.children[0].type === 3)) {node.staticRoot = true;return} else {node.staticRoot = false;}// 遞歸處理子節點if (node.children) {for (var i = 0, l = node.children.length; i < l; i++) {markStaticRoots(node.children[i], isInFor || !!node.for);}}// 無此屬性if (node.ifConditions) {walkThroughConditionsBlocks(node.ifConditions, isInFor);}}}

  由于本例子節點是純文本,所以staticRoot屬性被標記為false。

?

  經過optimize函數,ast對象被添加了兩個靜態屬性:

?

  

  最后是generate函數:

// Line-8799function generate(ast, options) {// 保存上一個屬性值var prevStaticRenderFns = staticRenderFns;var currentStaticRenderFns = staticRenderFns = [];var prevOnceCount = onceCount;onceCount = 0;currentOptions = options;warn$3 = options.warn || baseWarn;transforms$1 = pluckModuleFunction(options.modules, 'transformCode');dataGenFns = pluckModuleFunction(options.modules, 'genData');platformDirectives$1 = options.directives || {};isPlatformReservedTag$1 = options.isReservedTag || no;// 將ast對象轉換為字符串var code = ast ? genElement(ast) : '_c("div")';staticRenderFns = prevStaticRenderFns;onceCount = prevOnceCount;return {render: ("with(this){return " + code + "}"),staticRenderFns: currentStaticRenderFns}}

  這個函數主要部分是code那一塊,將ast對象轉換成自定義的字符串形式,但是由于本例只有很簡單的屬性和文本,所以摘取分支看一下。

// Line-8823function genElement(el) {if ( /* staticRoot,once,for,if,template,slot */ ) {/* code */} else {// component or elementvar code;if (el.component) {code = genComponent(el.component, el);} else {// 1var data = el.plain ? undefined : genData(el);// 2var children = el.inlineTemplate ? null : genChildren(el, true);code = "_c('" + (el.tag) + "'" + (data ? ("," + data) : '') + (children ? ("," + children) : '') + ")";}// module transformsfor (var i = 0; i < transforms$1.length; i++) {code = transforms$1[i](el, code);}return code}}

  跳過所有屬性的判斷,直接進入最后的分支,在這里對節點與子節點分別做了處理。

  首先看genData函數。

// Line-8937function genData(el) {var data = '{';if ( /* directives,key,ref,refInFor,pre,component */ ) {/* code */}// style,classfor (var i = 0; i < dataGenFns.length; i++) {data += dataGenFns[i](el);}// 進入這個分支if (el.attrs) {data += "attrs:{" + (genProps(el.attrs)) + "},";}if ( /* props,events,nativeEvents,slotTarget,scopedSlots,model,inline-template */ ) {/* code */}data = data.replace(/,$/, '') + '}';// v-bind data wrapif (el.wrapData) {data = el.wrapData(data);}return data}

  可以看到跳過了大多數的判斷,直接進入attrs,調用genProps函數并將之前{name:id,value:app}的對象傳了進去。

// Line-9146function genProps(props) {var res = '';// 將name,value拼接成 "name":"value", 形式的字符串for (var i = 0; i < props.length; i++) {var prop = props[i];res += "\"" + (prop.name) + "\":" + (transformSpecialNewlines(prop.value)) + ",";}// 去掉最后的逗號return res.slice(0, -1)}

  遍歷attrs數組,將鍵值拼接成對應的字符串,本例只有一個id屬性,拼接后返回。

  處理完后調用正則將最后的逗號去掉并加上對應的大括號,最后的wrapData屬性也沒有,所以直接返回data,最終結果如圖所示:

?

  第一步完事后,進行子節點處理:

// Line-8823function genElement(el) {if ( /* code... */ ) {/* code... */} else {var code;/* code... */// 返回節點信息var data = el.plain ? undefined : genData(el);// 子節點var children = el.inlineTemplate ? null : genChildren(el, true);code = "_c('" + (el.tag) + "'" + (data ? ("," + data) : '') + (children ? ("," + children) : '') + ")";// module transformsfor (var i = 0; i < transforms$1.length; i++) {code = transforms$1[i](el, code);}return code}} // Line-8823function genChildren(el, checkSkip) {var children = el.children;if (children.length) {var el$1 = children[0];// 對簡單的v-for做優化if (children.length === 1 &&el$1.for &&el$1.tag !== 'template' &&el$1.tag !== 'slot') {return genElement(el$1)}// 對存在子DOM節點的對象做處理 不存在返回0var normalizationType = checkSkip ? getNormalizationType(children) : 0;return ("[" + (children.map(genNode).join(',')) + "]" + (normalizationType ? ("," + normalizationType) : ''))}}// Line-9107function genNode(node) {if (node.type === 1) {return genElement(node)} else {return genText(node)}}function genText(text) {// 進行包裝return ("_v(" + (text.type === 2 ?text.expression // no need for () because already wrapped in _s() :transformSpecialNewlines(JSON.stringify(text.text))) + ")")}

  調用genChildren后同樣返回一個包裝后的字符串:。

?

  最后,將節點與內容結合,生成一個總的字符串,如圖所示:

  返回到generate函數:

// Line-8799function generate(ast, options) {/* code */var code = ast ? genElement(ast) : '_c("div")';staticRenderFns = prevStaticRenderFns;onceCount = prevOnceCount;return {render: ("with(this){return " + code + "}"),staticRenderFns: currentStaticRenderFns}}

  輸出一個對象,返回到最初的baseCompile函數,除了ast,多出來的對象內容如圖:

  這個對象返回到compileToFunctions函數,目前進度是這樣的:

// Line-9326function compileToFunctions(template, options, vm) {options = options || {};/* new Function檢測 *//* 緩存查詢 */// compilevar compiled = compile(template, options);/* 輸出返回的error和tips */// 將字符串代碼轉化為函數var res = {};var fnGenErrors = [];res.render = makeFunction(compiled.render, fnGenErrors);var l = compiled.staticRenderFns.length;res.staticRenderFns = new Array(l);for (var i = 0; i < l; i++) {res.staticRenderFns[i] = makeFunction(compiled.staticRenderFns[i], fnGenErrors);}/* checkError */return (functionCompileCache[key] = res)}

  返回的compiled如圖所示:

  接下來將render字符串重新轉換為函數,makeFunction方法很簡單,就是使用new Function生成一個函數:

// Line-9275function makeFunction(code, errors) {try {return new Function(code)} catch (err) {errors.push({err: err,code: code});return noop}}

  結果如圖:

  由于res.staticRenderFns是空,所以最后直接把該res緩存進functionCompileCache然后返回。

?

  這個函數完事后,返回到了$mount方法中,很久之前的一個函數,內容如下:

// Line-9553Vue$3.prototype.$mount = function(el,hydrating) {el = el && query(el);/* warning */var options = this.$options;// resolve template/el and convert to render functionif (!options.render) {var template = options.template;if (template) {/* 獲取template */} else if (el) {template = getOuterHTML(el);}if (template) {/* compile start */if ("development" !== 'production' && config.performance && mark) {mark('compile');}var ref = compileToFunctions(template, {shouldDecodeNewlines: shouldDecodeNewlines,delimiters: options.delimiters}, this);var render = ref.render;var staticRenderFns = ref.staticRenderFns;options.render = render;options.staticRenderFns = staticRenderFns;/* compile end */}}return mount.call(this, el, hydrating)};

  調用完compileToFunctions后,返回的對象包含一個render函數,一個staticRenderFns屬性,分別掛載到options參數上,然后再次調用mount方法。

  結束~

  

轉載于:https://www.cnblogs.com/QH-Jimmy/p/6991987.html

總結

以上是生活随笔為你收集整理的.9-Vue源码之AST(5)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 伊人天天干| 91漂亮少妇露脸在线播放 | 日韩av在线免费观看 | 国产精品一区二区在线免费观看 | 污视频免费在线 | 日韩精品三区 | 久久成人综合网 | 中文av一区二区 | 西欧毛片 | 美女午夜影院 | 影音先锋成人网 | 午夜影院在线看 | 国产 欧美 日韩 在线 | 91波多野结衣| 国产三级精品在线 | 一区二区网 | 成年人福利 | 日本亚洲一区 | 亚洲狼人综合网 | 操操网 | 69视频一区二区三区 | av影视网| 香蕉网在线 | av视觉盛宴 | 亚州av成人 | 97av视频| 美丽的姑娘在线观看免费 | 黄色污污网站 | 天天想你免费观看完整版高清电影 | 第一页在线视频 | 伊人激情综合 | 欧美一区二区三区在线视频 | 娇喘顶撞深初h1v1 | 中文字幕乱码亚洲精品一区 | 成人乱人乱一区二区三区 | 91丝袜一区二区三区 | 在线观看av一区 | 美日韩丰满少妇在线观看 | 色播基地 | 1769国产精品视频 | 用舌头去添高潮无码视频 | 日韩欧美一区在线观看 | 成年人黄色录像 | 极度诱惑香港电影完整 | 免费在线观看网址 | 国产探花一区二区 | 日韩欧美国产视频 | 亚洲一级片av | 欧美天天性影院 | 青草视频在线播放 | 性爱免费在线视频 | 偷拍中国夫妇高潮视频 | 亚洲中文无码av在线 | 国产精品久久二区 | 中文字幕第八页 | 在线久久| 68日本xxxxxⅹxxx59 | 玉米地疯狂的吸允她的奶视频 | 亚洲4438| 毛片网在线观看 | 国产成人久久婷婷精品流白浆 | 性欧美一区 | 99er热精品视频 | 久久理论视频 | 久久你懂的 | 美女隐私免费观看 | 在线国产91 | 久久色在线观看 | 久久婷婷网 | 色在线免费视频 | 青青草自拍| 国产黄色自拍视频 | 人人爱人人搞 | 欧美成人激情在线 | 国产色婷婷一区二区三区竹菊影视 | 打屁股疼的撕心裂肺的视频 | 动漫av在线播放 | 中文字幕永久在线播放 | 久久va | 狠狠人妻久久久久久综合麻豆 | 日韩视频在线观看二区 | 成人福利一区二区三区 | 国产亚洲精品女人久久久久久 | h在线免费观看 | 亚洲高清福利 | 日本老小玩hd老少配 | 无码精品a∨在线观看中文 福利片av | 久久久久久999| 高清av在线 | 日韩精品久久久久久久酒店 | 国产精品久久久久久久久动漫 | 人人爱爱人人 | 国产精品伦子伦免费视频 | 亚洲综合激情另类小说区 | 亚洲欧美日韩综合 | 高h av| 免费av地址| 久久黄色大片 | 久久一区国产 |