vue3使用总结
1. ref 和 reactive 的区别:
ref:定义基本数据类型、引用数据类型的响应式;
reactive:定义引用类型数据的响应式,不支持基本数据类型,如果需要写基本数据类型只能是放在对象中。
因为,不管什么类型数据,通过 ref 来定义的,都需要以 .value 的方式来调用。
这样会导致,对于引用数据类型来看,代码并不美观。
所以,对于引用类型数据,都推荐使用 reactive 来定义;
而对于基本数据类型,可以使用 ref 也可以使用 reactive 来定义。其实在绝大多数场景下,ref 都够用了。
在使用时,不要使用解构去写,会丢失响应性。
<template>
<div>{{ count }}</div>
<button @click="onClick">
增加 1
</button>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(1);
const onClick = () => {
// 不要这样写!!
const { value } = count;
value += 1;
};
</script>
2. watch 监听:
(1) 当 watch 监听一个 使用 ref 定义的 未初始化的数组 时,不能用 .value 且 必须是深度监听。
这种写法不仅可以监听数组本身的变化,也可以监听数组元素的变化:
const selectedColumnsArr = ref([]);
watch(
selectedColumnsArr, // 此处不用 .value
(newValue, oldValue) => {
console.log('选择数组变化了', newValue, oldValue)
},
{deep: true}
)
(2) 监听一个 string:
const name = ref('张三')
watch(
name,
(newValue, oldValue) => {
console.log('watch===', newValue, oldValue)
}
)
(3) 监听一个 reactive:
const userInfo = reactive({
name: '张三',
age: 10
})
// 监听整个对象
watch(
userInfo,
(newValue, oldValue) => {
console.log('watch userInfo', newValue, oldValue)
}
)
// 监听某个属性
watch(
() => userInfo.name,
(newValue, oldValue) => {
console.log('watch name', newValue, oldValue)
}
)
(4) 监听多个源,可以传入一个数组同时侦听多个数据。
(以往在 Vue2 中为了实现同时监听多个数据,往往需要借助 computed ,现在在 Vue3 里我们可以少一些不必要的代码了):
const name = ref('张三')
const userInfo = reactive({
age: 18
})
// 同时监听name和userInfo的age属性
watch(
[name, () => userInfo.age],
([newName, newAge], [oldName, oldAge]) => {
console.log('watch name', newName, oldName)
console.log('watch age', newAge, oldAge)
}
)
(5) watchEffect 的用法:
watchEffect 传入一个函数参数,该函数会立即执行。同时会响应式的更新函数内的依赖变量,并在依赖发生改变时重新运行该函数。
例一:
const name = ref('张三')
const age = ref(18)
watchEffect(() => {
console.log(`${name.value}:${age.value}`) // 张三:18
})
setTimeout(() => {
name.value = '李四' // watchEffect中打印- 李四:18
}, 3000)
setTimeout(() => {
age.value = 20 // watchEffect中打印- 李四:20
}, 5000)
例二:
<template>
<div>{{ count }}</div>
<div>{{ anotherCount }}</div>
<button @click="onClick">增加 1</button>
</template>
<script setup>
import { ref, watchEffect } from 'vue';
const count = ref(1);
const onClick = () => {
count.value += 1;
};
const anotherCount = ref(0);
// 注意这里
watchEffect(() => {
// 会自动根据 count.value 的变化,
// 触发下面的操作
anotherCount.value = count.value - 1;
})
</script>
所以,它和watch的区别:
- 运行时机不同。watchEffect会立即执行,相当于设置了 immediate: true 的 watch;
- watch 需要你明确指定依赖的变量,才能做到监听效果;
- watchEffect 会根据你使用的变量,自动的实现监听效果;
- watchEffect 无法获取改变前后的值;
- 建议在大部分时间里使用 watch,避免一些不必要的重复触发。
3. Vue3中,可以通过参数来达到一个组件支持多个 v-model 的能力。
// 父组件
<template>
<child v-model="name" v-model:email="email" />
<p>姓名:{{ name }}</p>
<p>邮箱:{{ email }}</p>
</template>
<script setup>
import child from './child.vue'
import { ref } from 'vue'
const name = ref('张三')
const email = ref('666@qq.com')
</script>
// 子组件
<template>
<button @click="updateName">更新name</button>
<button @click="updateEmail">更新email</button>
</template>
<script setup>
// 定义emit
const emits = defineEmits(['update:modelValue','update:email'])
const updateName = () => {
emits('update:modelValue', '李四')
}
const updateEmail = () => {
emits('update:email', '123456@qq.com')
}
</script>
如果 v-model 没有使用参数,则其默认值为 modelValue,如上面的第一个v-model,注意此时不再是像Vue2 那样使用 $emit(‘input’)了,而是统一使用 update:xxx 的方式。
4. Vue3中,废弃了 .sync
在 Vue2 中,由于一个组件只支持一个 v-model,当我们还有另外的值也想要实现双向绑定更新时,往往用 .sync 修饰符来实现,而在 Vue3 中该修饰符已被废弃,因为 v-model 可以支持多个( 如上第3点所述 ),所以 .sync 也就没有存在的必要了。
5. Vue3中,无法使用 ref 访问子组件的方法和属性
在 Vue3 中必须使用 defineExpose 暴露子组件内的方法或属性才能被父组件所调用。
// 父组件
<template>
<child ref="childRef" />
</template>
<script setup>
import { ref, onMounted } from 'vue'
const childRef = ref()
onMounted(() => {
childRef.value.getData()
})
</script>
// 子组件
<script setup>
import { defineExpose } from 'vue'
const getData = () => {
console.log('getData')
}
const name = ref('张三')
defineExpose({
getData,
name
})
</script>
6. 生命周期
除了将两个 destroy 相关的钩子,改成了 unmount,剩下需要注意的,就是在
<script setup>
中,不能使用 beforeCreate 和 created 两个钩子。