vue 封装组件供全局使用_Vue如何封装高质量组件

依照MVC模式思想来解释高可复用性、低耦合性的组件定义方法

组件分类

级别从小到大:

  • 基础组件:只是一种宽泛的定义,可见场景较多,与业务无关的组件。比如列表、表格、输入框等,没有实际的UI,故不能直接使用
  • UI组件:与基础组件同级,为基础组件提供UI,仅仅跟样式和数据有关
  • 业务组件:与基础组件是一一对应的关系,与业务相关,具有实际的UI,是能够直接使用的组件的最小单位
  • 功能组件:也叫做模块组件。由多个业务组件和非组件代码组成的某个业务功能或者模块,仅仅是代码结构的一种划分,实际上没有层级的变化
  • 页面组件:路由级的组件,代表某个页面

基础组件相当于MVC中的Model,UI组件相当于View,业务组件 = 基础组件 + UI组件

组件继承

基础组件是可以实现继承的,“继承”是对组件定义的一种扩展。比如轮播图组件可以继承列表组件,因为它具有列表的一些性质。

定义一个组件的文件目录如下:

51517f7292f9b3ce0428ff125228d361.png

index.mixin.js是该基础组件的私有定义,在index.vue中通过mixin:[parentComp1, parentComp2..., selfComp]的方式实现继承。

实例

下面通过 豆瓣图书列表 的例子来定义这三个级别的组件:

基础组件定义

豆瓣图书列表这个业务功能抽象出的基础组件就是列表。 列表组件有两个prop:

  • 列表数据:类型是Array,数组项为每个列表项的数据对象(列表项数目可以通过一个computed属性来表示)
  • UI组件接口:每个基础组件都存在的接口,用于导入UI组件(这个prop在comp.base.mixin中定义)
  • meta:用于控制UI组件的元信息(可选)

代码

components/List/index.vue

<script>
    import base from '@lib/interface/comp.base.mixin' // 基础组件接口
    import selfComp from './index.mixin'

    export default {
        name: 'List',
        mixins: [base, selfComp] // 在selfComp前面加上父组件的定义mixin就可以实现继承
    }
</script>

index.mixin.js

// 基础组件定义
export default {
    props: {
        data: {
            // 列表数据
            type: Array,
            default: () => {
                /**
                * 数组项规范:
                * { anymore }
                */
                return []
            }
        }
    },
    computed: {
        // 数据总数
        dataTotal() {
            return this.data.length
        }
    }
}

comp.base.mixin.js

// 基础组件定义Mixin
export default {
    props: {
        ui: {
            // UI组件接口
            type: Object,
            default: () => {
                return null
            }
        },
        meta: {
            // 用于控制UI组件的元信息
            type: Object,
            default: () => {
                return {}
            }
        }
    },
    render: function(h) {
        let uiComponent = this.ui;
        if(uiComponent == null) {
            return h('div', '没有定义UI组件或不能直接调用!')
        }
        else {
            return h(uiComponent, {
                props: {
                    scope: this, // 将基础组件的数据和方法(实例)暴露给UI组件
                    meta: this.meta // 通过meta属性获取控制元信息
                }
            })
        }
    }
}

UI组件定义

为List基础组件提供UI。根据业务使用场景的不同,List可以有多种UI组件,在豆瓣图书列表这个例子中,UI组件就是BookList

代码

components/List/ui/book-list.vue

<style scoped>
...
</style>

<template>
    <div class="book-list">
        <!-- 通过scope访问基础组件的数据和方法 -->
        <div class="book-item" v-for="(item,index) in scope.data" :key="item.id">
            <img class="book-cover" :src="bookCoverUrls[index]" :alt="item.name">
            <div class="book-info">
                <a href="javascript:void(0)">
                    <h3 v-text="item.name"></h3>
                </a>
                <p class="book-rate">
                    <Rate show-text allow-half disabled v-model="item.score">
                        <span style="color: #f5a623" v-text="item.score"></span>
                    </Rate>
                </p>
                <p v-text="item.meta"></p>
            </div>
        </div>
    </div>
</template>

<script>
import ui from '@lib/comp.ui.mixin'

export default {
    name: 'BookList',
    mixins: [ui], // UI组件接口
    data() {
        return {
            bookCoverUrls: [ ... ]
        }
    }
}
</script>

comp.ui.mixin.js

// UI组件定义Mixin
export default {
    props: {
        scope: {
            type: Object,
            default: () => {
                return {}
            }
        },
        meta: {
            type: Object,
            default: () => {
                return {}
            }
        }
    }
}

组件调用

豆瓣图书列表 = List组件 + BookList组件

<template>
    <List :ui="comp.BookList" :data="bookList"/>
</template>

<script>
import List from '@c/List/index.vue'
import BookList from '@c/List/ui/book-list.vue'

export default {
    components: {
        List
    },
    data() {
        return {
            comp: {
                BookList
            },
            bookList: [
                {
                    id: 1,
                    name: '英国特工阿申登',
                    score: 4.6,
                    meta: '[英] 毛姆 著/理想国丨广西师范大学出版社/2019-1'
                },
                {
                    id: 2,
                    name: '建筑师',
                    score: 4.8,
                    meta: '(美) 大卫·马祖凯利/后浪 | 北京联合出版公司/2019-3'
                },
                {
                    id: 3,
                    name: '长长的回家路',
                    score: 4.5,
                    meta: '[瑞典] 弗雷德里克·巴克曼/北京联合出版社/2019-1'
                },
                {
                    id: 4,
                    name: '缓刑时刻',
                    score: 4.9,
                    meta: '[意]普里莫·莱维/中信出版集团/2019-1'
                }
            ]
        }
    }
}
</script>

效果

53f1491ea01e24e41f509c4c649eafb1.png
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值