vue 组件封装-逻辑与展示分离

vue 组件封装-逻辑与展示分离

在组件封装中,逻辑与展示的分离是一种常见的开发模式,它将组件的功能和样式分隔开来,使代码更具可读性、可维护性和可重用性,在统计与报表类场景中最为常见,往往是以不同主题或不同需求进行不同的展示,业务逻辑的代码一样展示效果不一样。以下是三种种常见的实现方式:

1. 继承

使用 extends 继承组件,这种方式的缺点就是 父组件的template和子组件template模板不能共存,只能选其一,如果要使用父级模板就子组件就不能要template,如果子组件要使用template模板,父组件的模板是继承不过来的,所以这种方式适用于只是页面不一样的的场景,让子组件去重写模板。

创建逻辑组件

javascript 复制代码
<template>
  <div class="fill-width fill-height flex1">
    <slot v-bind="thatData"></slot>
  </div>
</template>

<script>
export default {
    name:'rulesRegulaBase',
    data(){
        return {
            tableData: []
        }
    },
    computed:{
        thatData(){
            return this._data
        }
    },
    methods: {
        getPage() {
            const formSelectData = {
                simpleCondition: "",
                pageSize: 5,
                pageNumber: 1,
                sort: "createtime",
                order: "desc",
                sortS: "createtime",
                orderS: "desc"
            }
            this.$store.dispatch('specificationlistHelp',formSelectData).then(res => {
                this.tableData = res.data || []
            })
        },
        readMore(){
            const routeUrl = this.$router.resolve({ path: '/help/2' }).href;
            window.open(routeUrl, '_blank');
        },
        init(){
            this.getPage()
        }
    },
    mounted(){
        this.init()
    }
}
</script>

创建展示组件

javascript 复制代码
<template>
    <div class="flex1 height-200 hotContainer d-flex flex-col">
        <div class="hotTitle">
            <span>
                <svg-icon
                    class="primary--text text-fz-20 mr-1"
                    style="font-size: 25px !important"
                    text="notify"
                />
                <span class="titleText">&nbsp;&nbsp;规章制度</span>
            </span>
        </div>
        <div class="flex1 pa-2  overflow-auto">
            <ul class="minConentList">
                <li v-for="(item,index) in tableData" :key="index">
                    <div class="text-overflow-hidden">{{ item.title }}</div>
                </li>
            </ul>
        </div>
        <div class="height-40 con_bottom" @click="readMore()">查看全部&gt;&gt;</div>
    </div>
</template>

<script>
import rulesRegulaBase from '../../base/rulesRegulaBase'
export default {
    name:'rulesRegula',
    extends: rulesRegulaBase
}
</script>

2. 作用域插槽

使用 作用域插槽 插槽这种方式比较灵活,即可以在父组件复杂的逻辑,将需要不同展示的部分通过插槽的方式传入即可。

创建逻辑组件

Javascript 复制代码
<template>
  <div class="fill-width fill-height">
    <notice ref="noticeRef"/>
    <slot v-bind="thatData"></slot>
  </div>
</template>

<script>
import { getNoticeList } from '@/api/common/notice'
import notice from "@Work/notice"
export default {
    components: {
        notice
    },
    data(){
        return {
            noticeList: []
        }
    },
    computed:{
        thatData(){
            return this._data
        }
    },
    methods: {
        getTop10NoticeList(){
            getNoticeList().then(res => {
                this.noticeList = res.data || []
            })
        },
        readMore(){
            this.$refs.noticeRef.showDialog()
        },
        init(){
            this.getTop10NoticeList()
        }
    },
    mounted(){
        this.init()
    },

}
</script>

<style>

</style>

创建展示组件

Javascript 复制代码
<template>
    <notifiMessageBase ref="notifiMessageBaseRef">
        <template #default="{noticeList}">
            <div class="flex1 height-200 hotContainer d-flex flex-col minwidth-0">
                <div class="hotTitle">
                    <span>
                        <svg-icon
                            class="primary--text text-fz-20 mr-1"
                            style="font-size: 25px !important"
                            text="book"
                        />
                        <span class="titleText">&nbsp;&nbsp;通知消息</span>
                    </span>
                </div>
                <div class="flex1 pa-2 overflow-auto">
                    <ul class="minConentList">
                        <li v-for="(item,index) in noticeList" :key="index">
                            <div class="text-overflow-hidden">{{ item.title }}</div>
                        </li>
                    </ul>
                </div>
                <div class="height-40 con_bottom" @click="notifiMessageBaseRefObj.readMore()">查看全部>></div>
            </div>
        </template>
    </notifiMessageBase>
