包含两种组件:Descriptions
和 DescriptionsItem
(必须搭配使用!)
效果如下图:在线预览
APIs
Descriptions
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
title | 描述列表的标题,显示在最顶部 | string | slot | undefined |
extra | 描述列表的操作区域,显示在右上方 | string | slot | undefined |
bordered | 是否展示边框 | boolean | false |
vertical | 是否使用垂直描述列表 | boolean | false |
size | 设置列表的大小 | ‘default’ | ‘middle’ | ‘small’ | ‘default’ |
column | 一行的 DescriptionItems 数量,可以写成数值或支持响应式的对象写法 { xs: 8, sm: 16, md: 24 } | number | Responsive | {xs: 1, sm: 2, md: 3} |
labelStyle | 自定义标签样式,优先级低于 DescriptionItems 的 labelStyle | CSSProperties | {} |
contentStyle | 自定义内容样式,优先级低于 DescriptionItems 的 contentStyle | CSSProperties | {} |
Responsive Type
名称 | 说明 | 类型 | 默认值 |
---|---|---|---|
xs | <576px 响应式栅格 | number | undefined |
sm | ≥576px 响应式栅格 | number | undefined |
md | ≥768px 响应式栅格 | number | undefined |
lg | ≥992px 响应式栅格 | number | undefined |
xl | ≥1200px 响应式栅格 | number | undefined |
xxl | ≥1600px 响应式栅格 | number | undefined |
DescriptionsItem
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
label | 内容的描述标签 | string | slot | undefined |
span | 包含列的数量,当使用水平列表且未设置 span 时等效于 span: 1 ,但最后一行的最后一项,会包含该行剩余的所有列数 | number | undefined |
labelStyle | 自定义标签样式,优先级高于 Description 的 labelStyle | CSSProperties | {} |
contentStyle | 自定义内容样式,优先级高于 Description 的 contentStyle | CSSProperties | {} |
其中引入使用了以下工具函数:
创建 Descriptions.vue 组件
<script setup lang="ts">
import { computed, nextTick, ref, watch, onMounted } from 'vue'
import type { CSSProperties } from 'vue'
import { throttle, useEventListener, useMutationObserver, useSlotsExist } from '../utils'
interface Responsive {
xs?: number // <576px 响应式栅格
sm?: number // ≥576px 响应式栅格
md?: number // ≥768px 响应式栅格
lg?: number // ≥992px 响应式栅格
xl?: number // ≥1200px 响应式栅格
xxl?: number // ≥1600px 响应式栅格
}
interface Props {
title?: string // 描述列表的标题,显示在最顶部 string | slot
extra?: string // 描述列表的操作区域,显示在右上方 string | slot
bordered?: boolean // 是否展示边框
vertical?: boolean // 是否使用垂直描述列表
size?: 'default' | 'middle' | 'small' // 设置列表的大小
column?: number | Responsive // 一行的 DescriptionItems 数量,可以写成数值或支持响应式的对象写法 { xs: 8, sm: 16, md: 24 }
labelStyle?: CSSProperties // 自定义标签样式,优先级低于 DescriptionItems 的 labelStyle
contentStyle?: CSSProperties // 自定义内容样式,优先级低于 DescriptionItems 的 contentStyle
}
const props = withDefaults(defineProps<Props>(), {
title: undefined,
extra: undefined,
bordered: false,
vertical: false,
size: 'default',
column: () => ({ xs: 1, sm: 2, md: 3 }),
labelStyle: () => ({}),
contentStyle: () => ({})
})
const defaultSlotsRef = ref() // 所有渲染的 DescriptionsItems 节点引用
const defaultSlots = ref(true) // 用于刷新 <slot></slot>
const observer = ref() // defaultSlotsRef 监听器
const stopObservation = ref(true) // 停止观察器
const children = ref<any[]>() // DescriptionsItems 节点
const tdCols = ref() // 放置 DescriptionsItems 节点的模板引用数组
const thVerticalCols = ref() // 放置垂直列表的 DescriptionsItems 节点的 th 模板引用数组
const tdVerticalCols = ref() // 放置垂直列表的 DescriptionsItems 节点的 td 模板引用数组
const trBorderedRows = ref() // 放置 DescriptionsItems 节点的模板引用数组(带边框)
const thVerticalBorderedRows = ref() // 放置垂直列表的 DescriptionsItems 节点的 th 模板引用数组(带边框)
const tdVerticalBorderedRows = ref() // 放置垂直列表的 DescriptionsItems 节点的 td 模板引用数组(带边框)
const groupItems = ref<any[]>([]) // 处理后的 DescriptionsItems 节点数组
const viewportWidth = ref(window.innerWidth)
function getViewportWidth() {
viewportWidth.value = window.innerWidth
}
const throttleEvent = throttle(getViewportWidth, 100)
useEventListener(window, 'resize', throttleEvent)
const slotsExist = useSlotsExist(['title', 'extra'])
const showHeader = computed(() => {
return slotsExist.title || slotsExist.extra || props.title || props.extra
})
const responsiveColumn = computed(() => {
if (typeof props.column === 'object') {
if (viewportWidth.value >= 1600 && props.column.xxl) {
return props.column.xxl
}
if (viewportWidth.value >= 1200 && props.column.xl) {
return props.column.xl
}
if (viewportWidth.value >= 992 && props.column.lg) {
return props.column.lg
}
if (viewportWidth.value >= 768 && props.column.md) {
return props.column.md
}
if (viewportWidth.value >= 576 && props.column.sm) {
return props.column.sm
}
if (viewportWidth.value < 576 && props.column.xs) {
return props.column.xs
}
return 1
}
return props.column
})
watch(
() => [props.bordered, props.vertical, responsiveColumn.value, props.labelStyle, props.contentStyle],
() => {
if (!stopObservation.value) {
stopObservation.value = true
}
refreshDefaultSlots()
},
{
deep: true
}
)
// 监听 defaultSlotsRef DOM 节点数量变化,重新渲染 Descriptions
observer.value = useMutationObserver(
defaultSlotsRef,
(MutationRecord: MutationRecord[]) => {
if (!stopObservation.value) {
stopObservation.value = true
const mutation = MutationRecord.some((mutation: any) => mutation.type === 'childList')
if (mutation) {
refreshDefaultSlots()
}
}
},
{ childList: true, attributes: true, subtree: true }
)
onMounted(() => {
getGroupItems()
})
async function refreshDefaultSlots() {
defaultSlots.value = !defaultSlots.value
await nextTick()
getGroupItems()
}
// 计算当前 group 中所有 span 之和
function getTotalSpan(group: any): number {
return group.reduce((accumulator: number, currentValue: any) => accumulator + currentValue.span, 0)
}
// 根据不同 cloumn 处理 DescriptionsItems 节点
async function getGroupItems() {
children.value = Array.from(defaultSlotsRef.value.children).filter((element: any) => {
return element.className === (props.bordered ? 'descriptions-item-bordered' : 'descriptions-item')
})
if (groupItems.value.length) {
groupItems.value.splice(0) // 清空列表
await nextTick()
}
if (children.value && children.value.length) {
const len = children.value.length
let group: any[] = []
for (let n = 0; n < len; n++) {
const item = {
span: Math.min(children.value[n].dataset.span ?? 1, responsiveColumn.value),
element: children.value[n]
}
if (getTotalSpan(group) < responsiveColumn.value) {
// 已有 items 的 totalSpan < column
item.span = Math.min(item.span, responsiveColumn.value - getTotalSpan(group))
group.push(item)
} else {
groupItems.value.push(group)
group = [item]
}
}
// 当使用水平列表且未设置 span 时等效于 span: 1,但最后一行的最后一项,会包含该行剩余的所有列数
if (!props.vertical && !children.value[len - 1].dataset.span && getTotalSpan(group) < responsiveColumn.value) {
const groupLen = group.length
group[groupLen - 1].span = group[groupLen - 1].span + responsiveColumn.value - getTotalSpan(group)
}
groupItems.value.push(group)
await nextTick()
updateDescriptions()
} else {
stopObservation.value = false
}
}
async function updateDescriptions() {
if (props.bordered) {
// 带边框列表
groupItems.value.forEach((items: any, index: number) => {
// 每一行 tr
items.forEach((item: any) => {
const itemChildren: any[] = Array.from(item.element.children)
// 创建节点副本,否则原节点将先被移除,后插入到新位置,影响后续响应式布局计算
const th = itemChildren[0]
// 动态添加节点样式
setStyle(th, props.labelStyle)
const td = itemChildren[1]
// 动态添加节点样式
setStyle(td, props.contentStyle)
// 插入节点到指定位置
if (props.vertical) {
// 垂直列表
th.colSpan = item.span
td.colSpan = item.span
thVerticalBorderedRows.value[index].appendChild(th)
tdVerticalBorderedRows.value[index].appendChild(td)
} else {
th.colSpan = 1
td.colSpan = item.span * 2 - 1
trBorderedRows.value[index].appendChild(th)
trBorderedRows.value[index].appendChild(td)
}
})
})
} else {
;(children.value as any[]).forEach((element: any, index: number) => {
const elementChildren: any[] = Array.from(element.children)
const label = elementChildren[0]
// 动态添加节点样式
setStyle(label, props.labelStyle)
const content = elementChildren[1]
// 动态添加节点样式
setStyle(content, props.contentStyle)
// 插入节点到指定位置
if (props.vertical) {
// 垂直列表
thVerticalCols.value[index].appendChild(element.firstChild)
tdVerticalCols.value[index].appendChild(element.lastChild)
} else {
tdCols.value[index].appendChild(element)
}
})
}
await nextTick()
stopObservation.value = false
}
// 为元素添加内联样式
function setStyle(element: any, styles: any) {
if (JSON.stringify(styles) !== '{}') {
Object.keys(styles).forEach((key: string) => {
if (!element.style[key]) {
element.style[key] = styles[key]
}
})
}
}
</script>
<template>
<div class="m-descriptions" :class="`descriptions-${size}`">
<div class="m-descriptions-header" v-if="showHeader">
<div class="descriptions-title">
<slot name="title">{{ title }}</slot>
</div>
<div class="descriptions-extra">
<slot name="extra">{{ extra }}</slot>
</div>
</div>
<div v-if="!vertical" class="m-descriptions-view" :class="{ 'descriptions-bordered': bordered }">
<table>
<tbody v-if="!bordered">
<tr v-for="(items, row) in groupItems" :key="row">
<td
ref="tdCols"
class="descriptions-item-td"
:colspan="item.span"
v-for="(item, col) in items"
:key="col"
></td>
</tr>
</tbody>
<tbody v-else>
<tr ref="trBorderedRows" class="descriptions-bordered-tr" v-for="row of groupItems.length" :key="row"></tr>
</tbody>
</table>
</div>
<div v-else class="m-descriptions-view" :class="{ 'descriptions-bordered': bordered }">
<table>
<tbody v-if="!bordered">
<template v-for="(items, row) in groupItems" :key="row">
<tr>
<th class="descriptions-item-th" :colspan="item.span" v-for="(item, col) in items" :key="col">
<div ref="thVerticalCols" class="descriptions-item"></div>
</th>
</tr>
<tr>
<td class="descriptions-item-td" :colspan="item.span" v-for="(item, col) in items" :key="col">
<div ref="tdVerticalCols" class="descriptions-item"></div>
</td>
</tr>
</template>
</tbody>
<tbody v-else>
<template v-for="row in groupItems.length" :key="row">
<tr ref="thVerticalBorderedRows" class="descriptions-bordered-tr"></tr>
<tr ref="tdVerticalBorderedRows" class="descriptions-bordered-tr"></tr>
</template>
</tbody>
</table>
</div>
<div ref="defaultSlotsRef" v-show="false">
<slot v-if="defaultSlots"></slot>
<slot v-else></slot>
</div>
</div>
</template>
<style lang="less" scoped>
.m-descriptions {
font-size: 14px;
color: rgba(0, 0, 0, 0.88);
line-height: 1.5714285714285714;
.m-descriptions-header {
display: flex;
align-items: center;
margin-bottom: 20px;
.descriptions-title {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
flex: auto;
font-weight: 600;
font-size: 16px;
color: rgba(0, 0, 0, 0.88);
line-height: 1.5714285714285714;
}
.descriptions-extra {
margin-inline-start: auto;
color: rgba(0, 0, 0, 0.88);
font-size: 14px;
}
}
.m-descriptions-view {
width: 100%;
border-radius: 8px;
table {
width: 100%;
table-layout: fixed;
display: table; // 可选,只为兼容 vitepress 中 .vp-doc 的样式入侵,下同
border-collapse: separate; // 可选
margin: 0; // 可选
tr {
// 可选
border: none;
background: transparent;
}
.descriptions-item-th {
padding: 0; // 可选
border: none; // 可选
padding-bottom: 16px;
vertical-align: top;
background: transparent; // 可选
}
.descriptions-item-td {
padding: 0; // 可选
border: none; // 可选
padding-bottom: 16px;
vertical-align: top;
}
.descriptions-item {
display: flex;
}
}
}
.descriptions-bordered {
border: 1px solid rgba(5, 5, 5, 0.06);
table {
table-layout: auto;
border-collapse: collapse;
display: table; // 可选
margin: 0; // 可选
.descriptions-bordered-tr {
border-bottom: 1px solid rgba(5, 5, 5, 0.06);
&:last-child {
border-bottom: none;
}
:deep(.descriptions-label-th) {
border: none; // 可选
color: rgba(0, 0, 0, 0.88);
font-weight: normal;
font-size: 14px;
line-height: 1.5714285714285714;
text-align: start;
background-color: rgba(0, 0, 0, 0.02);
padding: 16px 24px;
border-inline-end: 1px solid rgba(5, 5, 5, 0.06);
&:last-child {
// 消除 vertical 列表最后一个 th 的边框
border-inline-end: none;
}
}
:deep(.descriptions-content-td) {
border: none; // 可选
display: table-cell;
flex: 1;
padding: 16px 24px;
border-inline-end: 1px solid rgba(5, 5, 5, 0.06);
color: rgba(0, 0, 0, 0.88);
font-size: 14px;
line-height: 1.5714285714285714;
word-break: break-word;
overflow-wrap: break-word;
&:last-child {
border-inline-end: none;
}
}
}
}
}
}
.descriptions-middle {
.m-descriptions-view {
.descriptions-item-td {
padding-bottom: 12px !important;
}
}
.descriptions-bordered {
:deep(.descriptions-label-th) {
padding: 12px 24px !important;
}
:deep(.descriptions-content-td) {
padding: 12px 24px !important;
}
}
}
.descriptions-small {
.m-descriptions-view {
.descriptions-item-td {
padding-bottom: 8px !important;
}
}
.descriptions-bordered {
:deep(.descriptions-label-th) {
padding: 8px 16px !important;
}
:deep(.descriptions-content-td) {
padding: 8px 16px !important;
}
}
}
</style>
创建 DescriptionsItem.vue 组件
<script setup lang="ts">
import type { CSSProperties } from 'vue'
interface Props {
label?: string // 内容的描述标签 string | slot
span?: number // 包含列的数量;当使用水平列表且未设置 span 时等效于 span: 1,但最后一行的最后一项,会包含该行剩余的所有列数
labelStyle?: CSSProperties // 自定义标签样式,优先级高于 Description 的 labelStyle
contentStyle?: CSSProperties // 自定义内容样式,优先级高于 Description 的 contentStyle
}
withDefaults(defineProps<Props>(), {
label: undefined,
span: undefined,
labelStyle: () => ({}),
contentStyle: () => ({})
})
</script>
<template>
<div class="descriptions-item" :data-span="span">
<span class="descriptions-label" :style="labelStyle">
<slot name="label">{{ label }}</slot>
</span>
<span class="descriptions-content" :style="contentStyle">
<slot></slot>
</span>
</div>
<div class="descriptions-item-bordered" :data-span="span">
<th class="descriptions-label-th" :style="labelStyle">
<slot name="label">{{ label }}</slot>
</th>
<td class="descriptions-content-td" :style="contentStyle">
<slot></slot>
</td>
</div>
</template>
<style lang="less" scoped>
.descriptions-item {
display: flex;
.descriptions-label {
display: inline-flex;
align-items: baseline;
color: rgba(0, 0, 0, 0.88);
font-weight: normal;
font-size: 14px;
line-height: 1.5714285714285714;
text-align: start;
&::after {
content: ':';
position: relative;
top: -0.5px;
margin-inline: 2px 8px;
}
}
.descriptions-content {
display: inline-flex;
align-items: baseline;
flex: 1;
color: rgba(0, 0, 0, 0.88);
font-size: 14px;
line-height: 1.5714285714285714;
word-break: break-word;
overflow-wrap: break-word;
}
}
</style>
在要使用的页面引入
其中引入使用了以下组件:
- Vue3单选(Radio)
- Vue3弹性布局(Flex)
- Vue3栅格(Grid)
- Vue3输入框(Input)
- Vue3数字输入框(InputNumber)
- Vue3开关(Switch)
- Vue3间距(Space)
<script setup lang="ts">
import Descriptions from './Descriptions.vue'
import DescriptionsItem from './DescriptionsItem.vue'
import { ref, reactive } from 'vue'
const size = ref('default')
const options = ref([
{
label: 'default',
value: 'default'
},
{
label: 'middle',
value: 'middle'
},
{
label: 'small',
value: 'small'
}
])
const show = ref(true)
const onClick = () => {
show.value = false
}
const state = reactive({
title: 'User Info',
extra: 'extra',
bordered: false,
vertical: false,
size: 'default',
column: {
xs: 1,
sm: 2,
md: 3,
lg: 3,
xl: 3,
xxl: 3
},
labelStyle: {
fontSize: '14px',
color: '#FF6900',
fontWeight: 600
},
contentStyle: {
fontSize: '14px',
color: '#1677FF',
fontWeight: 400
}
})
</script>
<template>
<div>
<h1>{{ $route.name }} {{ $route.meta.title }}</h1>
<h2 class="mt30 mb10">基本使用</h2>
<Descriptions title="User Info">
<template #extra>
<a href="#" @click="onClick">more</a>
</template>
<DescriptionsItem label="UserName">Zhou Maomao</DescriptionsItem>
<DescriptionsItem label="Telephone">1810000000</DescriptionsItem>
<DescriptionsItem label="Live">Hangzhou, Zhejiang</DescriptionsItem>
<DescriptionsItem label="Remark">empty</DescriptionsItem>
<DescriptionsItem label="Address"
>No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China</DescriptionsItem
>
</Descriptions>
<h2 class="mt30 mb10">带边框的</h2>
<Descriptions title="User Info" bordered>
<DescriptionsItem label="Product">Cloud Database</DescriptionsItem>
<DescriptionsItem label="Billing Mode">Prepaid</DescriptionsItem>
<DescriptionsItem label="Automatic Renewal">YES</DescriptionsItem>
<DescriptionsItem label="Order time">2018-04-24 18:00:00</DescriptionsItem>
<DescriptionsItem label="Usage Time" :span="2">2030-04-24 18:00:00</DescriptionsItem>
<DescriptionsItem label="Status" :span="3">
<Badge status="processing" text="Running" />
</DescriptionsItem>
<DescriptionsItem label="Negotiated Amount">$80.00</DescriptionsItem>
<DescriptionsItem label="Discount">$20.00</DescriptionsItem>
<DescriptionsItem label="Official Receipts">$60.00</DescriptionsItem>
<DescriptionsItem label="Config Info">
Data disk type: MongoDB
<br />
Database version: 3.4
<br />
Package: dds.mongo.mid
<br />
Storage space: 10 GB
<br />
Replication factor: 3
<br />
Region: East China 1
<br />
</DescriptionsItem>
</Descriptions>
<h2 class="mt30 mb10">响应式描述列表</h2>
<Descriptions title="Responsive Descriptions" bordered :column="{ xxl: 4, xl: 3, lg: 3, md: 3, sm: 2, xs: 1 }">
<DescriptionsItem label="Product">Cloud Database</DescriptionsItem>
<DescriptionsItem label="Billing">Prepaid</DescriptionsItem>
<DescriptionsItem label="Time">18:00:00</DescriptionsItem>
<DescriptionsItem label="Amount">$80.00</DescriptionsItem>
<DescriptionsItem label="Discount">$20.00</DescriptionsItem>
<DescriptionsItem label="Official">$60.00</DescriptionsItem>
<DescriptionsItem label="Config Info">
Data disk type: MongoDB
<br />
Database version: 3.4
<br />
Package: dds.mongo.mid
<br />
Storage space: 10 GB
<br />
Replication factor: 3
<br />
Region: East China 1
</DescriptionsItem>
</Descriptions>
<h2 class="mt30 mb10">垂直列表</h2>
<Descriptions title="User Info" vertical>
<DescriptionsItem label="UserName">Zhou Maomao</DescriptionsItem>
<DescriptionsItem label="Telephone">1810000000</DescriptionsItem>
<DescriptionsItem label="Live">Hangzhou, Zhejiang</DescriptionsItem>
<DescriptionsItem label="Address" :span="2">
No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China
</DescriptionsItem>
<DescriptionsItem label="Remark">empty</DescriptionsItem>
</Descriptions>
<h2 class="mt30 mb10">带边框的垂直列表</h2>
<Descriptions title="User Info" vertical bordered>
<DescriptionsItem label="UserName">Zhou Maomao</DescriptionsItem>
<DescriptionsItem label="Telephone">1810000000</DescriptionsItem>
<DescriptionsItem label="Live">Hangzhou, Zhejiang</DescriptionsItem>
<DescriptionsItem label="Address" :span="2">
No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China
</DescriptionsItem>
<DescriptionsItem label="Remark">empty</DescriptionsItem>
</Descriptions>
<h2 class="mt30 mb10">自定义尺寸</h2>
<Flex vertical gap="middle">
<Radio :options="options" v-model:value="size" button button-style="solid" />
<Descriptions bordered title="Custom Size" :size="size">
<template #extra>
<Button type="primary">Edit</Button>
</template>
<DescriptionsItem label="Product">Cloud Database</DescriptionsItem>
<DescriptionsItem label="Billing">Prepaid</DescriptionsItem>
<DescriptionsItem label="Time">18:00:00</DescriptionsItem>
<DescriptionsItem label="Amount">$80.00</DescriptionsItem>
<DescriptionsItem label="Discount">$20.00</DescriptionsItem>
<DescriptionsItem label="Official">$60.00</DescriptionsItem>
<DescriptionsItem label="Config Info">
Data disk type: MongoDB
<br />
Database version: 3.4
<br />
Package: dds.mongo.mid
<br />
Storage space: 10 GB
<br />
Replication factor: 3
<br />
Region: East China 1
<br />
</DescriptionsItem>
</Descriptions>
<Descriptions title="Custom Size" :size="size">
<template #extra>
<Button type="primary">Edit</Button>
</template>
<DescriptionsItem label="Product">Cloud Database</DescriptionsItem>
<DescriptionsItem label="Billing">Prepaid</DescriptionsItem>
<DescriptionsItem label="Time">18:00:00</DescriptionsItem>
<DescriptionsItem label="Amount">$80.00</DescriptionsItem>
<DescriptionsItem label="Discount">$20.00</DescriptionsItem>
<DescriptionsItem label="Official">$60.00</DescriptionsItem>
</Descriptions>
</Flex>
<h2 class="mt30 mb10">自定义内容 & 标签样式</h2>
<Flex vertical gap="middle">
<Descriptions
bordered
title="Custom Style"
:labelStyle="{ fontWeight: 800, color: '#faad14' }"
:contentStyle="{ fontWeight: 600, color: '#1677ff' }"
>
<template #extra>
<Button type="primary">Edit</Button>
</template>
<DescriptionsItem label="Product">Cloud Database</DescriptionsItem>
<DescriptionsItem label="Billing">Prepaid</DescriptionsItem>
<DescriptionsItem label="Time">18:00:00</DescriptionsItem>
<DescriptionsItem label="Amount" :labelStyle="{ color: '#52c41a' }" :contentStyle="{ color: '#ff4d4f' }"
>$80.00</DescriptionsItem
>
<DescriptionsItem label="Discount">$20.00</DescriptionsItem>
<DescriptionsItem label="Official">$60.00</DescriptionsItem>
<DescriptionsItem label="Config Info">
Data disk type: MongoDB
<br />
Database version: 3.4
<br />
Package: dds.mongo.mid
<br />
Storage space: 10 GB
<br />
Replication factor: 3
<br />
Region: East China 1
<br />
</DescriptionsItem>
</Descriptions>
<Descriptions
title="Custom Style"
:labelStyle="{ fontWeight: 800, color: '#faad14' }"
:contentStyle="{ fontWeight: 600, color: '#1677ff' }"
>
<template #extra>
<Button type="primary">Edit</Button>
</template>
<DescriptionsItem label="Product">Cloud Database</DescriptionsItem>
<DescriptionsItem label="Billing">Prepaid</DescriptionsItem>
<DescriptionsItem label="Time">18:00:00</DescriptionsItem>
<DescriptionsItem label="Amount" :labelStyle="{ color: '#52c41a' }" :contentStyle="{ color: '#ff4d4f' }"
>$80.00</DescriptionsItem
>
<DescriptionsItem label="Discount">$20.00</DescriptionsItem>
<DescriptionsItem label="Official">$60.00</DescriptionsItem>
</Descriptions>
</Flex>
<h2 class="mt30 mb10">描述列表配置器</h2>
<Flex vertical>
<Row :gutter="[24, 12]">
<Col :span="6">
<Flex gap="small" vertical>
title:
<Input v-model:value="state.title" placeholder="title" />
</Flex>
</Col>
<Col :span="6">
<Flex gap="small" vertical>
extra:
<Input v-model:value="state.extra" placeholder="extra" />
</Flex>
</Col>
<Col :span="6">
<Space gap="small" vertical>
bordered:
<Switch v-model="state.bordered" />
</Space>
</Col>
<Col :span="6">
<Space gap="small" vertical>
vertical:
<Switch v-model="state.vertical" />
</Space>
</Col>
<Col :span="6">
<Space gap="small" vertical>
size:
<Radio :options="options" v-model:value="state.size" button button-style="solid" />
</Space>
</Col>
<Col :span="6">
<Flex gap="small" vertical>
Column xs:
<InputNumber v-model:value="state.column.xs" :min="1" placeholder="xs" />
</Flex>
</Col>
<Col :span="6">
<Flex gap="small" vertical>
Column sm:
<InputNumber v-model:value="state.column.sm" :min="1" :max="9" placeholder="sm" />
</Flex>
</Col>
<Col :span="6">
<Flex gap="small" vertical>
Column md:
<InputNumber v-model:value="state.column.md" :min="1" :max="9" placeholder="md" />
</Flex>
</Col>
<Col :span="6">
<Flex gap="small" vertical>
Column lg:
<InputNumber v-model:value="state.column.lg" :min="1" :max="9" placeholder="lg" />
</Flex>
</Col>
<Col :span="6">
<Flex gap="small" vertical>
Column xl:
<InputNumber v-model:value="state.column.xl" :min="1" :max="9" placeholder="xl" />
</Flex>
</Col>
<Col :span="6">
<Flex gap="small" vertical>
Column xxl:
<InputNumber v-model:value="state.column.xxl" :min="1" :max="9" placeholder="xxl" />
</Flex>
</Col>
<Col :span="6"></Col>
<Col :span="6">
<Flex gap="small" vertical>
labelStyle fontSize:
<Input v-model:value="state.labelStyle.fontSize" placeholder="labelStyle fontSize" />
</Flex>
</Col>
<Col :span="6">
<Flex gap="small" vertical>
labelStyle color:
<Input v-model:value="state.labelStyle.color" placeholder="labelStyle color" />
</Flex>
</Col>
<Col :span="6">
<Flex gap="small" vertical>
labelStyle fontWeight:
<InputNumber
v-model:value="state.labelStyle.fontWeight"
:step="100"
:min="100"
:max="1000"
placeholder="labelStyle fontWeight"
/>
</Flex>
</Col>
<Col :span="6"></Col>
<Col :span="6">
<Flex gap="small" vertical>
contentStyle fontSize:
<Input v-model:value="state.contentStyle.fontSize" placeholder="contentStyle fontSize" />
</Flex>
</Col>
<Col :span="6">
<Flex gap="small" vertical>
contentStyle color:
<Input v-model:value="state.contentStyle.color" placeholder="contentStyle color" />
</Flex>
</Col>
<Col :span="6">
<Flex gap="small" vertical>
contentStyle fontWeight:
<InputNumber
v-model:value="state.contentStyle.fontWeight"
:step="100"
:min="100"
:max="1000"
placeholder="contentStyle fontWeight"
/>
</Flex>
</Col>
</Row>
<Descriptions
:title="state.title"
:extra="state.extra"
:bordered="state.bordered"
:vertical="state.vertical"
:size="state.size"
:column="{
xs: state.column.xs,
sm: state.column.sm,
md: state.column.md,
lg: state.column.lg,
xl: state.column.xl,
xxl: state.column.xxl
}"
:label-style="state.labelStyle"
:content-style="state.contentStyle"
>
<DescriptionsItem label="Product">Cloud Database</DescriptionsItem>
<DescriptionsItem label="Billing">Prepaid</DescriptionsItem>
<DescriptionsItem label="Time">18:00:00</DescriptionsItem>
<DescriptionsItem label="Amount">$80.00</DescriptionsItem>
<DescriptionsItem label="Discount">$20.00</DescriptionsItem>
<DescriptionsItem label="Official">$60.00</DescriptionsItem>
<DescriptionsItem label="Status" :span="1">
<Badge status="processing" text="Running" />
</DescriptionsItem>
<DescriptionsItem label="Usage Time" :span="2">2030-04-24 18:00:00</DescriptionsItem>
<DescriptionsItem label="Address" :span="3"
>No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China</DescriptionsItem
>
</Descriptions>
</Flex>
</div>
</template>