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中利用three.js实现全景图的完整示例
Dec 07 Vue.js
vue 实现基础组件的自动化全局注册
Dec 25 Vue.js
基于vuex实现购物车功能
Jan 10 Vue.js
vue实现简易计算器功能
Jan 20 Vue.js
vue+echarts实现中国地图流动效果(步骤详解)
Jan 27 Vue.js
详解Vue的七种传值方式
Feb 08 Vue.js
WebStorm无法正确识别Vue3组合式API的解决方案
Feb 18 Vue.js
vue-router路由懒加载及实现的3种方式
Feb 28 Vue.js
vue实现移动端div拖动效果
Mar 03 Vue.js
Vue中Object.assign清空数据报错的解决方案
Mar 03 Vue.js
vue使用wavesurfer.js解决音频可视化播放问题
Apr 04 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
上海无线电三厂简史修改版
2021/03/01 无线电
PHP在特殊字符前加斜杠的实现代码
2011/07/17 PHP
PHP中::、-&amp;gt;、self、$this几种操作符的区别介绍
2013/04/24 PHP
PHP数据类型之布尔型的介绍
2013/04/28 PHP
使用JavaScript创建新样式表和新样式规则
2016/06/14 PHP
js wmp操作代码小结(音乐连播功能)
2008/11/08 Javascript
重载toString实现JS HashMap分析
2011/03/13 Javascript
js获取url参数代码实例分享(JS操作URL)
2013/12/13 Javascript
js获取通过ajax返回的map型的JSONArray的方法
2014/01/09 Javascript
jquery实现input输入框实时输入触发事件代码
2014/01/28 Javascript
js实现图片拖动改变顺序附图
2014/05/13 Javascript
jquery实现页面关键词高亮显示的方法
2015/03/12 Javascript
浅谈jQuery中replace()方法
2015/05/13 Javascript
在JS方法中返回多个值的方法汇总
2015/05/20 Javascript
javascript日期操作详解(脚本之家整理)
2015/09/05 Javascript
swiper动态改变滑动内容的实现方法
2018/01/17 Javascript
微信小程序url传参写变量的方法
2018/08/09 Javascript
js实现json数组分组合并操作示例
2019/02/12 Javascript
vue按需加载实例详解
2019/09/06 Javascript
node.js使用zlib模块进行数据压缩和解压操作示例
2020/02/12 Javascript
[09:40]DAC2018 4.5 SOLO赛 MidOne vs Miracle
2018/04/06 DOTA
深入浅析python定时杀进程
2016/06/06 Python
numpy找出array中的最大值,最小值实例
2018/04/03 Python
pycharm中显示CSS提示的知识点总结
2019/07/29 Python
Python之Numpy的超实用基础详细教程
2019/10/23 Python
Python使用py2neo操作图数据库neo4j的方法详解
2020/01/13 Python
使用 pytorch 创建神经网络拟合sin函数的实现
2020/02/24 Python
python数据库编程 Mysql实现通讯录
2020/03/27 Python
解析python 类方法、对象方法、静态方法
2020/08/15 Python
DJI大疆无人机官方商城:全球领先的无人飞行器研发和生产商
2016/12/21 全球购物
德国著名廉价网上药店:Shop-Apotheke
2017/07/23 全球购物
泰国国际航空公司官网:Thai Airways International
2019/12/04 全球购物
新年晚会开场白
2015/05/29 职场文书
英文诗歌翻译方法(赏析)
2019/08/16 职场文书
Python Pytorch查询图像的特征从集合或数据库中查找图像
2022/04/09 Python
Python使用pyecharts控件绘制图表
2022/06/05 Python