0%

vue3系列二

说明

  • 紧接 vue3系列一 文章
  • 环境等信息参考上述的文章

其它Composition API

toRef与toRefs

toRef

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

  • 语法:const name=toRef(obj,‘name’)

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

  • 扩展:toRefs与toRef功能一致,但可以批量创建多个ref对象,toRefs(obj)

  • 如下实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<template>
<h2>toRef与toRefs</h2>
<h2>姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<h2>薪水:{{person.job.salary}}k</h2>
<button @click="person.name+='!'">修改姓名</button>
<button @click="person.age++">修改年龄</button>
<button @click="person.job.salary++">涨点薪资</button>
</template>

<script>
import {reactive} from 'vue'
export default {
name: "toRef_component",
setup(){
let person=reactive({
name:'二郎神杨杨戬',
age:18,
job:{
salary:20
}
})
return{
person,
}
}
}
</script>

<style scoped>

</style>

示例一里面直接返回person对象,导致每次取值的时候都需要person.xxx,这样既不美观也不优雅,修改一下代码。

  • 修改代码为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<template>
<h2>toRef与toRefs</h2>
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<h2>薪水:{{salary}}k</h2>
<button @click="name+='!'">修改姓名</button>
<button @click="age++">修改年龄</button>
<button @click="salary++">涨点薪资</button>
</template>

<script>
import {reactive,toRef} from 'vue'
export default {
name: "toRef_component",
setup(){
let person=reactive({
name:'二郎神杨杨戬',
age:18,
job:{
salary:20
}
})
return{
name:toRef(person,'name'),
age:toRef(person,'age'),
salary:toRef(person.job,'salary')
}
}
}
</script>

<style scoped>

</style>

toRefs

  • 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<template>
<h2>toRef与toRefs</h2>
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<h2>薪水:{{job.salary}}k</h2>
<button @click="name+='!'">修改姓名</button>
<button @click="age++">修改年龄</button>
<button @click="job.salary++">涨点薪资</button>
</template>

<script>
import {reactive,toRef,toRefs} from 'vue'
export default {
name: "toRef_component",
setup(){
let person=reactive({
name:'二郎神杨杨戬',
age:18,
job:{
salary:20
}
})
return{
...toRefs(person)
}
}
}
</script>

<style scoped>

</style>

shallowRef和shallowReactive

  • shallowReactive:只处理对象最外层属性的响应式(浅响应式)

  • shallowRef:只处理基本数据类型的响应式,不进行对象的响应式处理

  • 什么时候用

    • 如果有一个对象数据,结构比较深,但变化时只是外层属性变化用shallowReactive

    • 如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换用shallowRef

  • 感觉没有什么用,不做演示

readonly和shallowReadonly

  • readonly:让一个响应式数据变为只读的(深只读)

  • shallowReadonly:让一个响应式变为只读的(浅只读)

toRaw和markRaw

  • toRaw

    • 作用:将一个由reactive生成的响应式对象转为普通对象
    • 使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新
  • markRow

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

      应用场景

    • 有些值不应该被设置为响应式的,例如复杂的第三方类库,

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

customRef

  • 作用:创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显示控制,它需要一个工厂函数,该函数接收 track 和 trigger 函数作为参数,并且应该返回一个带有 get 和 set 的对象。
    实现防抖效果:
  • 1、先实现自定义双向绑定
  • 2、实现了双向绑定之后,实现防抖

响应式数据的判断

  • isRef:检查一个值是否为ref对象
  • isReactive:检查一个对象是否由reactive创建的响应式代理
  • isReadonly:检查一个对象是否由readonly创建的只读代理
  • isProxy:检查一个对象是否由reactive或者readonly方法创建的代理

provide和inject

  • 在父子组件传递数据时,通常使用的是 props 和 emit,父传子时,使用的是 props,如果是父组件传孙组件时,就需要先传给子组件,子组件再传给孙组件,如果多个子组件或多个孙组件使用时,就需要传很多次,会很麻烦。
  • 像这种情况,可以使用 provide inject 解决这种问题,不论组件嵌套多深,父组件都可以为所有子组件或孙组件提供数据,父组件使用 provide 提供数据,子组件或孙组件 inject 注入数据。同时兄弟组件之间传值更方便。

img

  • 祖组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    <template>
    <h2>我是祖组件</h2>
    <h3>汽车信息</h3>
    <p>名称:{{name}}</p>
    <p>价格:{{price}}</p>
    <inject_component></inject_component>
    </template>

    <script>
    import {reactive,toRefs,provide} from 'vue'
    import inject_component from "./inject.vue"

    export default {
    name: "provide_component",
    setup(){
    let car=reactive({
    name:'宝马',
    price:'40w'
    });
    provide('car',car); // 提供provide
    return{
    ...toRefs(car)
    }
    },
    components:{
    inject_component
    }
    }
    </script>

    <style scoped>

    </style>

  • 后代组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<template>
<h2>我是孙组件</h2>
<h3>汽车信息</h3>
<p>名称:{{name}}</p>
<p>价格:{{price}}</p>
</template>

<script>
import {inject,toRefs,ref} from 'vue'
export default {
name: "inject_component",
setup(){
let car=inject("car"); //使用inject接收
return{
...toRefs(car)
}
}
}
</script>

<style scoped>

</style>

  • 运行结果

image-20240307151409520

在vue2中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//父组件

export default{

provide:{

info:"提供数据"

}

}

//子组件

export default{

inject:['info'],

mounted(){

console.log("接收数据:", this.info) // 接收数据:提供数据

}

}
  • provide / inject 类似于消息的订阅和发布。provide 提供或发送数据, inject 接收数据。

Vue2x和Vue3x的其它变化

1.全局API的转移

vue2.x有许多全局API和配置,例如:全局注册组件、注册全局指令等

  • 注册全局组件
1
2
3
4
5
6
7
Vue.component('MyButton',{
data:()=>{
count:0,
},
template:'<button @click="count++">clicked {{count}} times</button>'
});

  • 注册全局指令,
1
2
3
4
Vue.directive('focus',{
inserted:el=>el.foucus
})

  • Vue3.0中对这些API做出了调整

  • 将全局的API,即Vue.xxx调整到应用实例app上

2.x 全局API(Vue) 3.x 实例API(app)
Vue.config.xxx app.config.xxx
Vue.config.productionTip 移除
Vue.component app.component
Vue.directive app.directive
Vue.mixin app.mixin
Vue.use app.use
Vue.prototype app.config.globalProperties
  • 移除过滤器(filter):过滤器虽然看起来方便,但它需要一个自定义语法,打破大括号内表达式’只是javascript’的假设,这不仅有学习成本,而且有实现成 本, 建议用法调用或者计算属性去替换过滤器