vue3-ref、reactive、计算属性、watch监视、生命周期
ref和reactive区别
ref创建的变量必须使用.value
reactive重新分配一个新对象(在函数中另car={brand:,price:} 此时是给car重新分配了一个对象),会失去响应式,需要使用Object.assign Object.assign(变量,{属性:,属性:})
而ref则不影响,因为重新分配时修改的是.value
开发时:基本类型必须用ref,需要一个层级较深的响应式对象用reactive
toRefs和toRef
这两都是将对象解构拿出来,让其具有响应式
let {name,age}=toRefs(person)是响应式引用,让name指向person.name
let n1=toRef(person,'name')
计算属性(尽量在模板template中代码简洁)
<input :value=""> 此时是单向绑定:只能数据流向页面,而不能页面流向数据
计算属性有缓存、方法没缓存
let fullName=computed(()=>return firstName.value.slice(0,1)+lastName.value)此时fulllName是只读,不可修改
要想可读写改:
let fullName = computed({
get() {
return (
firstName.value.slice(0, 1).toUpperCase() +
firstName.value.slice(1) +
"-" +
lastName.value
);
},
set(newValue: string) { //set方法实现修改
console.log(newValue);
const [str1, str2] = newValue.split("-");
firstName.value = str1;
lastName.value = str2;
},
});
function changeName() {
fullName.value = "li-si";
}
watch
监视数据的变化,但只监测ref、reactive定义的数据、函数返回一个值(getter函数)、一个包含上述内容的数组
watch(a,b,c) a:是被监视的数据,b是回调函数,c是配置对象(deep、immediate等)
- 监视ref定义的基本类型
import { ref, watch } from "vue";
let sum = ref(0);
function changeSum() {
sum.value++;
}
const stopwatch = watch(sum, (newValue, oldValue) => { //watch(监视的变量,回调函数)
console.log("sum changed:", sum.value); //上面监视的sum无.value(因为监视变量的限制)
if (newValue > 10) stopwatch();
});
- ref定义的对象类型
import { ref, watch } from "vue";
let person = ref({
name: "张三",
age: 18,
});
function changeName() {
person.value.name += "+";
}
function changeAge() {
person.value.age += 1;
}
function changeperson() {
person.value = {
name: "李四",
age: 20,
};
}
watch(
person,
(newValue, oldValue) => {
console.log("person changed:", newValue, oldValue);
},
{ deep: true } // 深度监听
);
深度监视监视的是地址
若需改的ref是对象中的属性,newValue和oldValue都是新值,因为它们是同一个对象
若修改的是ref定义的对象,newValue是新值,oldValue是旧值,因为它们不是同一个对象了
- reactive定义的对象类型数据
是默认开启深度监视的且关闭不掉
function changeperson() {
Object.assign(person, { name: "李四", age: 20 }); //也没有创建新对象,所以newValue和oldValue相同
}
- ref和reactive定义的对象类型数据中的某个属性
想监听一个响应式对象中的某属性(非对象类型),可以包装成一个getter函数(一个返回值)
watch(
() => person.name, //只监视name属性需写成函数
(a, b) => {
console.log("name changed:", a, b);
},
{ deep: true }
);
监视对象类型
写成函数(监测整体)+上深度监测(也能监视对象内部),不写成函数(监视不到整体)
watch(
() => person.car,
() => {
console.log("car changed:", person.car);
},
{ deep: true }
);
- 监视多个数据
用[]
watch([() => person.name, () => person.car.c1], () =>
console.log("name or car.c1 changed:", person.name, person.car.c1)
);
watchEffect
立即运行一个函数,同步响应式追踪其依赖,并在依赖更改时重新执行该函数
不用明确指出监视的属性
//当if里两个数据变化时,watchEffect自动监视
watchEffect(() => {
if (temp.value >= 60 || height.value>=80) {
console.log("向服务器发请求");
}
})
ref标签的属性、组件
给dom结点打标识的
<h3 ref="title2">北京</h3>
import { ref } from "vue";
let title2 = ref();
function showLog() {
console.log(title2.value);
}
Array<PersonInter> 泛型
当defineExpose({a,b,c}) 时 父组件则可以console.log出子组件中ref标签过的元素
<style scoped> </style> scoped是局部样式,只在当前.vue中执行
父组件与子组件传递数据
:list="personList" 冒号让其变成动态数据,无冒号就是个字符串
父组件:
<Person :list="personList" />
子组件:
import { ref, watch, watchEffect, withDefaults } from "vue";
import { type PersonInter, type Persons } from "@/types"; //@符代表站在金字塔塔尖、type告诉自己引入了一个类型
//直接接受list
// const props = defineProps(["list"]);
// console.log("props", props);
//接受并限制类型
// defineProps<{ list: Persons }>();
//接受限制类型+限制必要性+指定默认值
withDefaults(defineProps<{ list?: Persons }>(), {
list: () => [
{
id: "123",
name: "默认用户",
age: 20,
},
],
});
生命周期
组件的生命周期:创建、挂载、更新、卸载 调用函数:created、mounted
父组件最后挂载(App.vue)
import {
ref,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted,
} from "vue";
onBeforeMount(() => {
console.log("挂载前");
});
onMounted(() => {
console.log("挂载后");
});
- 自定义hooks
像封装,命名为useDog...
浙公网安备 33010602011771号