从AngularJS迁移到Vue,同一组件如何切换多套模板避免逻辑重复?
方案1:逻辑抽离 + 动态组件切换(最匹配AngularJS单controller多模板的使用习惯)
核心思路是把业务逻辑和视图层完全拆分,避免逻辑重复的同时解决模板臃肿问题:
- 抽离公共逻辑:
如果是Vue3,把组件内所有公共状态(如items)、业务方法(如loadObject/viewType等)全部抽为独立的可复用组合式函数(composable):
// composables/useDataList.js export default function useDataList() { const items = ref([]) // 原有所有业务逻辑、接口请求、计算属性、交互方法都保留在此处 const loadObject = (uid) => { /* 原有逻辑 */ } const viewType = (uid) => { /* 原有逻辑 */ } const expandOptions = (uid) => { /* 原有逻辑 */ } const analyze = (uid) => { /* 原有逻辑 */ } return { items, loadObject, viewType, expandOptions, analyze } }
如果是Vue2,把上述公共逻辑抽为mixin即可。
2. 编写独立视图组件:
每个视图只写对应模板,逻辑直接复用上述抽离的公共代码,无需重复编写:
<!-- components/TableView.vue --> <template> <table> <tr><td>Name</td><td>Type</td><td>Actions</td></tr> <tr v-for="item in items" :key="item.Uid"> <td @click="loadObject(item.Uid)">{{item.Name}}</td> <td @click="viewType(item.Uid)">{{item.Type}}</td> <td> <span @click="expandOptions(item.Uid)">Expand</span> <span @click="analyze(item.Uid)"></span> </td> </tr> </table> </template> <script setup> import useDataList from '@/composables/useDataList' const { items, loadObject, viewType, expandOptions, analyze } = useDataList() </script>
按同样方式编写ListView.vue,只替换模板部分即可。
3. 父组件通过动态组件实现一键切换:
<template> <div> <!-- 视图切换按钮 --> <button @click="toggleView">切换视图</button> <!-- 动态渲染当前选中的视图组件 --> <component :is="currentView" /> </div> </template> <script setup> import { ref } from 'vue' import TableView from '@/components/TableView.vue' import ListView from '@/components/ListView.vue' const currentView = ref('TableView') const toggleView = () => { currentView.value = currentView.value === 'TableView' ? 'ListView' : 'TableView' } </script>
方案2:模板片段拆分(不想拆分组件的轻量优化方案)
如果不想调整现有逻辑结构,只需要解决模板臃肿问题,可以把两个视图的代码单独抽为独立的模板片段文件,在主组件中引入即可:
- 新建
table-view.html和list-view.html,分别存放对应视图的模板代码 - 主组件模板通过构建工具的引入能力加载片段(Vite可使用
vite-plugin-html-include,Vue CLI可使用html-loader):
<template> <div> <div v-if="showTable"> <!-- @include ./table-view.html --> </div> <div v-if="showList"> <!-- @include ./list-view.html --> </div> </div> </template> <!-- 原有script逻辑完全不用改动 -->
方案3:作用域插槽封装(适合后续需扩展更多视图的场景)
如果后续还会新增卡片视图、缩略图视图等更多展示形式,可以把所有业务逻辑封装为容器组件,通过作用域插槽向外暴露状态和方法,完全自定义视图:
<!-- components/DataListContainer.vue --> <template> <!-- 把所有状态、方法通过插槽传给父组件 --> <slot :items="items" :loadObject="loadObject" :viewType="viewType" :expandOptions="expandOptions" :analyze="analyze" /> </template> <script setup> // 原有所有业务逻辑全部放在此处,无需改动 </script>
使用时直接在插槽内切换视图即可:
<template> <DataListContainer v-slot="slotProps"> <!-- 表格视图 --> <table v-if="showTable"> <tr v-for="item in slotProps.items" :key="item.Uid"> <td @click="slotProps.loadObject(item.Uid)">{{item.Name}}</td> <!-- 剩余表格代码 --> </tr> </table> <!-- 列表视图 --> <div v-else> <!-- 列表代码 --> </div> </DataListContainer> </template>
内容的提问来源于stack exchange,提问作者Gotts
相关产品推荐
相关产品推荐

