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' 
        }
    }
}

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

相关推荐
徐小夕8 小时前
100小时,我做了一款AI CAD建模软件,开源!
前端·vue.js·github
淸湫10 小时前
项目中使用了全局权限管理,请详细描述如何通过Vue Router的路由守卫来实现全局权限控制?
前端·vue.js
李剑一10 小时前
前端必看 | Vue 刷新页面,生命周期钩子直接 "罢工",原来问题在这?90% 开发者都栽过!
前端·vue.js
閞杺哋笨小孩10 小时前
域名驱动多租户入驻:后台配置 + 前端解析
前端·vue.js
用户1257585243612 小时前
写了三年定时任务还在手改 Cron 表达式?这个 GoFrame 后台框架帮你全闭环了
vue.js
前端那点事12 小时前
Vue3自定义Hooks保姆级教程!从原理到企业级实战,告别混乱代码
前端·vue.js
前端那点事12 小时前
别再乱用Vue3响应式!ref、reactive、toRef、toRefs完整区别+企业级落地实战
前端·vue.js
閞杺哋笨小孩12 小时前
从脚手架到构建注入:Vue 多租户「入驻」工程实践
vue.js·vite
卤蛋fg614 小时前
VxeTable 实现表尾合计行并支持数据实时统计
vue.js
杨大厨wd14 小时前
Vue3 业务组件封装别只会传 props:如何设计一个真正好用的组件
vue.js