Vue Element UI自定义描述列表组件

本文实例为大家分享了Vue Element UI自定义描述列表组件的具体代码,供大家参考,具体内容如下

效果图

写在前面

写后台管理经常从列表点击查看详情,展示数据信息,Element UI虽然有表格组件,但是描述组件并没有,之前团队的成员遇到这种情况都自己去写样式,写起来也麻烦,而且每个人写出来的样式也不统一,破坏了项目的整体风格。

像是Ant Design UI就有描述组件,用起来特别舒服,所以索性自己结合Element UI的el-row和el-col自己写了一个。

实现哪些功能

1、每行的高度根据改行中某一列的最大高度自动撑开

2、列宽度自动补全,避免最后一列出现残缺的情况

3、支持纯文本与HTML插槽

4、支持每行几列的设置

5、支持每列宽度自定义

6、支持动态数据重绘

组件设计

1、使用父子组件嵌套实现,父组件为 e-desc, 子组件为 e-desc-item 。

2、e-desc-item传递props的label 和 插槽的value,使用 $slots.content来显示DOM

3、利用 el-row 和 el-col 来实现整体组件布局

封装e-desc组件

<template>

<div class="desc" :style="{margin}">

<!-- 标题 -->

<h1 v-if="title" class="desc-title" v-html="title"></h1>

<el-row class="desc-row">

<slot/>

</el-row>

</div>

</template>

<script>

export default {

name: 'EDesc',

// 通过provide提供给子组件

provide () {

return {

labelWidth: this.labelWidth,

column: this.column,

size: this.size

}

},

props: {

// 数据源,监听数据重绘

data: {

type: Object,

required: true,

default () {

return {}

}

},

// 标题

title: {

type: String,

default: ''

},

// 边距

margin: {

type: String,

default: '0'

},

// label宽度

labelWidth: {

type: String,

default: '120px'

},

column: {

// 每行显示的项目个数

type: [Number, String],

default: 3

},

size: {

// 大小

type: String,

default: ''

}

},

watch: {

data: {

handler () {

this.$nextTick(() => {

// 筛选出子组件e-desc-item

const dataSource = this.$slots.default

const dataList = []

dataSource.forEach(item => {

if (item.componentOptions && item.componentOptions.tag === 'e-desc-item') {

dataList.push(item.componentInstance)

}

})

// 剩余span

let leftSpan = this.column

const len = dataList.length

dataList.forEach((item, index) => {

// 处理column与span之间的关系

// 剩余的列数小于设置的span数

const hasLeft = leftSpan <= (item.span || 1)

// 当前列的下一列大于了剩余span

const nextColumnSpan = (index < (len - 1)) && (dataList[index + 1].span >= leftSpan)

// 是最后一行的最后一列

const isLast = index === (len - 1)

if (hasLeft || nextColumnSpan || isLast) {

// 满足以上条件,需要自动补全span,避免最后一列出现残缺的情况

item.selfSpan = leftSpan

leftSpan = this.column

} else {

leftSpan -= item.span || 1

}

})

})

},

deep: true,

immediate: true

}

}

}

</script>

<style scoped lang="scss">

.desc{

.desc-title {

margin-bottom: 10px;

color: #333;

font-weight: 700;

font-size: 16px;

line-height: 1.5715;

}

.desc-row{

display: flex;

flex-wrap: wrap;

border-radius: 2px;

border: 1px solid #EBEEF5;

border-bottom: 0;

border-right: 0;

width: 100%;

}

}

</style>

封装e-desc-item组件

<template>

<el-col :span="computedSpan" class="desc-item">

<div class="desc-item-content" :class="size">

<label class="desc-item-label" :style="{width: labelWidth}" v-html="label"></label>

<div class="desc-item-value" v-if="$slots">

<!-- 纯文本 -->

<slot v-if="$slots.default && $slots.default[0].text"/>

<!-- HTML -->

<slot name="content" v-else-if="$slots.content"/>

<span v-else>暂无数据</span>

</div>

</div>

</el-col>

