vue2转vue3一些属性使用方法总结 (持续更新中)

本文介绍了Vue3中移除this.$set方法,使用Proxy实现响应式系统,以及如何在Vue3中定义数组、对象、使用watch、v-bind=$attrs、nextTick、props父子传值、组件间通信等关键概念。同时,还涵盖了Vue2与Vue3之间的差异和注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.vue3中不再需要用this.$set 方法

在 Vue 3 中,this.set方法不再存在,因为Vue3使用了Proxy来实现其响应式系统,使得对象的属性访问和修改都能够被自动追踪。因此,在Vue3中,你通常不需要使用特殊的方法来添加响应式属性。在Vue2中,你可能会使用this.set 方法不再存在,因为 Vue 3 使用了 Proxy 来实现其响应式系统,使得对象的属性访问和修改都能够被自动追踪。因此,在 Vue 3 中,你通常不需要使用特殊的方法来添加响应式属性。 在 Vue 2 中,你可能会使用 this.set方法不再存在,因为Vue3使用了Proxy来实现其响应式系统,使得对象的属性访问和修改都能够被自动追踪。因此,在Vue3中,你通常不需要使用特殊的方法来添加响应式属性。在Vue2中,你可能会使用this.set 来确保向一个已经创建的数组或对象添加的新属性是响应式的。但在 Vue 3 中,当你使用
ref 或 reactive 创建的响应式对象或数组时,任何新添加的属性默认都是响应式的。

2.vue3定义数组 并接口赋值

定义数组 并赋值
const items = ref([]);
const myObject = reactive({});

const response = await axios.get('your-api-endpoint');
items.value = response.data; // 假设接口返回的是数组格式数据

3.watch侦听对象中的具体属性

watch 的基本用法

watch() 默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数

第一个参数:侦听源,侦听源可以是一下几种

一个函数,返回一个值一个 ref一个响应式对象(reactive)或是由以上类型的值组成的数组
第二个参数:侦听源发生变化时要触发的回调函数。

​ (newValue, oldValue) => { /* code */}

​ 当侦听多个来源时,回调函数接受两个数组,分别对应源数组中的新值和旧值

​ ( [ newValue1, newValue2 ] , [ oldValue1 , oldValue2 ]) => {/* code
*/}

第三个参数:可选对象,可以支持一下这些选项

immediate:侦听器创建时立即触发回调
deep:如果源是一个对象,会强制深度遍历,以便在深层级发生变化时触发回调函数
flush:调整回调函数的刷新时机onTrack / onTrigger:调试侦听器的依赖

const obj = reactive({ count: 0 })
// 错误,因为 watch() 中的侦听源是一个 number,最终 source 返回的 getter 函数是一个空,所以就得不到侦听的数据
watch(obj.count, (count) => {
  console.log(`count is: ${count}`)
})
// 正确,主要思想是,将侦听源转化为以上4种类型(转化为getter函数是最简单方便的)
watch(
  () => obj.count,
  (count) => {
    console.log(`count is: ${count}`)
  },
  {
    immediate: true, // 立即执行回调
    deep: true,      // 深度观察
    flush: 'pre'     // 在DOM更新之前调用回调
  } //第三个参数的使用方法
)

4.过滤方法
const statusFilter = (status: number) => {
const filter: any = { 0: ‘danger’, 1: ‘success’, 50: ‘danger’ }
return filter[status]
}

5.vue2中this.$nextTick() 方法在vue3中使用如下:

import  {nextTick} from 'vue'
nextTick(()=>{
// 这个回调将在 DOM 更新后执行
})

6. vue3中使用的 v-bind=‘$attrs’ 踩坑

在 Vue 3 中,v-bind=“$attrs” 的用法与 Vue 2 中相同,它用于将父组件中未被子组件识别(即未定义为
props)的属性绑定到子组件的根元素上。这样做可以确保父组件传递的额外属性(如 class、style 等)能够被应用到子组件上。
$attrs是一个对象,包含了父组件中不被认为是props的属性,这些属性可以是事件监听器(v-on),或者其他的DOM attribute。

注意1,inheritAttrs: false 的使用是可选的,

这取决于你是否希望 $attrs 自动绑定到子组件的根元素上。如果你希望手动控制这些属性的绑定,你可以设置 inheritAttrs 为 false,并在 setup 函数中返回你想要绑定的属性。
如果你不使用 inheritAttrs: false,则 attrs会自动绑定到子组件的根元素上,你不需要在模板中显式地使用v−bind="attrs 会自动绑定到子组件的根元素上,你不需要在模板中显式地使用 v-bind="attrs会自动绑定到子组件的根元素上,你不需要在模板中显式地使用vbind="attrs"。
如果你需要处理 $attrs 中的类名和样式,你可能需要手动合并它们,因为 Vue 不会自动合并这些属性。这通常可以通过使用工具函数如 classNames 或 mergeStyles 来实现。

