Vue3 跨组件渲染模板

Vue3 跨组件渲染模板

现在有个需求,就是页面中某个组件渲染的时候动态改变另一个组件的某个部分。

下面是简化后的页面,页面有个 Header,内容中有个按钮可以切换两个组件。

代码也很简单:

html 复制代码
<!-- App.vue -->
<template>
    <div class="app">
        <header />
        <div class="app-content">
            <el-button @click="flag = !flag" type="primary">切换组件</el-button>
            <ComA v-if="flag" />
            <ComB v-else />
        </div>
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Header from './components/Header.vue'
import ComA from './components/ComA.vue'
import ComB from './components/ComB.vue'
const flag = ref(true)
</script>

现在是要当 A组件 渲染的时候,标题显示 A 组件 ,当 B组件 渲染的时候,标题显示 B 组件。

如果你使用过或者开发过微信小程序应该知道,当切换到某个页面的时候,小程序顶部的标题是可以改变的,在小程序中这是通过配置文件实现的。那么在网页端中怎么做呢?

下面给出两种方法。

方法 1:Teleport 组件

如果你学过 Vue3,应该已经想到了这个方案,就是在组件 AB 中使用 Vue3 的内置组件Teleport把模板渲染到 Header 当中去。

html 复制代码
<!-- ComA.vue -->
<template>
    <div class="com-a">
        这是页面A
        <Teleport to=".header .main">
            <div>A页面</div>
        </Teleport>
    </div>
</template>

<script setup lang="ts"></script>

这样大部分需求都解决了,但还是有些问题,就是不够灵活,比如标题有默认内容时,用 Teleport 组件会往后面插入内容,这就不是很好解决了。

方法 2:借助变量

大概思路就是,拿到要渲染的模板的虚拟DOM,保存到一个变量中,在 Header 中使用 component 组件渲染。

为了方便我们可以自定义一个组件,写在该组件的内容会保存在某个地方,并什么都不渲染。

ts 复制代码
// helper.ts
import { SetupContext, Slots, defineComponent, ref } from 'vue'
// 用来保存虚拟DOM的变量
const content = ref<Slots | null>(null)
// 自定义组件,使用该组件时,组件内的所有内容会被保存到变量content当中,原地什么都不渲染
const HeaderContent = defineComponent((_props: any, ctx: SetupContext) => {
    content.value = ctx.slots
    // 返回什么都不渲染的render函数
    return () => null
})
export { content, HeaderContent }

这逻辑就是这么简单。接下来只要在Header中使用component组件渲染刚才被保存下来的虚拟DOM的内容即可,并且你可以自己做一些逻辑判断,加默认内容等等。

html 复制代码
<!-- Header.vue -->
<template>
    <div class="header">
        <div class="left">
            <img :src="logoVue" alt="" />
        </div>
        <div class="main">
            <span v-if="!defaultCom">默认内容</span>
            <component v-else :is="defaultCom" />
        </div>
        <div class="right">
            <el-button type="primary">按钮</el-button>
        </div>
    </div>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { content } from '../utils/helper'
import logoVue from '@/assets/vue.svg'

const defaultCom = computed(() => {
    if (!content.value || (content.value && !content.value.default)) return
    return content.value.default
})
</script>

接下来只要使用自定义组件就可以了,内容的逻辑全部写在ComA中,但实际渲染会渲染在Header中,还支持响应式数据,这就是我们想要的。

html 复制代码
<!-- ComA.vue -->
<template>
    <div class="com-a">
        这是页面A
        <el-button type="primary" @click="num++">增加</el-button>
        <HeaderContent>
            <div>A页面{{ num }}</div>
        </HeaderContent>
    </div>
</template>

<script setup lang="ts">
    import { ref } from 'vue'
    import { HeaderContent } from '../utils/helper'
    const num = ref(0)
</script>

看看效果

好了,思路提供给大家了,接下来要怎么玩你们自己决定吧。

相关推荐
吃乔巴的糖7 小时前
Vue 3 打印模板设计器 (print-canvas-designer)
前端·vue.js
如果超人不会飞11 小时前
后端别再手绘了!TinyVue 流程图组件 Flowchart 跨端定制指南
vue.js
cc.ChenLy11 小时前
大文件断点续传原理总结和Demo示例详解
javascript·vue.js·文件上传·大文件断点续传
程序员祥云11 小时前
VUE2_TO_VITE_VUE3
javascript·vue.js·ecmascript
苏瞳儿12 小时前
vue3+pinia+mqtt实时响应连接
前端·javascript·vue.js
i220818 Faiz Ul12 小时前
理财系统|基于java+vue的家庭理财系统小程序(源码+数据库+文档)
java·vue.js·spring boot·小程序·论文·毕设·理财系统
暗冰ཏོ13 小时前
《2026 Vue2 + Vue3 完整学习指南:基础语法、路由缓存、登录拦截、项目实战与面试题》
前端·vue.js·vue·vue3·vue2
幸运小圣13 小时前
动态表格在 Vue 3 中的实现指南【前端】
前端·javascript·vue.js
SwJieJie13 小时前
Day 3|表格表单分页范式与 vue-request 最佳实践:从配置驱动到业务落地
前端·javascript·vue.js
沙漠14 小时前
Mock Server 中间件
vue.js·webpack