</template>

<script>

export default {

name: 'EDescItem',

inject: ['labelWidth', 'column', 'size'],

props: {

span: {

type: [Number, String],

required: false,

default: 0

},

label: {

type: String,

required: false,

default: ''

}

},

data () {

return {

// 子组件自己的span

selfSpan: 0

}

},

computed: {

computedSpan () {

// 子组件自己的span,用于父组件计算修改span

if (this.selfSpan) {

return 24 / this.column * this.selfSpan

} else if (this.span) {

// props传递的span

return 24 / this.column * this.span

} else {

// 未传递span时,取column

return 24 / this.column

}

}

}

}

</script>

<style scoped lang="scss">

.desc-item {

border-right: 1px solid #EBEEF5;

border-bottom: 1px solid #EBEEF5;

.desc-item-content {

display: flex;

justify-content: flex-start;

align-items: center;

color: rgba(0,0,0,.65);

font-size: 14px;

line-height: 1.5;

width: 100%;

background-color: #fafafa;

height: 100%;

.desc-item-label{

border-right: 1px solid #EBEEF5;

display: inline-block;

padding: 12px 16px;

flex-grow: 0;

flex-shrink: 0;

color: rgba(0, 0, 0, 0.6);

font-weight: 400;

font-size: 14px;

line-height: 1.5;

height: 100%;

display: flex;

align-items: center;

}

.desc-item-value{

background: #fff;

padding: 12px 16px;

flex-grow: 1;

overflow: hidden;

word-break: break-all;

height: 100%;

display: flex;

align-items: center;

color: #444;

span{

color: #aaa;

}

}

&.small {

.desc-item-label,

.desc-item-value {

padding: 10px 14px;

}

}

}

}

</style>

使用方式

<template>

<e-desc :data='info' margin='0 12px' label-width='100px'>

<e-desc-item label="姓名">{{info.name}}</e-desc-item>

<e-desc-item label="年龄">{{ info.age }}岁</e-desc-item>

<e-desc-item label="性别">{{ info.sex }}</e-desc-item>

<e-desc-item label="学校">{{ info.school }}</e-desc-item>

<e-desc-item label="专业">{{ info.major }}</e-desc-item>

<e-desc-item label="爱好">{{ info.hobby }}</e-desc-item>

<e-desc-item label="手机号">{{ info.phone }}</e-desc-item>

<e-desc-item label="微信">{{ info.wx }}</e-desc-item>

<e-desc-item label="QQ">{{ info.qq }}</e-desc-item>

<e-desc-item label="住址">{{ info.address }}</e-desc-item>

<e-desc-item label="自我描述" :span='2'>{{ info.intro }}</e-desc-item>

<e-desc-item label="操作" :span='3'>

<template slot="content">

<el-button size="small" type="primary">修改</el-button>

<el-button size="small" type="danger">删除</el-button>

</template>

</e-desc-item>

</e-desc>

</template>

<script>

import EDesc from './e-desc'

import EDescItem from './e-desc-item'

export default {

components: {

EDesc, EDescItem

},

data () {

return {

info: {

name: 'Jerry',

age: 26,

sex: '男',

school: '四川大学',

major: '码农专业',

address: '四川省成都市',

hobby: '搬砖、前端、赚钱',

phone: 18888888888,

wx: 'Nice2cu_Hu',

qq: 332983810,

intro: '我是一个粉刷匠,粉刷本领强。我要把那新房子,刷得更漂亮。刷了房顶又刷墙,刷子飞舞忙。哎呀我的小鼻子,变呀变了样。我是一个粉刷匠,粉刷本领强。我要把那新房子,刷得更漂亮。刷了房顶又刷墙,刷子飞舞忙。哎呀我的小鼻子,变呀变了样。'

}

}

}

}

</script>

参数说明

至此,代码就写完啦,考虑不周或者有bug的地方,还望多多留言告知我哟

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

以上是 Vue Element UI自定义描述列表组件 的全部内容, 来源链接: utcz.com/p/220509.html

回到顶部