只有身在更高处的你才能体验风不一样的感觉, 看不一样的风景
vue-cli
- 创建项目:
vue create [project-name]
- 运行项目:
npm run serve
vite
- 创建项目:
npm init vite@latest
- 运行项目:
npm run dev
Composition API(组合API)
ref
与reactive
ref
- 定义一个响应式的数据
- 语法
<script setup lang="ts">
// 按需导入API
import {
ref } from 'vue'
const refDc = ref('dc')
</script>
-
打印
refDc
-
使用需要通过
.value
方式,但是模板中是不需要这样的,自动会解包{ { refDc }}
就可使用 -
如果被套在
reactive
中会自动解包不用.value
-
基本类型的数据:响应式依然是靠
Object.defineProperty()
的get
与set
方式完成 -
对象类型的数据:内部是通过
reactive
函数完成(下面会有介绍)
shallowRef()
ref()
的浅层作用形式
import {
shallowRef } from "vue"
const obj = shallowRef({
name: "dc", age: 21 })
obj.value.name = "dcdc" /* 并不会触发响应式 */
// obj.value ===> { name: "dc", age: 21 }
// 即
obj.value = {
name: '帝尘'} /* 这样才会触发响应式 */
obj.value = '帝尘' /* 这样才会触发响应式 */
- 因为
ref
对象使用要.value
只有.value
这一项改变才会触发响应式, 即shallowRef({ name: "dc", age: 21 })
传入的参数本身改变才会触发响应式 - 不能跟
ref
一起去写会影响视图的更新(shallowRef
也会去触发更新)
triggerRef()
- 强制触发依赖于一个浅层
ref
的副作用, 也就是shallowRef()
的副作用
import {
shallowRef, triggerRef } from "vue"
const obj = shallowRef({
name: "dc", age: 21 })
obj.value.name = "dcdc" /* 并不会触发响应式 去更新视图 */
triggerRef(obj) /* 调用之后 会强制触发依赖于所传的ref对象 的副作用 */
customRef()
- 创建一个自定义的
ref
,显式声明对其依赖追踪和更新触发的控制方式(创建一个我们可控的ref) - 接受一个回调, 两个参数
track
和trigger
, 并返回一个带有get
和set
方法的对象。 - 一般:
track()
应该在get()
方法中调用,而trigger()
应该在set()
中调用
创建防抖的
ref
import {
customRef } from "vue"
const myRef = (value: any) => {
let time: number
return customRef((track, trigger) => {
return {
get() {
/* 跟踪依赖 */
track()
return value
},
set(newVal) {
clearTimeout(time)
time = setTimeout(() => {
value = newVal
/* 触发依赖 */
trigger()
}, 500);
}
}
})
}
const my = myRef(1)
const change = () => {
my.value++
}
reactive
:
- 定义一个响应式的数据
- 语法
<script setup lang="ts">
// 按需导入API
import {
reactive} from 'vue'
const reactionDc = reactive({
name: 'dc',
age: '21'
})
</script>
- 打印
reactionDc
reactive
对象是用来对复杂数据类型进行响应式,并且内部是通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等- 仅对对象类型(引用类型)有效(对象、数组和 Map、Set 这样的集合类型),而对 string、number 和 boolean 这样的 原始类型 无效。
- 原因: Vue 的响应式系统是通过属性访问进行追踪的, 如果更改了原始的引用就会导致响应式连接丢失
- 通过解构例如
let name = reactionDc.name
这种是不可取会丢失响应式 可以使用toRef | toRefs
去解构
shallowReactive()
reactive()
的浅层作用形式- 和 reactive() 不同,这里没有深层级的转换:一个浅层响应式对象里只有根级别的属性是响应式的。属性的值会被原样存储和暴露,这也意味着值为
ref
的属性不会被自动解包了
<template>
<div>{
{
shallowObj.c.d.e }}</div>
<button @click="change">改变</button>
</template>
<script setup lang="ts">
import {
isReactive, shallowReactive } from "vue";
const shallowObj = shallowReactive({
a: 1,
b: 2,
c: {
d: {
e: 10,
},
},
})
const change = () => {
// shallowObj.a++ 不能一起写
shallowObj.c.d.e++; /* 不会触发更新 */
console.log(
isReactive(shallowObj) /* true */,
isReactive(shallowObj.c.d.e) /* false */
)
}
不能跟
reactive
一起写会向ref
和shallowRef
一样影响视图更新
readonly()
- 属性只读, 不可修改
import {
readonly } from "vue";
const obj = readonly({
a: 123, b: 456 });
obj.a++; /* 会提示: 无法分配到 "a" ,因为它是只读属性。 */
shallowReadonly()
readonly()
的浅层作用形式
import {
shallowReadonly } from "vue";
const obj = shallowReadonly({
a: 123, b: {
c: 200 } });
// obj.a++ /* 会提示: 无法分配到 "a" ,因为它是只读属性。 */
obj.b.c++ /* 深层次可以修改 */
toRaw()
- 可以返回由
reactive()
、readonly()
、shallowReactive()
或者shallowReadonly()
创建的代理对应的原始对象
import {
shallowReadonly, toRaw } from "vue";
const obj = shallowReadonly({
a: 123, b: {
c: 200 } });
console.log(toRaw(obj)); /* 返回原始对象 { a: 123, b: { c: 200 } } */
markRaw()
- 与
shallowReactive()
和shallowReadonly()
,shallowRef
这种类似都是浅层作用形式, 作用为: 将一个对象标记为不可被转为代理。返回该对象本身
import {
markRaw, reactive} from "vue";
const markRawObj = markRaw({
a: 123, b: {
c: 200 } })
console.log(markRawObj); /* 添加标记属性 __v_skip: true */
const reactiveObj = reactive(markRawObj)
console.log(reactiveObj); /*