背景
在开发中是否曾遇到过, 需要把子组件的额外内容展示到当前template里其他位置的情况呢?
比如父组件的导航栏需要根据子组件的类型展示不同按钮的情况, 麻烦点的做法是在父组件内, 根据子组件类型定义好所有的按钮, 然后分别展示. 🌚
实现是可以实现, 但是十分的不优雅, 与子组件通信也麻烦😑
那有没有什么简单点的方法呢?
思路
众所周知, Vue组件实际上都是一个个Object, 自定义的组件事件(emits
)可以向父组件发送一个Object, 所以有没有可能通过向父组件emit一个组件Object的方式来实现这个场景呢?
经过试验, 单独定义一个组件确实可行, 但很多时候需要emit出去的组件, 可能只是几个按钮, 为几个按钮单独新建一个文件又很麻烦. 有没有什么简单的方式呢👀.
好了, 不卖关子了, 感谢 Anthony Fu 大佬在vueuse
中贡献的createReusableTemplate
, ,通过这个组件, 可以在template内定义局部可复用的组件, 将这个组件emit出去即可达到需要的效果.
Show me the code.
js
/// ChildCmp.vue
<template>
<DefineTemplate>
<div>我命由我不由天</div>
</DefineTemplate>
<div class="child-cmp">
没错我就是天.
</div>
</template>
<script setup lang="ts">
import { createReusableTemplate } from '@vueuse/core'
import { onMounted } from 'vue';
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
const emits = defineEmits(['showCmp']);
onMounted(()=>{
emits('showCmp', ReuseTemplate);
})
</script>
<style scoped>
.child-cmp {
width: 100px;
height: 100px;
line-height: 100px;
color: red;
background: gray;
text-align: center;
}
</style>
js
/// ParentView.vue
<template>
<div class='xjc_container'>
<div class="ParentView">
<span>什么不由天, 我是天外天</span>
<component v-if="extraCmp" :is="extraCmp"></component>
</div>
<ChildCmp @showCmp="handleShowCmp"></ChildCmp>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, nextTick } from 'vue';
import ChildCmp from './ChildCmp.vue';
const extraCmp = ref<any>();
function handleShowCmp(cmp: any) {
extraCmp.value = cmp;
}
</script>
<style scoped lang="scss">
.ParentView{
background: #7474ff;
width: 200px;
height: 200px;
color: white;
}
</style>
实现效果如下, 相信看到这里的都能明白这个trick的意义🌚