美文网首页
vue实例挂载----渲染到页面

vue实例挂载----渲染到页面

作者: 八月飞花 | 来源:发表于2020-04-14 21:14 被阅读0次

    vue实例如何挂载----执行$mount到底做了什么

    这个函数被定义在  src\platforms\web\entry-runtime-with-compiler.js文件下
    

    函数内部逻辑

      1判断el是否存在,el参数可以是字符串,或者是一个element
      2.调用util/index.js,query函数
        判断是不是字符串,如果是,就通过选择器获取dom对象,
        如果是dom对象,就直接返回
      3.判断el是不是htm或者body标签,如果是,就报错
      4.判断options中有没有render方法 
         如果没有就判断有没有template属性
           如果有,就判断template是不是字符串
            判断是不是以 # 开头
              如果是,就通过idToTemplate获取这个元素的html字符串
        5.判断模板字符串是不是为空
             如果不为空,就开始编译
        最终执行  mount函数,这个函数对el进行一次判断,执行mountComponent函数
        这个mountComponent函数就是将DOM挂载到node上
          这个方法实现挂载主要是vm.rander方法
      返回vm实例对象
    

    函数源码

    Vue.prototype.$mount = function (
      el?: string | Element,
      hydrating?: boolean
    ): Component {
      el = el && query(el)
    
      /* istanbul ignore if */
      if (el === document.body || el === document.documentElement) {
        process.env.NODE_ENV !== 'production' && warn(
          `Do not mount Vue to <html> or <body> - mount to normal elements instead.`
        )
        return this
      }
    
      const options = this.$options
      // resolve template/el and convert to render function
      if (!options.render) {
        let template = options.template
        if (template) {
          if (typeof template === 'string') {
            if (template.charAt(0) === '#') {
              //获取选择器对应的html字符串
              template = idToTemplate(template)
              /* istanbul ignore if */
              if (process.env.NODE_ENV !== 'production' && !template) {
                warn(
                  `Template element not found or is empty: ${options.template}`,
                  this
                )
              }
            }
          } else if (template.nodeType) {
            template = template.innerHTML
          } else {
            if (process.env.NODE_ENV !== 'production') {
              warn('invalid template option:' + template, this)
            }
            return this
          }
        } else if (el) {
          template = getOuterHTML(el)
        }
        if (template) {
          /* istanbul ignore if */
          if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
            mark('compile')
          }
    
          const { render, staticRenderFns } = compileToFunctions(template, {
            outputSourceRange: process.env.NODE_ENV !== 'production',
            shouldDecodeNewlines,
            shouldDecodeNewlinesForHref,
            delimiters: options.delimiters,
            comments: options.comments
          }, this)
          options.render = render
          options.staticRenderFns = staticRenderFns
    
          /* istanbul ignore if */
          if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
            mark('compile end')
            measure(`vue ${this._name} compile`, 'compile', 'compile end')
          }
        }
      }
      return mount.call(this, el, hydrating)
    }
    

    mountComponent函数

    首先将el缓存到vm.$el上
    判断vm.$options有没有传入render函数
      如果没有,就创建一个空的vnode
    最终生成一个updataComponent函数,这个函数内部执行了
      vm._update(vm._render(),hydrating)//vnode,渲染相关参数
      
      调用 new Watcher(vm实例,updataComponent函数,noop空)
      这个函数是渲染Watcher,是一个观察者模式
    

    mountComponent函数源码

    
    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)
        }
      }
      //渲染watcher,者就是一个观察者模式
      // 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
    }
    

    相关文章

      网友评论

          本文标题:vue实例挂载----渲染到页面

          本文链接:https://www.haomeiwen.com/subject/mgsxvhtx.html