• Vue组件封装如何实现逻辑与展示分离?
  • 发布于 2个月前
  • 250 热度
    0 评论
在组件封装中,逻辑与展示的分离是一种常见的开发模式,它将组件的功能和样式分隔开来,使代码更具可读性、可维护性和可重用性,在统计与报表类场景中最为常见,往往是以不同主题或不同需求进行不同的展示,业务逻辑的代码一样展示效果不一样。以下是三种种常见的实现方式:
1. 继承
使用 extends 继承组件,这种方式的缺点就是 父组件的template和子组件template模板不能共存,只能选其一,如果要使用父级模板就子组件就不能要template,如果子组件要使用template模板,父组件的模板是继承不过来的,所以这种方式适用于只是页面不一样的的场景,让子组件去重写模板。
创建逻辑组件:
<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>
创建展示组件:
<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. 作用域插槽
使用 作用域插槽 插槽这种方式比较灵活,即可以在父组件复杂的逻辑,将需要不同展示的部分通过插槽的方式传入即可。
创建逻辑组件:
<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>
创建展示组件:
<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
<script>
export default {
    name:'rulesRegulaBase',
    data(){
        return {
            tableData: [] 
            // 堆代码 duidaima.com
        }
    },
    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>
创建逻辑组件:
<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 (不推荐)
这种方式简单,逻辑与展示都写在了同一个组件里了
<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' 
        }
    }
}
每种方式都有各自的使用场景,选用一种适合自己业务的即可。
用户评论