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 } }, 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,readMore}"> <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="readMore()">查看全部>></div> </div> </template> </notifiMessageBase> </template> <script> import notifiMessageBase from '../../base/notifiMessageBase' export default { name:'notifiMessage', components: { notifiMessageBase } } </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' } } } ``` 每种方式都有各自的使用场景,选用一种适合自己业务的即可。