Vue 源码学习

Vue 源码学习

资料
熟悉设计模式
AST 抽象语法树
htmlParse 解析器
wue 仿Vue实现
Vue.js 源码学习笔记
Virtual DOM patching algorithm based on Snabbdom
逐行学习vue 源码
组件的本质

以下是个人学习vue 源码的先后学习过程:(假设我是小白,按照下面顺序学习会轻松很多,循序渐进)

  1. 学习正则表达式

  2. 学习js 设计模式,重点观察者模式 50行代码的MVVM,感受闭包的艺术

  3. 了解AST 抽象语法树的概念,并通过博文开头的资料 htmlParse解析器 中分析parse 原理

  4. 参看githut 上的开源仿 Vue 实现项目 wue 仿Vue实现Vue 源码注释版(注释版可以放在后面看)

  5. 查看调试vue.js 2.1.3 版本单文件脚本(或其他新版本) https://cdn.bootcss.com/vue/2.1.3/vue.js

  6. 学习 es6 模块化编程,学习 rollup 构建工具,学习 flow 类型检查工具

  7. es6 版本的vue 学习 源码调试方法,对应版本V2.5.9

  8. 待补充~

步骤5 举例

单步调试如下代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <!-- 版本:vue 2.1.3 -->
  <script type="text/javascript" src="./vue.js"></script>
</head>
<body>
  
  <div id="app">
    <div><span v-text="reverse"></span></div>
    <div><span v-text="tip"></span></div>
    <div><bar :age="info.age"></bar></div>
  </div>
  
  <script>
      let bar = {
        name: 'Bar',
        template: '<div><span>name: {{name}}</span><br/><span>age: {{age}}</span></div>',
        props: [ 'age' ],
        created() {
          console.log('child created.')
        },
        data() {
          return {
            name: 11
          }
        }
      }

      var app = new Vue({
        el: "#app",
        components: {
          bar: bar
        },
        created() {
          console.log('created.')
        },
        data() {
          return {
            message: "hello.",
            info: {
              age: 12
            }
          }
        },
        computed: {
          reverse() {
            return this.message.split("").reverse().join("")
          },
          tip() {
            return `${this.message} world.`
          }
        }
      })

      setTimeout(()=>{
        app.info.age = 23
      }, 400)
  </script>
  
</body>
</html>

编译过程中会生成render code 如下:

_h(
   'div',
   {attrs:{"id":"app"}},
   [
    _h(
       'div',
       [
        _h('span',{domProps:{"textContent":_s(reverse)}})]),
        " ",
        _h(
           'div',
           [_h('span',{domProps:{"textContent":_s(tip)}})]
          ),
        " ",
        _h('div',[_h('bar',{attrs:{"age":info.age}})]
      )
   ]
)

其中_h_s 方法分别对应:

// shorthands used in render functions
Vue.prototype._h = createElement;
// toString for mustaches
Vue.prototype._s = _toString;

官网example 代码对应render code示例:render code 示例

大体过程:

  1. render code 的执行,即代码调用 vm._render() , 后生成了包含dom 结构的vnode 实例;
  2. vmpatch 调用会把 vnode 树转为document 的对象并挂在 vm.$el 上,并挂载到根节点上,如示例中的 <div id='app'> 上;
代码案例

示例1
index.html

<body>
  <div id="demo">
    <div v-text="message"></div>
    <span>{{info.age}}</span>
  </div>
  <script src="./app.js"></script>
</body>

app.js

var demo = new Vue({
  el: '#demo',
  data: {
    info: {
      name: {
        firstName: 'Lili'
      }
    }
  },
  computed: {
    message () {
      return 'Hello' + this.info.name.firstName
    }
  },
  created: function () {
    this.init()
  },
  methods: {
    init () {
      setTimeout(() => {
        this.info.age = 88
        delete this.info.name.firstName
        this.$forceUpdate()
      }, 1000)
    }
  }
})

执行结果:

问题:上述示例如果注释掉 this.$forceUpdate() 的结果呢? 自己动手试一下吧


示例2
index.html

<body>
  <div id="demo">
    <ul style="border-bottom: 1px solid plum;">
       <li v-for="item in info.list" :key="item">{{item}}</li>
    </ul>
  </div>
  <script src="./app.js"></script>
</body>

app.js

var demo = new Vue({
  el: '#demo',
  data: {
    info: {
      list: ['app', 'web', 'ios']
    }
  }
})
// 通过数组索引修改数值
demo.info.list[0] = 'apple'

执行结果:

问题1:那我如何修改数组的值呢? (下文回答)

现在将app.js 做了如下调整:

var demo = new Vue({
  el: '#demo',
  data: {
    info: {
      list: ['app', 'web', 'ios']
    }
  },
  created: function () {
    this.init()
  },
  methods: {
    init () {
      this.info.list[0] = 'apple'
    }
  }
})

发现执行结果有效了:

问题2:为什么这样又可以了呢?

现在来揭晓答案:
问题1:原因是Object.defineProperty的局限,set方法在一些场景下不会触发(例如示例)。官方给的解决方法是利用 Vue.set或者vm.$set。可参看官网列表渲染

问题2:原因是init方法是在created生命周期中调用的,此时dom结构还没开始生成。如果放在mounted生命周期中调用则同样不会更新。

(未完,待续)

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值