JxlDescription 信息描述
满足开发者采用配置的方式,快速搭建信息描述的需求。
基于 ElementUI 的 el-row 和 el-col 标签封装。
<template>
<div class="description-list">
<template v-if="group">
<div v-for="(groupItem, key) in items" :key="key" :class="['description-group', indent ? '' : 'no-indent']">
<div class="description-group-title">{{ groupItem.title }}</div>
<div class="description-group-items">
<el-row v-bind="layout.row">
<el-col v-for="(item, index) in groupItem.items" :key="index" v-bind="layout.col">
<jxl-description-item
v-if="itemVisible(item)"
:item="item"
:colon="colon"
:prop="prop"
:data="data"
:layout="layout"
:ellipsis="ellipsis"
:label-width="labelWidth"
:label-align="labelAlign"
:label-direction="labelDirection"
>
<template v-if="_typeof(item.slotName) === String && $scopedSlots[item.slotName]" v-slot:content>
<slot :name="item.slotName" :row="item" />
</template>
</jxl-description-item>
</el-col>
</el-row>
</div>
</div>
</template>
<template v-else>
<el-row v-bind="layout.row">
<el-col v-for="(item, index) in items" :key="index" v-bind="layout.col">
<jxl-description-item
v-if="itemVisible(item)"
:item="item"
:colon="colon"
:prop="prop"
:data="data"
:layout="layout"
:ellipsis="ellipsis"
:label-width="labelWidth"
:label-align="labelAlign"
:label-direction="labelDirection"
>
<template v-if="_typeof(item.slotName) === String && $scopedSlots[item.slotName]" v-slot:content>
<slot :name="item.slotName" :row="item" />
</template>
</jxl-description-item>
</el-col>
</el-row>
</template>
</div>
</template>
<script>
import JxlDescriptionItem from '@/components/libs/Description/JxlDescriptionItem'
import mixin from '@/components/libs/mixin'
import { _typeof } from '@/components/libs/util'
export default {
name: 'JxlDescription',
components: { JxlDescriptionItem },
mixins: [mixin],
props: {
/**
* 数据项名称固定宽度
*/
labelWidth: {
type: String,
default: undefined
},
/**
* 数据项名称对齐方式
* 可选值:left、right、center
*/
labelAlign: {
type: String,
default: 'left'
},
/**
* 数据项名称摆放方向
* 可选值:row、column
*/
labelDirection: {
type: String,
default: 'row'
},
/**
* 数据来源是否是 prop
*/
prop: {
type: Boolean,
default: true
},
/**
* 是否显示冒号
*/
colon: {
type: Boolean,
default: true
},
/**
* 分组模式下标题与子项缩进
*/
indent: {
type: Boolean,
default: true
},
/**
* 是否限制内容行数,超出的部分内容省略
* 0 表示不限制;正整数表示限制的行数
*/
ellipsis: {
type: Number,
default: 0
},
/**
* 是否是分组展示
*/
group: {
type: Boolean,
default: false
},
/**
* 布局
*/
layout: {
type: Object,
default: () => {
return {}
}
},
/**
* 数据项
*/
items: {
type: [Object, Array],
default: () => {
return {}
},
required: true
},
/**
* 数据来源
*/
data: {
type: Object,
default: () => {
return {}
}
}
},
data() {
return {}
},
methods: {
/**
* 描述可见
*/
itemVisible(item) {
if (_typeof(item.hidden) === Function) return !item.hidden()
return !item.hidden
}
}
}
</script>
<style lang="less" scoped>
.description-list {
.description-group {
margin-bottom: 24px;
&:last-child {
margin-bottom: 0;
}
&.no-indent {
.description-group-title {
padding-left: 0;
&:before {
display: none;
}
}
.description-group-items {
padding-left: 0;
}
}
.description-group-title {
position: relative;
white-space: nowrap;
text-overflow: ellipsis;
color: #303233;
font-weight: 600;
font-size: 16px;
line-height: 1.5;
padding-left: 12px;
margin-bottom: 20px;
&:before {
display: block;
content: '';
position: absolute;
left: 0;
top: 3px;
width: 2px;
height: 13px;
background-color: #1890ff;
}
}
.description-group-items {
padding-left: 12px;
}
}
/deep/ .el-col:last-of-type {
.description-item {
margin-bottom: 0 !important;
}
}
}
</style>
JxlDescriptionItem 信息描述项
满足开发者采用配置的方式,快速搭建信息描述的需求。
基于 自封组件的 jxl-tip 和 jxl-ellipsis 标签封装。
<template>
<div class="description-item" :class="hasLabelDirection" v-bind="item.itemAttrs">
<div :class="['description-item__label', hasColon ? 'has-colon' : '']" :style="{ width: labelWidth ? labelWidth : undefined, textAlign: labelAlign ? labelAlign : undefined }" v-bind="item.labelAttrs">
<!-- 条目名称 -->
<span>{{ item.label }}</span>
<!-- 条目提示符 -->
<jxl-tip v-if="item.tip" :options="item.tip" />
</div>
<div class="description-item__value" :style="item.valueStyle" v-bind="item.valueAttrs">
<!-- 自定义插槽 -->
<template v-if="_typeof(item.slotName) === String && $scopedSlots['content']"><slot name="content" /></template>
<!-- 自定义组件 -->
<component :is="item.component" v-else-if="_typein(item.component, [String, Object])" v-bind="item.attrs" v-on="item.events" />
<!-- 省略文本 -->
<jxl-ellipsis v-else-if="hasEllipsis" :line="getEllipsis" :text="renderItem()" />
<!-- 普通文本 -->
<template v-else>{{ renderItem() }}</template>
</div>
</div>
</template>
<script>
import JxlTip from '@/components/libs/Tip/JxlTip'
import mixin from '@/components/libs/mixin'
import JxlEllipsis from '@/components/libs/Ellipsis/JxlEllipsis'
export default {
name: 'JxlDescriptionItem',
components: { JxlEllipsis, JxlTip },
mixins: [mixin],
props: {
/**
* 数据项名称固定宽度
*/
labelWidth: {
type: String,
default: undefined
},
/**
* 数据项名称对齐方式
* 可选值:left、right、center
*/
labelAlign: {
type: String,
default: undefined
},
/**
* 数据项名称摆放方向
* 可选值:row、column
*/
labelDirection: {
type: String,
default: 'row'
},
/**
* 数据来源是否是 prop
*/
prop: {
type: Boolean,
default: false
},
/**
* 是否显示冒号
*/
colon: {
type: Boolean,
default: true
},
/**
* 是否限制内容行数,超出的部分内容省略
* 0 表示不限制;正整数表示限制的行数
*/
ellipsis: {
type: Number,
default: 0
},
/**
* 布局
*/
layout: {
type: Object,
default: () => {
return {}
}
},
/**
* 数据项
*/
item: {
type: Object,
default: () => {
return {}
}
},
/**
* 数据来源
*/
data: {
type: Object,
default: () => {
return {}
}
}
},
computed: {
/**
* 是否需要冒号
* @returns {boolean|*}
*/
hasColon() {
if (this._typeof(this.item.colon) === Boolean) return this.item.colon
return this.colon
},
/**
* 获取是否需要省略
* @returns {boolean}
*/
hasEllipsis() {
if (this._typeof(this.item.ellipsis) === Number && this.item.ellipsis > 0) return true
return this._typeof(this.ellipsis) === Number && this.ellipsis > 0
},
/**
* 获取省略的行数
* @returns {number}
*/
getEllipsis() {
if (this._typeof(this.item.ellipsis) === Number) return this.item.ellipsis
if (this._typeof(this.ellipsis) === Number) return this.ellipsis
return 0
},
/**
* 数据项名称摆放方向
*/
hasLabelDirection() {
if (this._typeof(this.item.labelDirection) === String) {
if (this.item.labelDirection === 'column') return 'description-item-direction-column'
return 'description-item-direction-row'
}
if (this.labelDirection === 'column') return 'description-item-direction-column'
return 'description-item-direction-row'
}
},
methods: {
/**
* 渲染数据项
*/
renderItem() {
if (this._typeof(this.item.render) === Function) {
return this.friendly(this.item.render(this.getItemValue()), this.isVoid(this.item.void) ? '-' : this.item.void)
}
return this.friendly(this.getItemValue(), this.isVoid(this.item.void) ? '-' : this.item.void)
},
/**
* 获取数据项值
* @returns {*}
*/
getItemValue() {
if (this.prop) return this._get(this.data, this.item.prop)
return this.item.value
}
}
}
</script>
<style lang="less" scoped>
.description-item {
display: flex;
line-height: 1.5;
margin-bottom: 20px;
&.description-item-direction-row {
flex-direction: row;
.description-item__label {
margin-right: 16px;
}
}
&.description-item-direction-column {
flex-direction: column;
.description-item__label {
margin-bottom: 8px;
}
}
.description-item__label {
color: #606366;
font-size: 14px;
line-height: 22px;
flex-shrink: 0; // 当宽度不足时,babel不能被挤压
&.has-colon {
margin-right: 8px;
padding-right: 4px;
&:after {
content: ":";
position: relative;
left: 4px;
top: -1px;
font-weight: 600;
}
}
}
.description-item__value {
flex: 1;
color: #303233;
line-height: 22px;
font-size: 14px;
}
}
</style>