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 03 Vue.js
在vue中使用inheritAttrs实现组件的扩展性介绍
Dec 07 Vue.js
基于vue与element实现创建试卷相关功能(实例代码)
Dec 07 Vue.js
vue实现购物车的小练习
Dec 21 Vue.js
基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析
Dec 30 Vue.js
vue3.0中友好使用antdv示例详解
Jan 05 Vue.js
详解Vue的七种传值方式
Feb 08 Vue.js
Vue实现下拉加载更多
May 09 Vue.js
Vue elementUI表单嵌套表格并对每行进行校验详解
Feb 18 Vue.js
vue实现列表垂直无缝滚动
Apr 08 Vue.js
vue选项卡切换的实现案例
Apr 11 Vue.js
解决vue中provide inject的响应式监听
Apr 19 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
PHP连接SQLSERVER 注意事项(附dll文件下载)
2012/06/28 PHP
php中的boolean(布尔)类型详解
2013/10/28 PHP
php出现内存位置访问无效错误问题解决方法
2014/08/16 PHP
php解析字符串里所有URL地址的方法
2015/04/03 PHP
php精度计算的问题解析
2019/06/21 PHP
JS控制表格隔行变色
2006/06/26 Javascript
JS 获取span标签中的值的代码 支持ie与firefox
2009/08/24 Javascript
通过JS获取用户本地图片路径并显示的代码
2012/02/16 Javascript
jquery中使用$(#form).submit()重写提交表单无效原因分析及解决
2013/03/25 Javascript
EasyUI闪屏EasyUI页面加载提示(原理+代码+效果图)
2016/02/21 Javascript
JavaScript判断页面加载完之后再执行预定函数的技巧
2016/05/17 Javascript
jQuery unbind 删除绑定事件详解
2016/05/24 Javascript
深入分析javascript中的错误处理机制
2016/07/17 Javascript
PHP捕捉异常中断的方法
2016/10/24 Javascript
JSON字符串和JSON对象相互转化实例详解
2017/01/05 Javascript
微信小程序侧边栏滑动特效(左右滑动)
2017/01/23 Javascript
canvas 实现中国象棋
2017/02/17 Javascript
解决BootStrap Fileinput手机图片上传显示旋转问题
2017/06/01 Javascript
AngularJS遍历获取数组元素的方法示例
2017/11/11 Javascript
JavaScript实现区块链
2018/03/14 Javascript
vue实现绑定事件的方法实例代码详解
2019/06/20 Javascript
微信小程序中使用 async/await的方法实例分析
2020/05/06 Javascript
Vue基本指令实例图文讲解
2021/02/25 Vue.js
[47:45]Liquid vs OG 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
基于python绘制科赫雪花
2018/06/22 Python
Python读写zip压缩文件的方法
2018/08/29 Python
解析pip安装第三方库但PyCharm中却无法识别的问题及PyCharm安装第三方库的方法教程
2020/03/10 Python
保加利亚手表、香水、化妆品和珠宝购物网站:Brasty.bg
2020/04/22 全球购物
岗位职责风险防控
2014/02/18 职场文书
关于安全的广播稿
2014/10/23 职场文书
2015年挂职锻炼工作总结
2014/12/12 职场文书
万能检讨书
2015/01/27 职场文书
保护环境的宣传语
2015/07/13 职场文书
五年级作文之学校的四季
2019/12/05 职场文书
解决IDEA翻译插件Translation报错更新TTK失败不能使用
2022/04/24 Python
Python使用BeautifulSoup4修改网页内容
2022/05/20 Python