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


Posted in Vue.js onMay 18, 2021

本文实例为大家分享了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>

参数说明

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

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

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

Vue.js 相关文章推荐
vue添加自定义右键菜单的完整实例
Dec 08 Vue.js
VUE中鼠标滚轮使div左右滚动的方法详解
Dec 14 Vue.js
Vue-router中hash模式与history模式的区别详解
Dec 15 Vue.js
详解Vue2的diff算法
Jan 06 Vue.js
vue-quill-editor插入图片路径太长问题解决方法
Jan 08 Vue.js
如何在 Vue 中使用 JSX
Feb 14 Vue.js
vue实现可移动的悬浮按钮
Mar 04 Vue.js
vue使用节流函数的踩坑实例指南
May 20 Vue.js
Vue3中的Refs和Ref详情
Nov 11 Vue.js
Vue的过滤器你真了解吗
Feb 24 Vue.js
Vue中Object.assign清空数据报错的解决方案
Mar 03 Vue.js
Vue3中toRef与toRefs的区别
Mar 24 Vue.js
使用这 6个Vue加载动画库来减少我们网站的跳出率
一文带你理解vue创建一个后台管理系统流程(Vue+Element)
详解vue中v-for的key唯一性
解读Vue组件注册方式
May 15 #Vue.js
如何理解Vue简单状态管理之store模式
May 15 #Vue.js
Vue如何实现组件间通信
May 15 #Vue.js
详解Vue的sync修饰符
May 15 #Vue.js
You might like
2020年4月放送决定!第2期TV动画《邪神酱飞踢》视觉图&主题曲情报公开!
2020/03/06 日漫
初学者入门:细述PHP4的核心Zend
2006/09/05 PHP
PHP函数篇详解十进制、二进制、八进制和十六进制转换函数说明
2011/12/05 PHP
Smarty模板简单配置与使用方法示例
2016/05/23 PHP
PHP常见的6个错误提示及解决方法
2016/07/07 PHP
php使用Jpgraph创建3D饼形图效果示例
2017/02/15 PHP
PHP语言对接抖音快手小红书视频/图片去水印API接口源码
2020/08/11 PHP
THINKPHP5分页数据对象处理过程解析
2020/10/28 PHP
基于jquery的loading 加载提示效果实现代码
2011/09/01 Javascript
JS中Iframe之间传值的方法
2013/03/11 Javascript
jQuery EasyUI编辑DataGrid用combobox实现多级联动
2016/08/29 Javascript
jQuery旋转插件jqueryrotate用法详解
2016/10/13 Javascript
Jquery实现上下移动和排序代码
2016/10/17 Javascript
jQuery实现动态添加、删除按钮及input输入框的方法
2017/04/27 jQuery
详解基于node的前端项目编译时内存溢出问题
2017/08/01 Javascript
jQuery实现表格冻结顶栏效果
2017/08/20 jQuery
微信小程序点击图片实现长按预览、保存、识别带参数二维码、转发等功能
2019/07/20 Javascript
微信小程序按顺序同步执行的两种方式
2019/12/20 Javascript
JS数组方法join()用法实例分析
2020/01/18 Javascript
python去掉字符串中重复字符的方法
2014/02/27 Python
基于scrapy实现的简单蜘蛛采集程序
2015/04/17 Python
Python实现1-9数组形成的结果为100的所有运算式的示例
2017/11/03 Python
Python玩转加密的技巧【推荐】
2019/05/13 Python
如何通过Python3和ssl实现加密通信功能
2020/05/09 Python
django 数据库返回queryset实现封装为字典
2020/05/19 Python
Python爬取某平台短视频的方法
2021/02/08 Python
html5 标签
2009/07/16 HTML / CSS
澳洲网红粉泥面膜:Sand & Sky
2019/08/13 全球购物
品学兼优的大学生自我评价
2013/09/20 职场文书
2013年保送生自荐信格式
2013/11/20 职场文书
大学生村官典型材料
2014/01/12 职场文书
社区志愿者培训方案
2014/06/10 职场文书
暑假社会实践心得体会
2014/09/02 职场文书
信用卡逾期证明示例
2014/09/13 职场文书
社区活动总结
2015/02/04 职场文书
基于python定位棋子位置及识别棋子颜色
2021/07/26 Python