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...
posted on 2025-08-18 11:14  Siannnn  阅读(11)  评论(0)    收藏  举报