Vue3学习笔记:ref函数、reactive函数等常用Composition API、生命周期,Fragment、teleport等新的组件用法记录

一、快速上手Vue3.0

1、使用vue-cli

2、使用vite

开发环境中,无需打包

轻量快速热重载

npm init vite-app vue3_test_vite

二、常用Composition API(组合式API)

1、Setup

组件中所用到的:数据、方法等等,均要配置在setup中。

在setup中不能访问到vue2配置



2、ref函数

作用:定义一个响应式的数据

语法: const xxx = ref(initValue)

  • 创建一个引用对象
  • JS中操作数据: xxx.value
  • 模板中读取数据不需要.value

接收的基本类型数据:响应式依然是靠 Object.defineProperty() 的get 与set完成的

对象类型的数据(reactive)




3、reactive函数

作用:定义一个对象类型的响应式数据

语法: const 代理对象 = reactive(源对象)接收一个对象或数组,返回一个代理对象(proxy的实例对象)

内部基于ES6的proxy实现,通过代理对象操作源对象内部数据进行操作



4、Vue3响应式

实现vue2的响应式原理:

  let person = {
            name:'张三',
            age:18
        }
// 模拟Vue2中实现响应式
        let p = {}
        Object.defineProperty(p,'name',{
            get(){
                //有人读取name时调用
                return person.name
            },
            set(value){
                //有人修改name时调用
                console.log('有人修改了name,我去更新页面');
                person.name = value
            }
        })
        Object.defineProperty(p,'age',{
            get(){
                //有人读取name时调用
                return person.age
            },
            set(value){
                //有人修改name时调用
                console.log('有人修改了age,我去更新页面');
                person.age = value
            }
        })

实现原理:

通过Proxy(代理):拦截对象中任意属性变化。包括增删读写

通过Reflect(反射):对被代理对象的属性进行操作

  let person = {
            name:'张三',
            age:18
        }
const p = new Proxy(person,{
        get(target,propName){
            console.log(`有人读取了p身上的${propName}属性`);
            return Reflect.get(target,propName)
        },
        set(target,propName,value){
            console.log(`有人修改了p身上的${propName}属性,我要去更新界面了!`);
            Reflect.set(target,propName,value)
        },
        deleteProperty(target,propName){
            console.log(`有人删除了p身上的${propName}属性,我要去更新界面了!`);
            return Reflect.deleteProperty(target,propName)
        }
    })

5、reactive和ref的对比

  • 从定义数据角度对比:

    ​ ref定义基本数据

    ​ reactive定义对象或数组类型

    从原理角度对比:

    ​ ref通过 Object.defineProperty()的get与set来实现响应式。

    ​ reactive通过使用 Proxy来实现响应式(数据劫持)并通过Reflect操作源对象内部数据。

    从使用角度对比:

    ​ ref定义的数据:操作数据需要 .value,读取数据模板中直接读取不需要 .value

    ​ reactive定义的数据:操作读取均不需要 .value

6、Setup的注意点

setup执行时机:在beforecreate之前执行一次,this是undefined

Setup的参数:props值为对象,包含组件外传递过来且组件内声明接收了的属性

context:上下文对象

​ attrs:值为对象,包含组件外部传递过来但没有props配置中声明的属性,相当于 this.$attrs

​ slots:收到的插槽内容,相当于 this.$slots

​ emit:分发自定义事件的函数,相当于 this.$emit

7、计算属性与监视

1、computed写法

import {computed} from 'vue'
setup(){
    ...
    //简写
    //let fullName = computed(()=>{
    //    return person.firstName + '-' + person.lastName
    //})
    //计算属性完整
    let fullName = computed({
        get(){
            return person.firstName + '-' + person.lastName
        },
        set(value){
            const nameArr = value.split('-')
            person.firstName = nameArr[0]
            person.lastName = nameArr[1]
        }
    })
}

2、watch写法

监视reactive所定义的一个响应式数据的全部属性,无法正确地获取oldValue,deep失效

监视的是reactive定义的对象中的某个对象属性,deep配置有效

import {ref,reactive,watch} from 'vue'
setup(){
    let sum = ref(0)
    let msg = ref('你好啊')
    let person = reactive({
        name:'张三',
        age:18,
        job:{
            j1:{
                salary:20
            }
        }
    })
    //情况一:监视ref所定义的一个响应式数据
    watch(sum,(newValue,oldValue)=>{
        console.log('sum变了',newValue,oldValue)
    },{immediate:true})
    //情况二:监视ref所定义的多个响应式数据
    watch([sum,msg],(newValue,oldValue)=>{
        console.log('sum或msg变了',newValue,oldValue)
    },{immediate:true})
	}
	//情况三:监视reactive所定义的一个响应式数据的全部属性
	//此处无法正确地获取oldValue
	//强制开启深度监视
	watch(person,(newValue,oldValue)=>{
        console.log('person变化了',newValue,oldValue)
    },{deep:false})//deep配置无效
	//情况四:监视reactive所定义的一个响应式数据的某个属性
	watch(()=>person.name,(newValue,oldValue)=>{
        console.log('person的name变化了',newValue,oldValue)
    })
	//情况五:监视reactive所定义的一个响应式数据中的某些属性
	watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
        console.log('person的name或age变化了',newValue,oldValue)
    })
	//特殊情况
	watch(()=>person.job,(newValue,oldValue)=>{
        console.log('person的job变化了',newValue,oldValue)
    },{deep:true})//此处监视的是reactive定义的对象中的某个对象属性,所以deep配置有效
	return{
        sum,
        msg,
        person
    }

