<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        詳解vue掛載到dom上會發生什么

        來源:懂視網 責編:小采 時間:2020-11-27 22:01:47
        文檔

        詳解vue掛載到dom上會發生什么

        詳解vue掛載到dom上會發生什么:vue 掛載到dom 元素后發生了什么 前一篇文章分析了new vue() 初始化時所執行的操作,主要包括調用vue._init 執行一系列的初始化,包括生命周期,事件系統,beforeCreate和Created hook,在在這里發生,重點分析了 initState,即對我們常用到的da
        推薦度:
        導讀詳解vue掛載到dom上會發生什么:vue 掛載到dom 元素后發生了什么 前一篇文章分析了new vue() 初始化時所執行的操作,主要包括調用vue._init 執行一系列的初始化,包括生命周期,事件系統,beforeCreate和Created hook,在在這里發生,重點分析了 initState,即對我們常用到的da

        vue 掛載到dom 元素后發生了什么

        前一篇文章分析了new vue() 初始化時所執行的操作,主要包括調用vue._init 執行一系列的初始化,包括生命周期,事件系統,beforeCreate和Created hook,在在這里發生,重點分析了 initState,即對我們常用到的data props computed 等等進行的初始化,最后,執行$mount 對dom進行了掛載,本篇文章將對掛載后所發生的事情進行進一步闡述,

        Vue.prototype.$mount = function (
         el?: string | Element,
         hydrating?: boolean
        ): Component {
         el = el && inBrowser ? query(el) : undefined
         return mountComponent(this, el, hydrating)
        }

        mount 的代碼很簡單,直接執行了moutComponent方法,

        export function mountComponent (
         vm: Component,
         el: ?Element,
         hydrating?: boolean
        ): Component {
         vm.$el = el
         if (!vm.$options.render) {
         vm.$options.render = createEmptyVNode
         if (process.env.NODE_ENV !== 'production') {
         /* istanbul ignore if */
         if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') ||
         vm.$options.el || el) {
         warn(
         'You are using the runtime-only build of Vue where the template ' +
         'compiler is not available. Either pre-compile the templates into ' +
         'render functions, or use the compiler-included build.',
         vm
         )
         } else {
         warn(
         'Failed to mount component: template or render function not defined.',
         vm
         )
         }
         }
         }
         callHook(vm, 'beforeMount')
        
         let updateComponent
         /* istanbul ignore if */
         if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
         updateComponent = () => {
         const name = vm._name
         const id = vm._uid
         const startTag = `vue-perf-start:${id}`
         const endTag = `vue-perf-end:${id}`
        
         mark(startTag)
         const vnode = vm._render()
         mark(endTag)
         measure(`vue ${name} render`, startTag, endTag)
        
         mark(startTag)
         vm._update(vnode, hydrating)
         mark(endTag)
         measure(`vue ${name} patch`, startTag, endTag)
         }
         } else {
         updateComponent = () => {
         vm._update(vm._render(), hydrating)
         }
         }
        
         // we set this to vm._watcher inside the watcher's constructor
         // since the watcher's initial patch may call $forceUpdate (e.g. inside child
         // component's mounted hook), which relies on vm._watcher being already defined
         new Watcher(vm, updateComponent, noop, {
         before () {
         if (vm._isMounted && !vm._isDestroyed) {
         callHook(vm, 'beforeUpdate')
         }
         }
         }, true /* isRenderWatcher */)
         hydrating = false
        
         // manually mounted instance, call mounted on self
         // mounted is called for render-created child components in its inserted hook
         if (vm.$vnode == null) {
         vm._isMounted = true
         callHook(vm, 'mounted')
         }
         return vm
        }
        
        

        moutComponent 這里判斷了render函數,正常開發過程中,對于dom的寫法有很多種,可以直接寫templete,也可以寫render函數,也可以直接把dom寫在掛載元素里面,但是在編譯階段(通常是通過webpack執行的),統統會把這些寫法都編譯成render函數,所以,最后執行的都是render函數,判斷完render可以看到,beforeMount hook在這里執行,最后執行了new Watcher() 我們進入new Watcher

        export default class Watcher {
         vm: Component;
         expression: string;
         cb: Function;
         id: number;
         deep: boolean;
         user: boolean;
         lazy: boolean;
         sync: boolean;
         dirty: boolean;
         active: boolean;
         deps: Array<Dep>;
         newDeps: Array<Dep>;
         depIds: SimpleSet;
         newDepIds: SimpleSet;
         before: ?Function;
         getter: Function;
         value: any;
        
         constructor (
         vm: Component,
         expOrFn: string | Function,
         cb: Function,
         options?: ?Object,
         isRenderWatcher?: boolean
         ) {
         this.vm = vm
         if (isRenderWatcher) {
         vm._watcher = this
         }
         vm._watchers.push(this)
         // options
         if (options) {
         this.deep = !!options.deep
         this.user = !!options.user
         this.lazy = !!options.lazy
         this.sync = !!options.sync
         this.before = options.before
         } else {
         this.deep = this.user = this.lazy = this.sync = false
         }
         this.cb = cb
         this.id = ++uid // uid for batching
         this.active = true
         this.dirty = this.lazy // for lazy watchers
         this.deps = []
         this.newDeps = []
         this.depIds = new Set()
         this.newDepIds = new Set()
         this.expression = process.env.NODE_ENV !== 'production'
         ? expOrFn.toString()
         : ''
         // parse expression for getter
         if (typeof expOrFn === 'function') {
         this.getter = expOrFn
         } else {
         this.getter = parsePath(expOrFn)
         if (!this.getter) {
         this.getter = noop
         process.env.NODE_ENV !== 'production' && warn(
         `Failed watching path: "${expOrFn}" ` +
         'Watcher only accepts simple dot-delimited paths. ' +
         'For full control, use a function instead.',
         vm
         )
         }
         }
         this.value = this.lazy
         ? undefined
         : this.get()
         }
        
        

        其他方法暫時不提,可以看到,但是我們也能大致猜到他在做些什么,這里只是截取了部分Watcher的構造方法,,重點是最后執行了this.get 而this.get則執行了this.getter,最后等于執行了Watcher構造方法中傳入的第二個參數,也就是上一環節moutComponent中的updateComponent方法,updateComponent方法也是在moutComponent方法中定義

        updateComponent = () => {
         vm._update(vm._render(), hydrating)
         }
        

        這里先是執行編譯而成的render方法,然后作為參數傳到_update方法中執行,render方法執行后返回一個vnode 即Virtual dom,然后將這個Virtual dom作為參數傳到update方法中,這里我們先介紹一下Virtual dom 然后在介紹最后執行掛載的update方法,

        render函數

        Vue.prototype._render = function (): VNode {
         const vm: Component = this
         const { render, _parentVnode } = vm.$options
        
         if (_parentVnode) {
         vm.$scopedSlots = normalizeScopedSlots(
         _parentVnode.data.scopedSlots,
         vm.$slots
         )
         }
        
         // 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 {
         vnode = render.call(vm._renderProxy, vm.$createElement)
         } catch (e) {
         handleError(e, vm, `render`)
         // return error render result,
         // or previous vnode to prevent render error causing blank component
         /* istanbul ignore else */
         if (process.env.NODE_ENV !== 'production' && vm.$options.renderError) {
         try {
         vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e)
         } catch (e) {
         handleError(e, vm, `renderError`)
         vnode = vm._vnode
         }
         } else {
         vnode = vm._vnode
         }
         }
         // if the returned array contains only a single node, allow it
         if (Array.isArray(vnode) && vnode.length === 1) {
         vnode = vnode[0]
         }
         // return empty vnode in case the render function errored out
         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
         }
        
        

        根據flow 的類型定義,我們可以看到,_render函數最后返回一個vnode,_render主要代碼 在第一個try catch中,vnode = render.call(vm._renderProxy,vm.$CREATRElement) ,第一個參數為當前上下文this 其實就是vm本身,第二個參數是實際執行的方法,當我們在手寫render函數時,比如這樣

         render:h=>{
         return h(
         "div",
         123
         )
         }
        

        這時候我們使用的h 就是傳入的$createElement方法,然后我們來看一下createElement方法,在看creatElement之前,我們先簡單介紹一下vdom,因為createElement返回的就是一個vdom,vdom其實就是真實dom對象的一個映射,主要包含標簽名字tag 和在它下面的標簽 children 還有一些屬性的定義等等,當我們在進行dom改變時首先是數據的改變,數據的改變映射到 vdom中,然后改變vdom,改變vdom是對js數據層面的改變所以說代價很小,在這一過程中我們還可以進行針對性的優化,復用等,最后把優化后的改變部分通過dom操作操作到真實的dom上去,另外,通過vdom這層的定義我們不僅僅可以把vdom映射到web文檔流上,甚至可以映射到app端的文檔流,桌面應用的文檔流多種,這里引用一下vue js作者對vdom的評價:Virtual DOM真正價值從來不是性能,而是它 1: 為函數式的ui編程方式打開了大門,2 :可以渲染到dom以外的backend 比如 ReactNative 。

        下面我們來繼續介紹creatElement

        export function _createElement (
         context: Component,
         tag?: string | Class<Component> | Function | Object,
         data?: VNodeData,
         children?: any,
         normalizationType?: number
        ): VNode | Array<VNode> {
         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()
         }
         // object syntax in v-bind
         if (isDef(data) && isDef(data.is)) {
         tag = data.is
         }
         if (!tag) {
         // in case of component :is set to falsy value
         return createEmptyVNode()
         }
         // warn against non-primitive key
         if (process.env.NODE_ENV !== 'production' &&
         isDef(data) && isDef(data.key) && !isPrimitive(data.key)
         ) {
         if (!__WEEX__ || !('@binding' in data.key)) {
         warn(
         'Avoid using non-primitive value as key, ' +
         'use string/number value instead.',
         context
         )
         }
         }
         // 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
         ns = (context.$vnode && context.$vnode.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 ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
         // component
         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
         vnode = createComponent(tag, data, context, children)
         }
         if (Array.isArray(vnode)) {
         return vnode
         } else if (isDef(vnode)) {
         if (isDef(ns)) applyNS(vnode, ns)
         if (isDef(data)) registerDeepBindings(data)
         return vnode
         } else {
         return createEmptyVNode()
         }
        }
        

        creatElement 最后結果時返回一個new VNode,并將craete時傳入的參數,經過處理,傳到VNode的初始化中,這里有幾種情況,createEmptyVNode,沒有傳參數,或參數錯誤,會返回一個空的vnode,如果tag 時瀏覽器的標簽如div h3 p等,會返回一個保留VNode,等等,最后,回到上面,vnode 創建完畢,_render會返回這個vnode,最后走回vm._update(),update 中,便是將vnode 通過dom操作插入到真正的文檔流中,下一節我們聊聊update

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        詳解vue掛載到dom上會發生什么

        詳解vue掛載到dom上會發生什么:vue 掛載到dom 元素后發生了什么 前一篇文章分析了new vue() 初始化時所執行的操作,主要包括調用vue._init 執行一系列的初始化,包括生命周期,事件系統,beforeCreate和Created hook,在在這里發生,重點分析了 initState,即對我們常用到的da
        推薦度:
        標簽: VUE 發生 什么
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 99国产精品免费观看视频| 国产精品1024在线永久免费| 亚洲AV无码一区二区三区国产| 亚洲婷婷第一狠人综合精品| 国内精自视频品线六区免费| 免费a级毛片无码av| 在线观看免费亚洲| 亚洲国产精品无码中文lv| 青柠影视在线观看免费高清| 亚洲精品色午夜无码专区日韩| 一本色道久久综合亚洲精品蜜桃冫 | 羞羞网站在线免费观看| 免费jjzz在线播放国产| 草久免费在线观看网站| 最新国产AV无码专区亚洲| 亚洲乱码国产乱码精华| 四虎影视永久免费观看地址| 亚洲国产精品人久久电影| 人妻视频一区二区三区免费| 亚洲AV噜噜一区二区三区| 国产99视频精品免费观看7| 亚洲中文无码卡通动漫野外| 国产一区二区视频免费| 亚洲五月午夜免费在线视频| 亚洲电影中文字幕| 国产精品久久久久久久久久免费 | 国产精品久久亚洲一区二区| 亚洲第一永久AV网站久久精品男人的天堂AV| 美女视频黄频a免费| 亚洲va无码手机在线电影| 国产免费伦精品一区二区三区| 国产男女猛烈无遮挡免费网站 | 蜜桃传媒一区二区亚洲AV | 亚洲精品高清国产麻豆专区| 成全视频免费高清| 中文字幕亚洲综合久久综合| 亚洲а∨天堂久久精品| 久久久久久毛片免费播放| 亚洲av无码成人精品区一本二本 | 69堂人成无码免费视频果冻传媒| 亚洲高清国产拍精品熟女|