最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • vue源码解析-$mount

    正文概述 掘金(老刘大话前端)   2021-02-24   518

    上一篇中,我们一起探讨了new Vue({...})背后发生了什么。那么当我们实例化vue之后,进行dom挂载又发生了什么呢?

    vue源码解析-$mount

    细心的同学会发现:$mount方法在多个文件中被定义,如:

    • src/platform/web/entry-runtime-with-compiler.js
    • src/platform/web/runtime/index.js
    • src/platform/weex/runtime/index.js

    之所以有多个地方,是因为$mount实现是和平台、构建方式都相关的 下面,我们选择compiler版本分析

    一. $mount 主干代码如下:

    Vue.prototype.$mount = function(el?: string | Element, hydrating?: boolean): Component {
      el = el && query(el)
      // query方法,实际上是对el参数做了一个转化,el可能是string 或者 element。如果是string,将返回document.querySelector(el) 
      // ...
      const options = this.$options
    
      if (!options.render) {
        // render函数不存在
        let template = options.template
        
        if (template) {
           // 如果存在template配置项:
           // 1. template可能是"#xx",那么根据id获取element内容
           // 2. 如果template存在nodeType,那么获取template.innerHTML 内容
        }else {
           // 如果template配置项不存在template,但是存在el:
          /*  
           * 例如: new Vue({ 
           *       el: "#app",
          *       ...
           *  })
           *
           */
          // 那么根据el获取对应的element内容
        }
    
        // 经过上面的处理,将获取的template做为参数调用compileToFunctions方法
        // compileToFunctions方法会返回render函数方法,render方法会保存到vm.$options下面
        const { render, staticRenderFns } = compileToFunctions(template, {...})
        options.render = render
      }
      return mount.call(this, el, hydrating)
    }
    

    从主干代码我们可以看出做了以下几件事

    • 由于el参数有两种类型,可能是string 或者 element,调用query方法,统一转化为Element类型
    • 如果没有手写render函数, 那么先获取template内容。再将template做为参数,调用compileToFunctions方法,返回render函数。
    • 最后调用mount.call,这个方法实际上会调用runtime/index.js的mount方法

    注:

    1. vue compiler分别2个版本:一个是构建时版本,即我们使用vue-loader + webpack。另一个版本是:运行时版本,运行的时候,再去compiler解析。我们这里分析的是 运行时
    2. vue最终只认render函数,所以如果我们手动写render函数,那么就直接调用mount.call。反之,vue会将template做为参数,运行时调用compileToFunctions方法,转化为render函数,再去调用mount.call方法。
    3. 如果是构建时版本,vue-loader + webpack,会先将我们本地的代码转化成render函数,运行将直接调用mount.call。生产环境,我们推荐构建时的版本。个人学习推荐运行时版本。
    4. mount.call方法,实际上会调用runtime/index.js下面的$mount方法,而这个方法很简单,将会调用mountComponent方法。

    二. mountComponent 主干代码如下:

    export function mountComponent(vm: Component, el: ?Element, hydrating?: boolean): Component {
      // ...
      // 调用beforeMount生命周期函数
      callHook(vm, 'beforeMount')
      // ...
      // 定义updateComonent方法
      let updateComponent = () => {
          vm._update(vm._render(), hydrating)
      }
      
      // ...
      new Watcher(vm, updateComponent, noop, {
        before () {
          if (vm._isMounted && !vm._isDestroyed) {
            callHook(vm, 'beforeUpdate')
          }
        }
      }, true)
      // ...
      // 调用生命周期函数mounted
      callHook(vm, 'mounted')
    }
    

    Watch类相关代码

    Watch类有许多逻辑,这里我们只看和$mount相关的:

    class Watcher {
        constructor(
            vm: Component,
            expOrFn: string | Function,
            cb: Function,
            options?: ?Object,
            isRenderWatcher?: boolean
        ){
            // ...
            if (typeof expOrFn === 'function') {
              this.getter = expOrFn
            }else {
              // ...
            }
    
            // ...
            this.value = this.lazy ? undefined : this.get()
        }
    
        get() {
          // ...
          value = this.getter.call(vm, vm)
          // ...
          // cleanupDeps方法后面我们会分析,这个在性能优化上比较重要
          return value;
        }
    }
    

    从上面代码,可以看出:

    • 先调用beforeMount钩子函数
    • 将updateComponent方法做为参数,实例化Watch。Watch在这个有2个作用: 1、初始化的时候会执行回调函数 2、当 vm 实例中的监测的数据发生变化的时候执行回调函数 这里,我们先看第1个。 第2个将在数据变化监测章节分析 执行回调后,我们看到vm._update(vm._render(), hydrating)方法,这个方法分2个步骤: (1) 执行render方法,返回最新的 VNode节点树 (2) 调用update方法,实际上进行diff算法比较,完成一次渲染
    • 调用mounted钩子函数

    三. 总结

    1. options上无render函数,对template, el做处理,获取template内容。
    2. 调用compileToFunctions方法,获取render函数,添加到options.render上
    3. 调用mount.call,实际上是调用mountComponent函数
    4. 调用beforeMount钩子
    5. 实例化渲染watcher,执行回调
    6. 根据render函数获取VNode节点树 (其实是一个js对象)
    7. 执行update方法,实际上是patch过程,vue会执行diff算法,完成一次渲染
    8. 调用mounted钩子

    在下面的章节,我们将陆续分析: 响应式,compileToFunctions, 虚拟DOM,以及patch 码字不易,多多关注~?


    起源地下载网 » vue源码解析-$mount

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元