</template>

<script>
import notifiMessageBase from '../../base/notifiMessageBase'
export default {
    name:'notifiMessage',
    components: {
        notifiMessageBase
    },
    computed: {
        notifiMessageBaseRefObj(){
            return this.$refs.notifiMessageBaseRef
        }
    }
}
</script>

3. mixin混入

创建mixin.js

javascript 复制代码
<script>
export default {
    name:'rulesRegulaBase',
    data(){
        return {
            tableData: []
        }
    },
    computed:{
        thatData(){
            return this._data
        }
    },
    methods: {
        getPage() {
            const formSelectData = {
                simpleCondition: "",
                pageSize: 5,
                pageNumber: 1,
                sort: "createtime",
                order: "desc",
                sortS: "createtime",
                orderS: "desc"
            }
            this.$store.dispatch('specificationlistHelp',formSelectData).then(res => {
                this.tableData = res.data || []
            })
        },
        readMore(){
            const routeUrl = this.$router.resolve({ path: '/help/2' }).href;
            window.open(routeUrl, '_blank');
        },
        init(){
            this.getPage()
        }
    },
    mounted(){
        this.init()
    }
}
</script>

创建逻辑组件

javascript 复制代码
<template>
    <div class="flex1 height-200 hotContainer d-flex flex-col">
        <div class="hotTitle">
            <span>
                <svg-icon
                    class="primary--text text-fz-20 mr-1"
                    style="font-size: 25px !important"
                    text="notify"
                />
                <span class="titleText">&nbsp;&nbsp;规章制度</span>
            </span>
        </div>
        <div class="flex1 pa-2  overflow-auto">
            <ul class="minConentList">
                <li v-for="(item,index) in tableData" :key="index">
                    <div class="text-overflow-hidden">{{ item.title }}</div>
                </li>
            </ul>
        </div>
        <div class="height-40 con_bottom" @click="readMore()">查看全部&gt;&gt;</div>
    </div>
</template>

<script>
import rulesRegulaBase from '../../base/rulesRegulaBase'
export default {
    name:'rulesRegula',
    mixins: [rulesRegulaBase]
}
</script>

使用 v-if (不推荐)

这种方式简单,逻辑与展示都写在了同一个组件里了

language 复制代码
<template>
    <div class="flex1 height-200 hotContainer d-flex flex-col">
        <divclass="flex1 pa-2  overflow-auto" v-if="templateone">
           
        </div>
        <div class="flex1 pa-2  overflow-auto" v-if="templatetow">
            
        </div>
    </div>
</template>

<script>
export default {
    name:'rulesRegula',
    data(){
        return {
              templateType: 'templateone' 
        }
    }
}

每种方式都有各自的使用场景,选用一种适合自己业务的即可。

相关推荐
小郎君6585 小时前
Vue 多标签页的加载态设计:为什么我没有用 Suspense 实现 PageLoading
vue.js·算法
yilaisai5 小时前
前端开发遇到的一些细节问题整理
vue.js
华玥作者6 小时前
Vue 3 + TypeScript + uni-app 组件库推荐:hy-app(华玥组件库)
vue.js·typescript·uni-app
阿琳a_6 小时前
b-map-viewer:面向 Vue 3 的地图可视化 SDK,从接入到展示再到交互分析
前端·javascript·vue.js·gis·数据可视化·地图
齐 飞7 小时前
VUE2常用语法总结
javascript·vue.js
北城笑笑7 小时前
Vue 106 ,上篇:前端桌面端应用实现方案( Electron 框架详细介绍,Vue + Electron )
前端·javascript·vue.js·python·electron
不磕了还不行8 小时前
用 Vue + Element UI 把元宝搜索的返回值做成“能点开检查的证据卡片”
前端·vue.js·ui
FRing0319 小时前
vue2干货总结2(v-bind、v-for、v-model、指令修饰符、v-bind操作class和style)
开发语言·前端·vue.js·vue2
徐小夕1 天前
深度剖析 30k star 的编码 Agent DeepSeek-Reasonix:长会话 Token 成本直降 80%
前端·vue.js·github
ruanno_top1 天前
1 万行表格只渲染 18 行:虚拟滚动让我放弃了三个功能
vue.js