最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Vue 3.0 中的响应式是如何实现的?

    正文概述 掘金(勾崽)   2021-01-26   486

    在上篇《当面试官问:为什么 Vue3.0 要重写响应式系统?》中,我们梳理了响应式原理的相关内容。本篇,来看看源码。

    Vue2 源码解读

    首先找到响应式代码的处理位置:

    Vue 3.0 中的响应式是如何实现的?

    看完Vue2.x 响应式的代码,我们再回过头来思考最开始的问题,为什么 Vue3.0 要重写响应式系统?

    为什么重写?如果之前好好的,重写就没有意义。

    那之前存在什么问题,换句话问就是 defineProperty 有什么问题?

    Object.defineProperty 的问题

    其实, defineProperty 的问题,在 Vue2.x 的手册中已经说过了。

    “哎,很多人就是不看文档啊”

    下面分别使用 Vue2 和 Vue3 实现了一个小功能,代码一模一样,功能当然也一样,但是,在 Vue2 中就会有 Bug,而运行在 vue3 中的,则没有任何问题。

    Vue2:

    <template>
      <div class="about">
        <h1>This is an about page</h1>
        <p v-for="(v, k) in users">
          {{ v.names }}
        </p>
        <button @click="changes">更新</button>
      </div>
    </template>​
    
    <script>
    export default {
      data() {
        return {
          users: [
            { id: 1, names: "路飞-v2" },
            { id: 2, names: "鸣人-v2" },
          ],
        };
      },​
    
      methods: {
        changes() {
          // this.users[0] = {id:'0',names:'liuneng'}
          // this.users[1].names = 'lnsdsdfg'
          this.users[1] = { id: "1", names: "刘能-v2" };
        },
      },
    };
    </script>
    
    ​<style lang="stylus" scoped></style>
    

    Vue3:

    <template>
      <div class="about">
        <h1>This is an about page</h1>
        <p v-for="(v, k) in users">
          {{ v.names }}
        </p>​
    
        <button @click="changes">更新</button>
      </div>
    </template>​
    
    <script>
    export default {
      data() {
        return {
          users: [
            { id: 1, names: "路飞-v3" },
            { id: 2, names: "鸣人-v3" },
          ],
        };
      },​
    
      methods: {
        changes() {
          // this.users[0] = {id:'0',names:'liuneng'}
          // this.users[1].names = 'lnsdsdfg'
          this.users[1] = { id: "1", names: "刘能-v3" };
        },
      },
    };
    </script>
    

    其核心点在于 defineProperty 不能很好的实现对数组下标的监控,而在 Vue2 的实现代码中,没有更好的方案对此进行改善,尤大索性直接放弃了实现。

    关于这个问题,尤大也在 github 做过回应,截个图给大家看看。

    Vue 3.0 中的响应式是如何实现的?

    那么,Vue 目前还没有解决的问题,Vue3 中显然是已经解决了。

    问题是,Vue3 是如何解决的呢?

    前面在 Vue3 的代码中我们使用的是传统的 Options Api 来实现数据响应式,而在 Vue3 中全新的 Composition Api 也实现了响应式系统。

    我们先来感受一下 Composition Api 的基础用法.

    Composition API 的响应式系统

    ref 响应式

    <template>
      <!-- 不需要.value -->
      <button @click="addNu"> Composition API: {{nu}}</button>
    </template>
    
    ​<script>
    // 引入 ref
    import {ref} from "vue"
    export default {
      setup() {
        // 定义 ref 响应式数据
        const nu = ref(1);
        // 定义函数
        function addNu(){
          nu.value++;
        }
    
        // 将数据和方法返回,即可在模板中直接使用
        return {
          nu,
          addNu
        };
      },
    };
    </script>
    

    reactive 响应式

    <template>
      <!-- 不需要.value --
      <button @click="addNu"> Composition API: {{nu}}</button>
      <!-- reactive 响应式数据 -->
      <h2>{{revData.name}}</h2>
      <h3 @click="ageAdd">年龄:{{revData.age}}</h3>
      <p v-for="(v,k) in revData.skill"> {{v}} </p> 
    </template>​
    
    <script>
    // 引入 ref
    import {reactive, ref} from "vue"
    export default {
      setup() {
        // 定义 ref 响应式数据
        const nu = ref(1);
    ​    // reactive 响应式数据
        const revData = reactive({
          name: '路飞',
          age: 22,
          skill:['橡胶机关枪','吃鸡腿'],
        })​
    
        function ageAdd(){
          revData.age++
        }​
    
        // 定义函数
        function addNu(){
          nu.value++;
        }​
    
        // 将数据和方法返回,即可在模板中直接使用
        return {
          nu,
          addNu,
          revData,
          ageAdd
        };
      },
    };
    </script>
    

    Vue3 中的响应式是如何实现的呢?

    关键点在于 Proxy 函数。

    Proxy 实现原理

    使用 Proxy 实现的响应式代码,要比使用 defineProperty 的代码简单得多。

    因为 Proxy 天然地能够对整个对象做监听,而不需要对数据行遍历后做监听,同时也就解决了数组下标的问题。

    我们来一段模拟代码看一下:

    <div id="app">
        hello
      </div>
      <script>
        // 模拟 Vue 中的 data 选项
        let data = {
          msg: 'hello',
          count: 0
        }​
    
        // 模拟 Vue 实例
        const vm = new Proxy(data, {
          // 执行代理行为的函数
          // 当访问 vm 的成员会执行
          get (target, key) {
            console.log('get, key: ', key, target[key])
            return target[key]
          },
          // 当设置 vm 的成员会执行
          set (target, key, newValue) {
            console.log('set, key: ', key, newValue)
            if (target[key] === newValue) {
              return
            }
            target[key] = newValue
            document.querySelector('#app').textContent = target[key]
          }
        })
    
    ​    // 测试
        vm.msg = 'Hello World'
        console.log(vm.msg)
    </script>
    

    好了,如果面试官再问你“为什么 Vue3.0 要重写响应式系统”,你该知道怎么回答了叭(●'◡'●)。


    起源地下载网 » Vue 3.0 中的响应式是如何实现的?

    常见问题FAQ

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

    发表评论

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

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

    联系作者

    请选择支付方式

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