-
三个子组件:A、B、C
-
父组件:
<template>
<h2 style="color: red">Vue父组件使用v-for循环不同(或相同)子组件ref使用问题</h2>
<div>
<el-button size="large" @click="aa">AAAAA</el-button>
<el-button size="large" @click="bb">BBBBB</el-button>
</div>
<div v-for="(item, index) in data.tabs" :key="item.id" style="height: 150px; border: 1px solid blueviolet">
<component :is="item.component" :message="item.name + '组件通过props传递的数据'"
:ref="(el) => setMyRef(el, item.refName)"></component>
</div>
</template>
<script setup>
import { reactive, markRaw } from 'vue'
import A from '@/views/pageTest/components/A.vue'
import B from '@/views/pageTest/components/B.vue'
import C from '@/views/pageTest/components/C.vue'
//为什么使用markRaw,控制台出现警告,原因分析:
/**
将一个Vue组件对象转换为响应式对象时,可能会导致不必要的性能开销。
这是因为Vue会对响应式对象进行递归式的深度观察,在对象的每个属性上都会添加getter和setter,
以便能够在响应式对象发生变化时自动更新视图。
但是,在某些情况下,将Vue组件对象转换为响应式对象是不必要的,因为组件本身是Vue的核心概念,
已经具有响应式的功能,因此,如果你将一个Vue组件对象转换为响应式对象,
将会出现重复观察相同的对象属性的情况,导致不必要的性能开销。
为了避免这种情况,Vue建议使用markRaw方法将组件对象标记为非响应式对象,
或者使用shallowRef代替ref来创建一个浅响应式对象
使用markRaw方法将组件对象标记为非响应式对象。
*/
let myRefs = {}
// 核心
const setMyRef = (el, refName) => {
if (el) {
myRefs[refName] = el
}
}
const data = reactive({
tabs: [
{
id: 1,
name: 'A',
refName: 'refA',
component: markRaw(A),
},
{
id: 2,
name: 'B',
refName: 'refB',
component: markRaw(B),
},
{
id: 3,
name: 'C',
refName: 'refC',
component: markRaw(C),
},
],
})
const aa = () => {
myRefs.refA?.a('A组件的方法被调用了')
}
const bb = () => {
myRefs.refB?.b('B组件的方法被调用了')
}
</script>
<style scoped></style>
- 效果: