Vue的整个实现流程

作者: 泡杯感冒灵 | 来源:发表于2020-08-04 10:40 被阅读0次

第一步,解析模板成render函数

  • with的用法
  • 模板中所有信息都被render函数包含
  • 模板中用到的data中的属性,都变成JS变量
  • 模板中的v-model,v-for,v-on都变成了JS逻辑
  • render函数返回vnode
  //模板
  <div id="app">
    <div>
      <input type="text" v-model="title">
      <button @click="add">add</button>
    </div>
    <div>
      <ul>
        <li v-for="(item,index) in lists" :key="index">{{item}}</li>
      </ul>
    </div>
  </div>

//render函数
with (this) {
  return _c(
    'div',
    {
      attrs: { "id": "app" }
    },
    [
      _c(
        'div',
        [
          _c(
            'input',
            {
              directives: [
                {
                  name: "model",
                  rawName: "v-model",
                  value: (title),
                  expression: "title"
                }],
              attrs: { "type": "text" },
              domProps: { "value": (title) },
              on: {
                "input": function ($event) {
                  if ($event.target.composing) return;
                  title = $event.target.value
                }
              }
            }
          ),
          _v(" "),  // 换行 创建一个空字符串的文本节点
          _c(
            'button',
            {
              on: { "click": add }
            },
            [
              _v("add")
            ]
          )
        ]
      ),
      _v(" "), // 换行 创建一个空字符串的文本节点
      _c(
        'div',
        [_c(
          'ul',
          _l(
            (lists), function (item, index) { return _c('li', { key: index }, [_v(_s(item))]) }
          )
        )
        ]
      )
    ]
  )
}

第二步,响应式开始监听

  • Object.defineProperty
  • 将data属性代理到vm上
// vm是一个vue实例
// var vm = new Vue({
//   el:'#app',
//   data:{
//     name:'lisi',
//     age: 20
//   }
// })

// 我们可以模拟一下,vue是怎么监听name和age的变化的,以及name和age怎么代理到vm实例上的
var vm = {}
var data = {
  name: 'lisi',
  age:20
}

var key, value
for (key in data) {
  // 此时key会命中一个闭包,我们需要一个立即执行函数把每个循环到的key保留下来
  (function (key) {
    Object.defineProperty(vm, key, {
      get: function () {
        console.log('get',data[key])  // 监听
        return data[key]
      },
      set: function (newVal) {
        console.log('set',newVal)    // 监听
        data[key] = newVal
      }
    })
  })(key)
}

第三步,首次渲染,显示页面,且绑定依赖

  • 初次渲染,执行updateComponent,执行vm._render
  • 执行render函数,会访问到data里的数据,也就是访问vm上的数据 (vm.list和vm.title)
  • 会被响应式的get方法监听到
  • 执行updateComponent,会走到vdom的patch方法
  • patch将vnode渲染成DOM,初次渲染完成
vm._update(vnode){
    const prevVnode = vm._vnode
    vm._vnode = vnode
    if(!prevVnode){
        vm.$el = vm.__patch__(vm.$el,vnode)
    }else{
        vm.$el = vm.__patch__(prevVnode,vnode)
    }
}

function updateComponent(){
    // vm._render即上边说的 render函数,会返回一个vnode
    vm._update(vm._render())
}
这里有个问题,为什么要监听get呢?get获取之后,什么都做不了,直接监听set不行吗?比如title被修改了,然后set监听到,直接把页面渲染成最新修改的数据。看原因
  • data中有很多属性,有些被用到,有些可能不被用到。
  • 被用到的(也就是被访问)会触发get,不被用到的不会触发get
  • 未触发get的属性,set的时候我们无需关心。
  • 目的是避免不必要的重新渲染。

比如,data有3个属性,这3个属性中,其中title和list都被模板用了,而aaa没有。如果我们不先监听get,而是直接监听set,那么无论哪个属性被修改了,都会被set监听到,从而引起重新渲染。
也就是说,aaa属性,虽然没有用到,当它改变的时候,也会被set监听到,从而重新执行updateComponent,
updateComponent里也会重新执行一遍patch,执行结果虽然没有什么变化,但是只要执行,就会消耗性能,所以我们要避免不必要的重新渲染
所以,我们先监听get,来判断这个属性是否被模板用到,只有被用到的属性改变了,set监听才会去重新渲染页面。而没有走get的属性,set的时候,无需关心。

data = {
  title:'',
  list:[],
  aaa:''
}

第四步,data属性变化,触发rerender

  • 修改属性,被响应式的set监听到
  • set中执行 updateComponent
  • updateComponent重新执行 vm._render
  • 生成的vnode和prevnode,通过patch进行对比
  • 渲染到html中
 var data = {
      title:'',
      lists:[]
    }
    var vm = new Vue({
        el:"#app",
        data:data,
        methods:{
            add:function(){
                if(!this.title){
                    return 
                }
                this.lists.push(this.title)
                this.title = ''
            }
        }
    })


var key, value
for (key in data) {
  // 此时key会命中一个闭包,我们需要一个立即执行函数把每个循环到的key保留下来
  (function (key) {
    Object.defineProperty(vm, key, {
      get: function () {
        console.log('get',data[key])  // 监听
        return data[key]
      },
      set: function (newVal) {
        console.log('set',newVal)    // 监听
        data[key] = newVal
      }
    })
  })(key)
}

相关文章

  • Vue的整个实现流程

    第一步,解析模板成render函数 with的用法 模板中所有信息都被render函数包含 模板中用到的data中...

  • 最近阅读vue源码的一些理解

    vue的整个实现流程 大体的执行方法如下: new Vue init (合并配置,初始化生命周期,初始化事件中心,...

  • 如何才可以颠覆传统餐饮

    APP的实现整个全部的流程 对于传统的餐饮行业的颠覆和革新 1流程化 APP的实现整个全部的流程,支付入口接入,会...

  • Vue实践与总结——组件与数据

    Vue实现组件化流程 Vue提供了一套构建组件的API,用于声明和实现 根组件,可复用组件 Vue库提供了名为Vu...

  • vue实现机制

    本文先对比一下jQuery和Vue的区别,再讲述Vue的MVVM模型,接着讲解Vue的实现流程。 一、jQuery...

  • Vue页面预览PDF文件

    vue-pdf,可实现在线预览 PDF 格式的文档,流程: 在搭建好的 Vue 项目中,引入 Vue-pdf np...

  • vuex

    官方推荐的数据框架:在vue的开发中 vue实现视图层的开发,vuex来实现数据层,实现数据共享 vuex是整个虚...

  • vue中渲染流程分析、归纳及总结

    在零星碎片地学了vue中渲染流程的一些知识后,有必要对vue整个渲染流程做一次梳理,确保知识的连贯性。vue中的渲...

  • Vue 实战课程

    Vue 实战课程需具备知识点: 要实现的功能 项目开发流程:

  • 一个System Service实现流程

    一个System Service实现流程 从上面的分析,我们可以总结出Vibrator服务的整个实现流程: 1、定...

网友评论

    本文标题:Vue的整个实现流程

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