打造你的专属Vue组件:超实用“Descriptions展示组件开发”实战

组件效果

在这里插入图片描述

实现功能

  • 栅格布局组件。根据屏幕尺寸(xs, md, lg),列宽会自动调整。
  • 根据配置的字段显示不显示
  • 动态设置label的宽度,可从当前项item.labelWidth或组件的labelWidth属性获取
  • 利用getData(item)方法用于处理并返回每个配置项对应的数据,支持格式化、过滤等功能

代码片段

<template>
  <el-row :gutter="14" style="width: 100%;" class="desc_contents">
    <el-col
      v-for="item in adjustedConfigs"
      :key="item.prop"
      :xs="item.col?.xs || 24"
      :md="item.col?.md || 12"
      :lg="item.col?.lg || 8"
      v-show="item.show !== false"
      class="desc_contents-item"
    >
      <div class="label" :style="{ width: item.labelWidth || labelWidth || '110px' }">
        <slot :name="`${item.slotName}_label`">
          {{ item.label }}
        </slot>
      </div>
      <div class="data">
          <template #content>
            <slot :name="`${item.slotName}_cont`">
              {{ getData(item) }}
            </slot>
          </template>
          <slot :name="`${item.slotName}_cont`">
            {{ getData(item) }}
          </slot>
      </div>
    </el-col>
  </el-row>
</template>

<script setup>
import { computed } from 'vue'
defineOptions({
  name: 'HDescriptions'
})

const props = defineProps({
  // 数据详情
  infoData: {
    type: Object,
    default: () => {}
  },
  // 配置项
  configs: {
    type: Array,
    default: () => []
  },
  // label宽度
  labelWidth: {
    type: String,
    default: '110px'
  }
})

// 处理数据并返回
const getData = (item) => {
  const value = getPropByPath(props.infoData, item.prop).v
  if(value === null || value === undefined || value === '') return '/'
  if (item.formatter) return `${item.formatter(props.infoData)} ${item.unit || ''}` || '/'
  if (item.filters) {
    return constantEscape(value, item.filters.list || [], item.filters.key || 'value', item.filters.label || 'label_zh')
  }
  if (value || value === 0) return `${value} ${item.unit || ''}`
  return '/'
}
// 处理过滤的数据
const constantEscape = (value, list, key, label) => {
  if(!list?.length) return value
  const res = list.find((item: any) => {
    return item[key].toString() === value.toString()
  })
  if (res === undefined) return '/'
  return res && res[label]
}

// 使用computed计算adjustedConfigs的生成
const adjustedConfigs = computed(() => {
  return props.configs.map((config) => {
    if (typeof config.show === 'function') {
      return { ...config, show: config.show(props.infoData) };
    }
    return config;
  });
});
</script>

<style lang="scss" scoped>
.desc_contents {
  &-item {
    margin-bottom: 6px;
  }
  :deep(.el-col){
    // padding: 5px 0;
    display: flex;
    font-size: 14px;
    .label {
      color: #909399;
      line-height: 140%;
      width: 86px;
      margin-right: 14px;
      flex-shrink: 0;
    }
    .data {
      line-height: 140%;
      color: #303133;
      flex: 1;
      width: 0;
      white-space: pre-wrap;
      .file {
        background: #f7faff;
        border: 1px solid rgba(28, 108, 249, 0.1);
        padding: 4px;
        display: flex;
        align-items: center;
        border-radius: 4px;
        & + .file {
          margin-top: 12px;
        }
        &-name {
          font-size: 14px;
          color: #333333;
          line-height: 20px;
          margin-bottom: 4px;
        }
        &-size {
          font-size: 12px;
          color: #999999;
          line-height: 20px;
        }
        &-icon {
          border: 1px solid #e1ecfe;
          border-radius: 4px;
          padding: 11px;
          margin-right: 10px;
        }
      }
    }
  }
}
</style>

总结

总之,这个组件提供了高度灵活的数据展示能力,允许用户通过配置来自定义展示哪些数据、如何格式化数据以及在不同屏幕尺寸下的布局,非常适合构建动态数据详情页面。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值