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"> 规章制度</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()">查看全部>></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"> 通知消息</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"> 规章制度</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()">查看全部>></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'
}
}
}
```
每种方式都有各自的使用场景,选用一种适合自己业务的即可。