注意2, 在vue3中 我们经常定义对象的类型时,会有继承类型的使用

 如: interface ProTableProps extends Partial<Omit<TableProps<any>, 'data'>>{  //****此处省略}
  //ProTableProps继承extends Partial<Omit<TableProps<any>, 'data'>>后,v-bind=$attrs穿透不生效了 ,所以去掉继承会继续生效

7.父子传值
1 .props 父子传值
父组件 :

 <div>
    <!-- 子组件 -->
    <child  :message=" '信息' "></child>
	</div>
子组件:   需要用到defineProps方法,是vue3提供方法,不需要引入直接使用
<script setup>
let props = defineProps(['message'])
使用方法:不管在script中还是template中  都是 props.message
<script />

//扩展子组件中多种方式接收参数:

<script setup lang="ts">
   import type {Persons} from '@/types'
   // 1. 接收list + 可不传
    defineProps(["list"])
 
   //2. 接收list + 限制类型 + 必传
    defineProps<{list:Persons}>()
 
   //3. 接收list + 限制类型 + 设置默认值 + 可不传
   withDefaults(defineProps<{list:Persons}>(),{
      // 数组类型必须使用函数返回,其它不用
      list:()=>[{name: '张三',age: 18,id:"adwa1234"}]
   })
   
   //4. 将Props收到的值保存起来,是一个对象
    let propsData = defineProps(["persons"])
    console.log(propsData.list);
   //5. 接收 Object类型参数
    const props = defineProps({
    formData: {
        type: Object,
        default: () => {
            return {}
        },
    },
});
</script>

2.defineExpose 方法,子组件将属性和方法暴露出去 ,父组件可以调用子组件的方法

//子组件:
defineExpose({
    closeDialog,
    openDialog,
});

//父组件
<div><child ref='childRef'></child><div>
/**
 * ref<InstanceType<typeof 组件名>>()来获取各个子组件实例
 */
const childRef = ref<InstanceType<typeof child>>();
childRef.value.openDialog(mode);  //父组件调用子组件方法

3.子组件触发父组件的方法 defineEmits适用于父组件向子组件传递方法

 //子组件:
<script setup lang="ts">
const emits = defineEmits<{
    (e: 'getTableList'): void;
}>();
	let props = defineProps(['message'])
	function changMes (){
		props.message = '信息123'
		emits('getTableList');  //触发父组件的值
	}
</script>
//父组件
<div><child ref='childRef' 	:message="'信息'" @getTableList=‘getTableList'></child><div>

8.定义el-form的ref,

使用ref来引用一个DOM元素或者一个组件实例。使用ref来访问它的实例和方法。

当我们有一个el-form组件时
<el-form ref="formDataRef" >
</el-form>
vue2: this.$refs.formDataRef 
vue3: const formDataRef = ref<FormInstance | null>(null);

9.// 定义el-tree的ref , (其他组件同理,不全部举例了)

使用ref来访问el-tree的实例和方法 vue3: const treeRef = ref(null)

<template>
    <el-tree ref="treeRef" :data="treeData" @node-click="handleNodeClick"></el-tree>
</template>

// setup函数中,你需要声明这个ref:
const treeRef = ref(null)
// 创建了一个名为treeRef的ref,并将其初始化为null。当el-tree组件被挂载时,这个ref会被自动填充为el-tree的实例。

//现在,你可以通过treeRef来访问el-tree组件的实例和方法。例如,你可以使用treeRef.value.expand(data)来展开某个节点,或者使用treeRef.value.getCheckedNodes()来获取当前被选中的节点。

请注意,在Vue 3中,ref是一个响应式引用,你需要通过.value来访问或修改它的值

接下来你可能会发现:
在这里插入图片描述

在Vue3中,使用ref创建的引用默认是null,直到它们被关联到实际的DOM元素或组件实例。因此,当你尝试访问treeRef.value时,TypeScript可能会警告你treeRef.value可能是null,特别是在组件刚挂载或ref尚未关联到任何实例时。
为了避免上边这种警告,你可以使用可选链式操作符?.来安全地访问value属性,或者使用条件检查来确保treeRef.value不是null。

解决办法:
1.使用可选链式操作符:

// 只有在treeRef.value不是null时,才会执行后面的操作
treeRef.value?.expand(nodeData);

// 获取当前被选中的节点,如果treeRef.value是null则不执行任何操作
const checkedNodes = treeRef.value?.getCheckedNodes();

2.使用条件检查:
if (treeRef.value) {
// 确保treeRef.value不是null再执行操作
treeRef.value.expand(nodeData);
const checkedNodes = treeRef.value.getCheckedNodes();
}
3.使用非空断言操作符! :

告诉TypeScript编译器你确信treeRef.value不会是null。但是,请小心使用这个操作符,因为它会绕过TypeScript的类型检查,如果treeRef.value实际上是null,那么你的代码将会抛出运行时错误。

// 使用非空断言操作符
treeRef.value!.expand(nodeData);
const checkedNodes = treeRef.value!.getCheckedNodes();
  1. vue3中 封装一个响应式组件,v-model 的值的变化,与emit的使用
//father中
<div>
<child v-model="fatherValue"></child>
</div>

//child中
<span>{{props.modelValue}}</span>
<el-button @click="changeModelValue">修改</el-button>
<script setup>
const props = defineProps({
    modelValue: String, //首先modelValue接收组件传来v-model的值,  
    //至于为什么是modelValue,可以去补充下双向绑定的基本实现原理的知识
})
const emits = defineEmits(['update:modelValue']) //接收父组件的事件,子组件中触发父组件使用
function changeModelValue(){
	props.value.modelValue = 'children'
	emits('update:modelValue',props.value.modelValue)  //将修改后的值传回去,实现双向绑定
}
</script>
补充双向绑定实现原理
一般写法: <ChildComponent v-model="name" /> 
 其实是:<ChildComponent  :modelValue="name"  @update:modelValue="name = $event"/> 的简写
自定义组件上的 v-model 相当于传递了 modelValue prop 并接收抛出的 update:modelValue 事件

注意:
可以写:1. v-model=“name” 2.v-model:modelValue=“name”
3. 不可以 :modelValue = “name” 不可以,因为v-model是vue语法糖,背后原理是利用emit(‘update:modelValue’)来修改,而:modelValue写法不具备组件通信中的语法糖功能;
所以在vue3中,为了更好的对组件进行双向响应式,就只能用v-model这种写法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值