初识Vue3,带你认识Vue2和Vue3的区别(二)

818 阅读5分钟

Vue3新操作

computed:基本和Vue2没太大改变

  1. computed不再是对象,而是一个函数,需要导入才能用
  2. 可以直接添加为reactive生成的对象中
import {reactive,computed} from 'vue'
setup(props,context) {
    let person = reactive({
      firstName:'连',
      secondName:'颜少',
    })
    // 只读的写法,如果修改则会警告
    person.fullName = computed( () => {
      return person.firstName + person.secondName
    })
    
    // 完整写法
    person.fullName = computed({
        get: function() {
            return person.firstName + person.secondName;
        },
        set: function(value) {
            //value为获取到修改的新值
        }
    })
    
    return {
      person
    }
  }

watch

  1. warch不再是对象,而是一个函数,需要导入才能用
  2. 可以直接添加为ref,reactive生成的对象或者是数组,而不监听对象内部的单独属性(person.money这种写法在Vue2中可以,在Vue3中需要写成函数的返回值 ()=>person.money)
  3. 可以写多个watch
  4. 一个watch监听多个,这样返回的newValueoldValue都会返回数组·
  5. 当监听reactive对象的时候,返回的oldValue===newValue,获取不到真实的oldValue
  6. watch第三个参数是配置有immediately,deep,但是deep不生效,强制开启,跟Proxy的原理有关系
import {ref,reactive,watch} from 'vue'
setup(props,context) {
    let person = reactive({
        name:'连颜少',
        money:1000000,
        job:{
            job1:{
                salary:20
            }
        }
    })
    
    let num1 = ref(500)
    let num2 = ref(600)
    // 写法1
    watch(num1,(newValue,oldValue) => {
        console.log('num1',newValue,oldValue)
        // result:num1 501 500
    })
    // 写法2:监听多个
    watch([num1,num2],([newnum1,newnum2],[oldnum1,oldnum2]) => {
        console.log('num1,num2',newValue,oldValue)
        // result: num1,num2,  [501, 600] ,[500, 600]
    })
    // 写法3:监听对象
    watch(person,(newValue,oldValue) => {
        console.log('person',newValue,oldValue)
        // 这时候由于对象是引用类型数据,无法返回oldValue的值,newValue === oldValue
    })
    // 写法4:监听对象内的单独属性
    watch(()=>person.money,(newValue,oldValue) => {
        console.log('person.money',newValue,oldValue)
        // result: 1000001 , 1000000
    })
    // 写法5:监听对象内的多个单独属性 和 ref的值 (这里的num1需要加上.value)
    watch(()=>[person.money,person.name,num1.value],(newValue,oldValue) => {
        console.log('person',newValue,oldValue)
    })
    // 写法6-1,兄弟们,最骚的地方来了:监听reactive里面的基本类型数据不行,监听对象却可以
    watch(person.job,(newValue,oldValue) => {
        console.log('person',newValue,oldValue)
        // 这样写反而可以了
    })
    // 写法6-2,还有另外一种函数返回值的写法可以监听对象中的对象,但是需要用上第三个属性 deep
    watch(()=>person.job,(newValue,oldValue) => {
        console.log('person',newValue,oldValue)
        // 这样写也可以
    },{deep:true})
    return {
      person,num1,num2
    }
  }

总结的来说就是:

  1. 1.可以监听单个ref基本类型,
  2. 2.可以监听多个ref基本类型,
  3. 3.可以监听多个reactive对象(默认deep:true),
  4. 4.不可以直接监听reactive对象里面的基本类型需要转化为返回函数(()=>person.money),
  5. 5.可以直接监听reactive对象里面的 对象,好像有点绕?
  6. 6.也可以用返回函数去监听对象里面的对象,但是这时候需要设置 deep:true(这种写法多此一举)
  7. 7.用返回函数的方法去监听ref的基本类型,需要.value (但是这么写的多少脑子有点问题吧,除非和其他数据一起监听需要) image.png

watchEffect(callback):监听回调函数内的所有属性,当一个发生变化,则重新执行回调函数

你可能会说,这特么不就是computed吗?还是有一点点区别:

  • computed需要返回值,重点在最终返回的内容
  • watchEffect 没有返回值,重点在执行的过程

生命周期:

  • 可以但是不精确的描述就是:
    • 删除了beforeCreatedcreated (其实没删除,并且用Vue2写法依然可以,只是整合到setup里面了)
  • - beforeDestorydestoryed 更名为 beforeUnmountunmounted
  • 笔者这边建议还是用Vue2的写法,写在setup外面,分清每个生命周期,全写在setup里面显得太臃肿

hook:类似mixins,封装数据的方法,返回需要的内容,在需要的页面按需引入~

toRef 和 toRefs

  1. toRef:把一个对象内的属性,变成ref类型的值
  2. toRefs:对象内的所有属性逐个解析,变成ref的值(这个就好用了)
setup() {
    let data = reactive({
        person: {
            name:'连颜少',
            age:18,
            job:{
                name:'front-end',
                salary:20
            }
        }
    })

    return {
    ...toRefs(data)
    }
}
// 第一篇我们讲过,把整个数据用reactive封装成data,这样模板里直接就用data.xxx属性,但是这样还是得多写个data,不妨就用上toRefs,就可以省去data,直接使用内部的值了,看起来就跟Vue2一样了

shallowReactive 和 shallowRef

  1. shallowReactive:只监听对象的第一层,第一层实现响应式
  2. shallowRef:判断是否为对象,如果是对象,则不监听。这边建议与Ref相比,用shallowRef更好,直接拒绝了实现Ref传入对象的情况

readonly 和 shallowReadoly

  1. readonly 将数据变为只可读(深层次都不允许修改)
  2. shallowReadoly 将数据的最外一层标记为只可读

toRow:顾名思义,就是把Vue封装的refImpl或者Proxy数据,返回为原生数据类型

markRow:将一个对象标记为原生,无法被ref和reactive给转化为响应式

customRef(callback(track,trigger)):自定义Ref,可以定义一些ref中的个性化操作

// 写个lazy绑定的例子:
setup() {
    let name = selfRef('连颜少')
    function selfRef(value) {
        let timer
        return customRef((track,trigger) => {
            return {
            // customRef需要返回值,并且一定要定义get和set方法
            get() {
                track() // 追踪值的变化
                return value //返回获取到的值
            },
            set(newValue) {
                clearTimeout(timer) // 个性化设置:防抖半秒,清除定时器
                timer = setTimeout( ()=> {
                    value = newValue // 将设置的新值,赋值给返回值
                    trigger() // 触发模板重新解析
                },500)
            }
            }
        })
    }
}


结语

下一篇会继续分析:Vue2Vue3Fragment组件,Teleport组件Suspense组件等...

如果你觉得此文对你有一丁点帮助,点个赞,给我一点儿鼓励哈~

更多精彩:

image.png