我的源码学习之路(14)--- vue3(1)

122 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 8 天,点击查看活动详情

前言

vue3开始了!!!

思考了下关于vue3 怎么写。我想先从vue3的网上的一些与vue2对比的一些面试题入手。先整理一下2版本和3版本的区别,及开发v3项目时遇到的一些问题。再去整理v3的源码。我觉得有方向的看V3的源码我会更有兴趣看下去(因为我确实纯看源码会烦躁)


下面列一下问题

V2与V3的区别

既然是新版本,肯定是要对比一下的。

区别:

区别v2v3
响应式Object.definePropety()Proxy
APIobject APIComposition API(组合API)
domdiff重构虚拟dom
.........

V3新特性

数据响应式

vue3启用了proxy替代Object.defineProperty

对于Proxy可以理解成:在目标对象之前假设一层拦截,外界访问,必须要先通过这层拦截

操作时是对new Proxy返回的一个新对象进行操作的.

相比较proxy比defineproperty遍历属性的方式效率更高,性能更好

  • 解决了对象、数组更新的检测问题,优化了响应式的监听的性能(V2对于数组的监听有缺陷),
    • 可以监听删除的属性
    • 可以监听数组的索引和length
  • proxy可以直接对整个对象劫持。(v2检测对象属性,需要深层次监听才可以)
    • 可以动态监听新增的属性
  • 响应式是惰性的
    • V2中,响应式是递归遍历对象,以保证这个对象每一层都是响应式的,有很大的性能消耗
    • V3中,proxy不需要初始化的时候遍历所有属性,只有访问的时候再去递归处理。就是按需实现响应式,减少性能消耗。他的处理方式是在getter里面实现递归的

组合式API

V2中的写法,被称作options API(选项式API)

先提一下选项式的缺陷:因为这种方式,特定的代码需要写在特定的位置,代码量一多,导致后续维护或者接手的人的接受度不友好。代码很乱

image.png

image.png

V3中,提出Composition API(组合式API)

  • setup
    • 是v3中新增的一个配置项,值为一个函数。是组合式api写法的入口点
    • setup不能是一个async函数
    • return 中返回的属性跟data合并,返回的方法跟methods方法合并,如若重名,setup为主

写法如下(两种):

<script setup>...</script>
<script>
    setup(props, contex){}|| setup(props, {attrs,slots,emit}){}
</script>
  • ref reactive toRef toRefs

    • ref: 是一个定义基本数据类型的响应式引用.
    • 仅能监听基本类型的变化,不能监听复杂类型的变化(数组,对象)
    • ref的底层原理也是调用了reactive

    const name = ref('vue3') console.log(name.value)

    • reactive:检测复杂数据类型,返回对象的响应式副本。这个必须要传一个对象,不能传基本类型.

    const obj = reactive({name: 'vue3'}) console.log(obj.name)

    • toRefs:将响应式对象转换为普通对象,把对象中的每一个属性,包裹成ref对象(接收一个对象作为参数,遍历对象的所有属性,然后挨个调用toRef执行)
setup(){
    let msg = { name: 'zs', age: 16 }
    let msg3 = toRefs(msg)
    console.log(msg) // { name:ref, age:ref }  ref代指ref对象
    function change3() {
      msg3.name.value = 'zl'
      msg3.age.value = 20
      console.log(msg, msg3) // {name: "zl", age: 20} { name:ref, age:ref }
    }
    change3()
    return { msg3, change3 }
}
 - [toRef](https://www.javascriptc.com/vue3js/api/refs-api.html#toref):可以用来为源响应式对象上的 property 新创建一个 [`ref`](https://www.javascriptc.com/vue3js/api/refs-api.html#ref)。然后可以将 ref 传递出去,从而保持对其源 property 的响应式连接。

     - 用来抽离响应式对象的某一个属性,并把这个属性包裹成ref对象。使其与原对象产生链接
 setup(props, { emit }) {
        const page = toRef(props, 'page')//将props里面的page 转成一个 ref的响应式的值,相当于:const page = ref()这种形式。

        const handleCurrentChange = val => {
            emit('update:page', val) // 这里改变了page 比如从1变成了2,但是视图上没有改变,视图上还是1
            emitChange()
        }

        const emitChange = () => { // 这里触发change之后页面才会跳到第二页,并展示第二页的数据
            emit('change', {
                currentPage: page.value,
                pageSize: size.value,
            })
        }

        return {
            handleCurrentChange,
        }
    },   
  • provide inject
    • provide 、 inject提供依赖注入 ,实现祖孙级组件通信
    • 用法和V2没啥区别
        // 祖先组件
        const msg = ref('red')
        provide('msg', msg)
        
        // 子组件
        setup() {
            const msg = inject('msg')
            return {
              msg
            }
          }
    

V3中获取dom

V2中我们获取dom:

<div ref='title'>标题</div>

console.log(this.$refs.title)

V3中我们获取dom:

<div ref='title'>标题</div>

setup(){
  const refTitle = ref(null)
  console.log(menu_item.value)
  
}

获取dom之后修改样式

const bg = ref(null); 
nextTick(() => { 
    bg.value.style.backgroundImage = `url(${bg})`; //设置背景图片 
});

后记

本文仅作为自己一个阅读记录,具体还是要看大佬们的文章

下一篇:我的源码学习之路(15)--- vue3(2)