当前位置:编程学习 > > 正文

vueelementui侧边栏(Vue Element UI自定义描述列表组件)

时间:2022-03-29 10:51:28类别:编程学习

vueelementui侧边栏

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

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

效果图

vueelementui侧边栏(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>
      <li class="desc" :style="{margin}">
        <!-- 标题 -->
        <h1 v-if="title" class="desc-title" v-html="title"></h1>
        <el-row class="desc-row">
          <slot/>
        </el-row>
      </li>
    </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">
        <li class="desc-item-content" :class="size">
          <label class="desc-item-label" :style="{width: labelWidth}" v-html="label"></label>
          <li 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>
          </li>
        </li>
      </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>
    
  • 参数说明

    vueelementui侧边栏(Vue Element UI自定义描述列表组件)

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

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

    上一篇下一篇

    猜您喜欢

    热门推荐