3、watchEffect函数

watch的套路是:既要指明监视属性,也指明监视回调

watchEffect:不用指明监视哪个属性,监视回调中用到哪个就监听哪个

import {ref,reactive,watch,watchEffect} from 'vue'
setup(){
    let sum = ref(0)
    let msg = ref('你好啊')
    let person = reactive({
        name:'张三',
        age:18,
        job:{
            j1:{
                salary:20
            }
        }
            })
    watchEffect(()=>{
        const x1 = sum.value
        const x2 = person.job.j1.salary
        console.log('watchEffect所指定的回调执行了')
    })
    	return{
        sum,
        msg,
        person
    }
   

8、生命周期

Vue3学习笔记:ref函数、reactive函数等常用Composition API、生命周期,Fragment、teleport等新的组件用法记录_第1张图片

Vue3.0中可以继续使用Vue2的生命周期钩子

beforeDestory改为 beforeUnmount

destroyed 改为 unmounted

Composition API形式的生命周期钩子,与Vue2中钩子对应关系如下:

beforeCreate===> setup()

created===>setup()

beforeMount ===> onBeforeMount

mounted===> onMounted

beforeUpdate===> onBeforeUpdate

updated===> onUpdated

beforeUnmount===> onBeforeUnmount

unmounted ===> onUnmounted

通过组合式API的形式去使用生命周期钩子




9、自定义hook函数

  • 本质是一个函数,把setup函数中使用的Composition API进行了封装
  • 类似于mixin
  • 复用代码,让setup中的逻辑更清楚

hooks/usePoint.js

import {onMounted,reactive,onBeforeUnmount} from 'vue'
export default function(){
    //实现“打点”的数据
    let point = reactive({
        x:0,
        y:0
    })
    //实现打点的方法
    function savePoint(event){
        point.x = event.pageX
        point.y = event.pageY
        console.log(event.pageX,event.pageY);
    }
    //实现打点的钩子
    onMounted(()=>{
        //函数体
        window.addEventListener('click',savePoint)
    })
    onBeforeUnmount(()=>{
        window.removeEventListener('click',savePoint)
    })
    return point
}

components/DemoOne.vue



10、toRef

作用:创建一个Ref对象,其value值指向另一个对象中的某个属性

语法 : const name = toRef(person,'name')

应用:要将响应式对象中的某个属性提供给外部使用时

扩展: toRefs(person)批量创建ref对象




三、其他Composition API

1、shallowReactive与shallowRef

shallowRecative只考虑对象类型第一层(最外层)的响应式

shallowRef不去处理对象类型的响应式,只处理基本数据类型响应式

使用:

如果一个对象数据结构比较深,但只用外层属性===>shallowRecative

如果一个对象数据后续不会修改对象中的属性,如要修改则直接替换为新的对象===>shallowRef

2、readonly与shallowReadonly

不希望数据被修改时

readonly:使一个响应式数据变为只读

shallowReadonly:使一个响应式数据外层只读

person = readonly(person)
person = shallowReadonly(person)

3、toRaw与markRaw

toRaw

  • 作用:将一个由 reactive生成的响应式对象转为普通对象
  • 使用:读取响应式对象对应的普通对象,对普通对象的所有操作不会引起页面变化
const p = toRaw(person)

markRaw

作用:标记一个对象,使其永远不会再成为响应式对象

使用:

有些值不应该被设为响应式,例如第三方类库axios等

渲染不可变数据的大列表时,可跳过响应式转换提高性能

let car = {name:'奔驰',price:40}
person.car = markRaw(car)

4、customRef

创建一个自定义Ref,并对其依赖项跟踪和更新触发进行显式控制

实现防抖效果:




5、provide与inject

作用:实现祖孙组件间通信

使用:父组件有一个 provide来提供数据,后代组件有一个 inject 选项来使用数据

父组件App.vue




后代组件Son.vue





6、响应式数据的判断

isRef():检查一个值是否为ref对象

isReactive():检查一个对象是否为reactive创建的响应式代理

isReadonly() :检查一个对象是否为readonly创建的只读代理

isProxy() :检查一个对象是否为代理

四、新的组件

1、Fragment

Vue3组件可以没有根标签,会将多个标签包含在一个Fragment虚拟元素中

减少层级嵌套

2、teleport

将组件html结构移动到指定位置


	

我是一个弹窗

3、Suspense

等待异步组件时渲染一些额外内容,增加用户体验

异步引入组件

import {defineAsyncComponent} from 'vue'
const Child = defineAsyncComponent(()=>import('./components/Child.vue'))

使用 Suspense包裹组件,配置 defaultfallback


五、其他变化

略写~~~~

移除 v-on.native修饰符

父组件中绑定事件



子组件中声明自定义事件


  
        
    
```

3、Suspense

等待异步组件时渲染一些额外内容,增加用户体验

异步引入组件

import {defineAsyncComponent} from 'vue'
const Child = defineAsyncComponent(()=>import('./components/Child.vue'))

使用 Suspense包裹组件,配置 defaultfallback


五、其他变化

略写~~~~

移除 v-on.native修饰符

父组件中绑定事件



子组件中声明自定义事件


你可能感兴趣的:(Vue,vue.js,javascript,vue,前端框架)