<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                >[success] # vm._render() ~~~ 1.剛才分析了掛載階段,發現想得到這個虛擬dom就需要,渲染函數vm._render()得到一份最新的VNode節點樹 ,現在就需要看看這個vm._render 是個什么? 2.通過代碼分析,首先在'core\instance\index.js' ,通過方法renderMixin(Vue)聲明注冊了'_render', renderMixin 方法在'core\instance\render.js' ~~~ * renderMixin 源碼內容 ~~~js export function renderMixin (Vue: Class<Component>) { Vue.prototype.$nextTick = function (fn: Function) { return nextTick(fn, this) } /*_render渲染函數,返回一個VNode節點*/ Vue.prototype._render = function (): VNode { const vm: Component = this const { render, staticRenderFns, _parentVnode } = vm.$options if (vm._isMounted) { // clone slot nodes on re-renders /*在重新渲染時會克隆槽位節點 不知道是不是因為Vnode必須必須唯一的原因,網上也沒找到答案,此處存疑。*/ for (const key in vm.$slots) { vm.$slots[key] = cloneVNodes(vm.$slots[key]) } } /*作用域slot*/ vm.$scopedSlots = (_parentVnode && _parentVnode.data.scopedSlots) || emptyObject if (staticRenderFns && !vm._staticTrees) { /*用來存放static節點,已經被渲染的并且不存在v-for中的static節點不需要重新渲染,只需要進行淺拷貝*/ vm._staticTrees = [] } // set parent vnode. this allows render functions to have access // to the data on the placeholder node. vm.$vnode = _parentVnode // render self /*渲染*/ let vnode try { /*調用render函數,返回一個VNode節點*/ vnode = render.call(vm._renderProxy, vm.$createElement) } catch (e) { handleError(e, vm, `render function`) // return error render result, // or previous vnode to prevent render error causing blank component /* istanbul ignore else */ if (process.env.NODE_ENV !== 'production') { vnode = vm.$options.renderError ? vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e) : vm._vnode } else { vnode = vm._vnode } } // return empty vnode in case the render function errored out /*如果VNode節點沒有創建成功則創建一個空節點*/ if (!(vnode instanceof VNode)) { if (process.env.NODE_ENV !== 'production' && Array.isArray(vnode)) { warn( 'Multiple root nodes returned from render function. Render function ' + 'should return a single root node.', vm ) } vnode = createEmptyVNode() } // set parent vnode.parent = _parentVnode return vnode } ~~~ >[info] ## 正式分析 ~~~ 1.這是一個粗略看源碼做了什么的解析文章,因此我不會去分析源碼內部,進過上面的源碼內容,整個核心 的地方在這里 /*調用render函數,返回一個VNode節點*/ vnode = render.call(vm._renderProxy, vm.$createElement) 2.現在有了新的疑問'$createElement'是哪里來的,在回到'initMixin'方法文件對應位置'vue-src\core\instance\init.js' ,里面有初始化render,的方法initRender(vm) 3.其實這里我不太懂,但是感覺領悟到,并不是所有方法都要掛載到構造函數上,讓構造函數變得無限臃腫 有時候可以將這些方法方法實例上 ~~~ ~~~js /*初始化render*/ export function initRender(vm: Component) { vm._vnode = null // the root of the child tree vm._staticTrees = null const parentVnode = vm.$vnode = vm.$options._parentVnode // the placeholder node in parent tree 父樹中的占位符節點 const renderContext = parentVnode && parentVnode.context vm.$slots = resolveSlots(vm.$options._renderChildren, renderContext) vm.$scopedSlots = emptyObject //將createElement fn綁定到此實例 //這樣我們就可以在里面得到正確的呈現上下文。 //args順序:tag、data、children、normalizationType、alwaysNormalize //內部版本由從模板編譯的呈現函數使用 /*將createElement函數綁定到該實例上,該vm存在閉包中,不可修改,vm實例則固定。這樣我們就可以得到正確的上下文渲染*/ vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false) //標準化總是應用于公共版本,用于 //用戶編寫的渲染函數。 /*常規方法被用于公共版本,被用來作為用戶界面的渲染方法*/ vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true) } ~~~ >[danger] ##### 在整個代碼分析前 需要理解一段代碼 [render](https://cn.vuejs.org/v2/api/#render) [官網對render介紹](https://cn.vuejs.org/v2/api/#render) ~~~ 1.我們在vue 使用render 時候一般可能會這么寫 new Vue({ render: function (createElement) { return createElement('h1', this.blogTitle) } }).$mount("#app"); 2.可以看到在'renderMixin' 中我們取出opition中的render,并且利用call 的形式改變指向和傳參,我這不是 細讀的版本所以'vm._renderProxy' 就理解成當前vue實例指向,這里傳入'vm.$createElement' 做參數,這個方法 也說過是在'initRender' 中聲明的 vnode = render.call(vm._renderProxy, vm.$createElement) 3.這么繞寫個簡單的小demo 給解開,其實option 中render參數,是一個回調函數,真正幫助我們解析內容的是 'createElement '這個函數 ~~~ ~~~ const opition = { render: function (createElement) { return createElement('h1', 'www') } } const createElement = (a, b, c) => { console.log(a, b, c) } opition.render.call(this, createElement) 打印結果: h1 www undefined ~~~ >[danger] ##### initRender -- createElement ~~~ 1.如果使用的是模板方式' vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)', 如果是正常的render 函數'vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)' 2.根據上面寫的小demo 也可以知道真正幫我們解析vnode其實是createElement 3.現在分析createElement這個方法,被定義在'\core\vdom\create-element.js' 4.'Array.isArray(data) || isPrimitive(data)' 用來判讀是否傳了參數data,如果沒傳data這個參數 其他參數都往上提一層 5.關于'alwaysNormalize' 這個 參數在初始化render 時候如果用的是'模板方法'就是false 是render 函數就是true 這里在后續_createElement中對'children' 參數處理有講究 ~~~ ~~~ export function createElement ( context: Component, tag: any, data: any, children: any, normalizationType: any, alwaysNormalize: boolean ): VNode { /*兼容不傳data的情況*/ if (Array.isArray(data) || isPrimitive(data)) { normalizationType = children children = data data = undefined } /*如果alwaysNormalize為true,則normalizationType標記為ALWAYS_NORMALIZE*/ if (isTrue(alwaysNormalize)) { normalizationType = ALWAYS_NORMALIZE } /*創建虛擬節點*/ return _createElement(context, tag, data, children, normalizationType) } ~~~ >[danger] ##### _createElement [更多詳細內容參考這里](https://ustbhuangyi.github.io/vue-analysis/v2/data-driven/create-element.html#children-%E7%9A%84%E8%A7%84%E8%8C%83%E5%8C%96) ~~~ 1.上面可以看到對參數進行整理后,會調用'_createElement'方法這個方法做了什么? 2.關于'normalizationType ' 判讀這里做個說明 2.1.simpleNormalizeChildren 方法調用場景是 render 函數是編譯生成的。 2.2.normalizeChildren 方法的調用場景有 2 種,一個場景是 render 函數是用戶手寫的,當 children 只有 一個節點的時候,Vue.js 從接口層面允許用戶把 children 寫成基礎類型用來創建單個簡單的文本節點,這 種情況會調用 createTextVNode 創建一個文本節點的 VNode;另一個場景是當編譯 slot、v-for 的時候會產 生嵌套數組的情況,會調用 normalizeArrayChildren 方法 ~~~ ~~~js /*創建VNode節點*/ export function _createElement ( context: Component, tag?: string | Class<Component> | Function | Object, data?: VNodeData, children?: any, normalizationType?: number ): VNode { /* 如果data未定義(undefined或者null)或者是data的__ob__已經定義(代表已經被observed,上面綁定了Oberver對象), https://cn.vuejs.org/v2/guide/render-function.html#約束 那么創建一個空節點 */ if (isDef(data) && isDef((data: any).__ob__)) { process.env.NODE_ENV !== 'production' && warn( `Avoid using observed data object as vnode data: ${JSON.stringify(data)}\n` + 'Always create fresh vnode data objects in each render!', context ) return createEmptyVNode() } /*如果tag不存在也是創建一個空節點*/ if (!tag) { // in case of component :is set to falsy value return createEmptyVNode() } // support single function children as default scoped slot /*默認默認作用域插槽*/ if (Array.isArray(children) && typeof children[0] === 'function') { data = data || {} data.scopedSlots = { default: children[0] } children.length = 0 } if (normalizationType === ALWAYS_NORMALIZE) { children = normalizeChildren(children) } else if (normalizationType === SIMPLE_NORMALIZE) { children = simpleNormalizeChildren(children) } let vnode, ns if (typeof tag === 'string') { let Ctor /*獲取tag的名字空間*/ ns = config.getTagNamespace(tag) /*判斷是否是保留的標簽*/ if (config.isReservedTag(tag)) { // platform built-in elements /*如果是保留的標簽則創建一個相應節點*/ vnode = new VNode( config.parsePlatformTagName(tag), data, children, undefined, undefined, context ) } else if (isDef(Ctor = resolveAsset(context.$options, 'components', tag))) { // component /*從vm實例的option的components中尋找該tag,存在則就是一個組件,創建相應節點,Ctor為組件的構造類*/ vnode = createComponent(Ctor, data, context, children, tag) } else { // unknown or unlisted namespaced elements // check at runtime because it may get assigned a namespace when its // parent normalizes children /*未知的元素,在運行時檢查,因為父組件可能在序列化子組件的時候分配一個名字空間*/ vnode = new VNode( tag, data, children, undefined, undefined, context ) } } else { // direct component options / constructor /*tag不是字符串的時候則是組件的構造類*/ vnode = createComponent(tag, data, context, children) } if (isDef(vnode)) { /*如果有名字空間,則遞歸所有子節點應用該名字空間*/ if (ns) applyNS(vnode, ns) return vnode } else { /*如果vnode沒有成功創建則創建空節點*/ return createEmptyVNode() } } ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看