乐趣区

关于vue.js:手写-Vue-系列-之-从-Vue1-升级到-Vue2

当学习成为了习惯,常识也就变成了常识。 感激各位的 关注 点赞 珍藏 评论

新视频和文章会第一工夫在微信公众号发送,欢送关注:李永宁 lyn

文章已收录到 github 仓库 liyongning/blog,欢送 Watch 和 Star。

前言

上一篇文章 手写 Vue 系列 之 Vue1.x 带大家从零开始实现了 Vue1 的外围原理,包含如下性能:

  • 数据响应式拦挡

    • 一般对象
    • 数组
  • 数据响应式更新

    • 依赖收集

      • Dep
      • Watcher
    • 编译器

      • 文本节点
      • v-on:click
      • v-bind
      • v-model

在最初也具体解说了 Vue1 的诞生以及存在的问题:Vue1.x 在中小型零碎中性能会很好,定向更新 DOM 节点,然而大型零碎因为 Watcher 太多,导致资源占用过多,性能降落。于是 Vue2 中通过引入 VNode 和 Diff 的来解决这个问题,

所以接下来的系列内容就是降级上一篇文章编写的 lyn-vue 框架,将它从 Vue1 降级到 Vue2。所以倡议整个系列大家按程序去浏览学习,如若强行浏览,可能会产生云里雾里的感觉,事倍功半。

另外欢送 关注 以防迷路,同时系列文章都会收录到 精通 Vue 技术栈的源码原理 专栏,也欢送关注该专栏。

指标

降级后的框架须要将如下示例代码跑起来

示例

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Lyn Vue2.0</title>
</head>

<body>
  <div id="app">
    <h3> 数据响应式更新 原理 </h3>
    <div>{{t}}</div>
    <div>{{t1}}</div>
    <div>{{arr}}</div>
    <h3>methods + computed + 异步更新队列 原理 </h3>
    <div>
      <p>{{counter}}</p>
      <div>{{doubleCounter}}</div>
      <div>{{doubleCounter}}</div>
      <div>{{doubleCounter}}</div>
      <button v-on:click="handleAdd"> Add </button>
      <button v-on:click="handleMinus"> Minus </button>
    </div>
    <h3>v-bind</h3>
    <span v-bind:title="title"> 右键审查元素查看我的 title 属性 </span>
    <h3>v-model 原理 </h3>
    <div>
      <input type="text" v-model="inputVal" />
      <div>{{inputVal}}</div>
    </div>
    <div>
      <input type="checkbox" v-model="isChecked" />
      <div>{{isChecked}}</div>
    </div>
    <div>
      <select v-model="selectValue">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
      </select>
      <div>{{selectValue}}</div>
    </div>
    <h3> 组件 原理 </h3>
    <comp></comp>
    <h3> 插槽 原理 </h3>
    <scope-slot></scope-slot>
    <scope-slot>
      <template v-slot:default="scopeSlot">
        <div>{{scopeSlot}}</div>
      </template>
    </scope-slot>
  </div>
  <script type="module">
    import Vue from './src/index.js'
    const ins = new Vue({
      el: '#app',
      data() {
        return {
          // 原始值和对象的响应式原理
          t: 't value',
          t1: {tt1: 'tt1 value'},
          // 数组的响应式原理
          arr: [1, 2, 3],
          // 响应式更新
          counter: 0,
          // v-bind
          title: "I am title",
          // v-model
          inputVal: 'test',
          isChecked: true,
          selectValue: 2,
        }
      },
      // methods + 事件 + 数据响应式更新 原理
      methods: {handleAdd() {this.counter++},
        handleMinus() {this.counter--}
      },
      // computed + 异步更新队列 的原理
      computed: {doubleCounter() {console.log('evalute doubleCounter')
          return this.counter * 2
        }
      },
      // 组件
      components: {
        // 子组件
        'comp': {
          template: `
            <div>
              <p>{{compCounter}}</p>
              <p>{{doubleCompCounter}}</p>
              <p>{{doubleCompCounter}}</p>
              <p>{{doubleCompCounter}}</p>
              <button v-on:click="handleCompAdd"> comp add </button>
              <button v-on:click="handleCompMinus"> comp minus </button>
            </div>`,
          data() {
            return {compCounter: 0}
          },
          methods: {handleCompAdd() {this.compCounter++},
            handleCompMinus() {this.compCounter--}
          },
          computed: {doubleCompCounter() {console.log('evalute doubleCompCounter')
              return this.compCounter * 2
            }
          }
        },
        // 插槽
        'scope-slot': {
          template: `
            <div>
              <slot name="default" v-bind:slotKey="slotKey">{{slotKey}}</slot>
            </div>
          `,
          data() {
            return {slotKey: 'scope slot content'}
          }
        }
      }
    })
    // 数据响应式拦挡
    setTimeout(() => {console.log('********** 属性值为原始值时的 getter、setter ************')
      console.log(ins.t)
      ins.t = 'change t value'
      console.log(ins.t)
    }, 1000)

    setTimeout(() => {console.log('********** 属性的新值为对象的状况 ************')
      ins.t = {tt: 'tt value'}
      console.log(ins.t.tt)
    }, 2000)

    setTimeout(() => {console.log('********** 验证对深层属性的 getter、setter 拦挡 ************')
      ins.t1.tt1 = 'change tt1 value'
      console.log(ins.t1.tt1)
    }, 3000)

    setTimeout(() => {console.log('********** 将值为对象的属性更新为原始值 ************')
      console.log(ins.t1)
      ins.t1 = 't1 value'
      console.log(ins.t1)
    }, 4000)

    setTimeout(() => {console.log('********** 数组操作方法的拦挡 ************')
      console.log(ins.arr)
      ins.arr.push(4)
      console.log(ins.arr)
    }, 5000)
  </script>
</body>

</html>

知识点

示例代码波及的知识点包含:

  • 基于模版解析的编译器

    • 解析模版失去 AST
    • 基于 AST 生成渲染函数
    • render helper

      • _c,创立指定标签的 VNode
      • _v,创立文本节点的 VNode
      • _t,创立插槽节点的 VNode
    • VNode
  • patch

    • 原生标签和组件的初始渲染

      • v-model
      • v-bind
      • v-on
    • diff
  • 插槽原理
  • computed
  • 异步更新队列

成果

示例代码最终的运行成果如下:

动图地址:https://gitee.com/liyongning/…

阐明

该框架只为解说 Vue 的外围原理,没有什么健壮性可言,说不定你换个示例代码可能就会报错、跑不起来,然而用来学习是齐全足够了,基本上把 Vue 的外围原理(知识点)都实现了一遍。

所以接下来就开始正式的学习之旅吧,加油!!

链接

  • 配套视频,微信公众号回复:” 精通 Vue 技术栈源码原理视频版 ” 获取
  • 精通 Vue 技术栈源码原理 专栏
  • github 仓库 liyongning/Vue 欢送 Star
  • github 仓库 liyongning/Lyn-Vue-DOM 欢送 Star
  • github 仓库 liyongning/Lyn-Vue-Template 欢送 Star

感激各位的:关注 点赞 珍藏 评论,咱们下期见。


当学习成为了习惯,常识也就变成了常识。 感激各位的 关注 点赞 珍藏 评论

新视频和文章会第一工夫在微信公众号发送,欢送关注:李永宁 lyn

文章已收录到 github 仓库 liyongning/blog,欢送 Watch 和 Star。

退出移动版