自定义el-table组件

目录

需求

table和table-column组件

        table组件:

        table-column组件:

        table.js

用法:

        引入:

         不带行内编辑

        带行内编辑

文档:

        Table Attributes

        Table Events

        Table-column Attributes


需求

最近项目上遇到一个需求,设计要求将列表改成这样

而且还要行内编辑

 

很显然,element-ui中的<el-table> 是很难实现的,光是这些个样式就头疼不已

思来想去,这个东西还是用div+css3自己写最容易,但是项目中又不止这一个列表,总不能全都复制粘贴一遍吧

完全之策略就是写个组件,保留我们使用<el-table>的习惯,我们又是多人开发,再写个小文档,小demo让同事们能用就行。

ok,办法想好了,我们就开干写组件

table和table-column组件

        table组件:

<template>
  <div class="list">
    <div class="table-header">
      <div
        v-for="item in headers"
        :key="item.label"
        :style="{
          flex: toFlexVal(item.width, item.minWidth),
          textAlign: item.align
        }"
        class="tooltip"
      >
        {{ item.label }}
      </div>
    </div>
    <div
      v-for="(item, index) in data"
      :key="item.userId"
      style="position: relative"
      :class="[
        isEdit && index === current && (item[currentRowNoEdit] || !currentRowNoEdit) ? 'current' : '',
        isEdit ? 'column-edit' : 'column'
      ]"
      @click.stop="clickCurrent(item, index)"
      @mouseenter.stop="enterDelete(item, index)"
      @mouseleave.stop="leaveDelete()"
    >
      <slot :item="item" :edit="current === index && (item[currentRowNoEdit] || !currentRowNoEdit)"> </slot>
      <div
        v-show="isDelete && hoverCurrent === index && index !== current && isEdit"
        class="delete"
        @click.stop="clickDelete(item, index)"
      >
        <i title="删除" class="iconfont icon-a-shanchubeifen2"></i>
      </div>
    </div>
    <div v-if="!data.length" class="dashboard">
      <img class="fire-arrow" src="@/assets/svg/fire-arrow.svg" alt="fire arrow" />
      <div class="text">暂无数据</div>
    </div>
  </div>
</template>
<script>
import { toFlexVal } from '@/utils/table'
export default {
  name: 'Table',
  componentName: 'Table',
  components: {},
  props: {
    // 整个列表的数据
    data: {
      type: Array,
      default: () => []
    },
    // 是否点击可编辑
    isEdit: {
      type: Boolean,
      default: true
    },
    // 是否hover删除
    isDelete: {
      type: Boolean,
      default: false
    },
    // 当前行不可编辑,该值为item的某个属性,item[currentRowNoEdit] = 1(可编辑)/0(不可编辑) (true/false)
    currentRowNoEdit: {
      type: [String, Boolean],
      default: false
    }
  },
  data() {
    return {
      columns: [],
      headers: [],
      current: false, // 当前点击行
      hoverCurrent: false, // 当前hover行
      toFlexVal: toFlexVal
    }
  },
  watch: {
    columns(val) {
      // 处理表头数据
      const info = []
      this.headers = val.filter(d => {
        if (info.indexOf(d.label) === -1) {
          info.push(d.label)
          return d
        }
      })
    }
  },
  methods: {
    // 鼠标点击某一项
    clickCurrent(item, index) {
      if (item[this.currentRowNoEdit] || !this.currentRowNoEdit) {
        this.current = index
        this.$emit('currentClick', item, index)
      } else {
        this.closeE()
      }
    },
    // 鼠标悬浮事件
    enterDelete(item, index) {
      this.hoverCurrent = index
    },
    // 鼠标移出事件
    leaveDelete() {
      this.hoverCurrent = false
    },
    // 点击hover删除
    clickDelete(item, index) {
      this.$emit('clickDelete', item, index)
    },
    toCssVal(val) {
      if (!val) return null
      if (/(px|rem|rem)/.test(val.toString())) return val
      else return val + 'px'
    },
    closeE() {
      this.current = false
    }
  }
}
</script>
<style scoped lang="scss">
/* 样式省略,如有需要请在源码中获取 */
</style>

        table-column组件:

<template>
  <div
    ref="column"
    :style="{
      flex: toFlexVal(width, minWidth),
      textAlign: align
    }"
    class="single-column tooltip"
  >
    <el-tooltip
      v-if="String(toolTip) && showToolTip"
      visible-arrow
      effect="dark"
      :content="String(toolTip)"
      placement="top-start"
    >
      <span ref="columnSpan">
        <slot></slot>
      </span>
    </el-tooltip>
    <slot v-else></slot>
  </div>
</template>
<script>
import { toFlexVal } from '@/utils/table'
import elementResizeDetectorMaker from 'element-resize-detector'
export default {
  name: 'TableColumn',
  props: {
    width: [Number, String],
    minWidth: [Number, String],
    label: {
      type: String,
      default: () => ''
    },
    align: {
      type: String,
      default: () => ''
    },
    toolTip: {
      type: [String, Number],
      default: () => ''
    }
  },
  data() {
    return {
      parent: null,
      column: null,
      toFlexVal: toFlexVal,
      showToolTip: false
    }
  },
  watch: {
    width(val) {
      this.column.width = val
    },
    minWidth(val) {
      this.column.minWidth = val
    },
    label(val) {
      this.column.label = val
    },
    align(val) {
      this.column.align = val
    },
    toolTip() {
      // 分页时resize()直接调用el.scrollWidth值不正确,需要这样处理
      this.$nextTick(this.resize)
    }
  },
  created() {
    const column = {
      ...this.$props
    }
    this.parent = this.getParent('Table')
    this.column = column
  },
  mounted() {
    this.parent.columns.push(this.column)
    this.resize()
  },
  methods: {
    getParent(name) {
      // this.$parent.$parent可以找到组件的套父级
      let parent = this.$parent
      while (parent) {
        if (parent.$options.componentName !== name) {
          parent = parent.$parent
        } else {
          return parent
        }
      }
      return null
    },
    // 监听某个div的宽度变化
    resize() {
      const erd = elementResizeDetectorMaker()
      erd.listenTo(this.$refs.column, el => {
        if (el.scrollWidth > el.offsetWidth) {
          this.showToolTip = true
        } else {
          this.showToolTip = false
        }
      })
    }
  }
}
</script>
<style scoped>
.single-column {
  padding: 18px 10px;
  flex: 1 0 100px;
  cursor: pointer;
  line-height: 24px;
}
.el-tooltip {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
</style>

        table.js

export const toFlexVal = (width, minWidth) => {
  if (minWidth) {
    return `1 0 ${minWidth}px`
  } else if (width) {
    return `0 0 ${width}px`
  }
  return '1 0 80px' // 默认值
}

用法:

        引入:

import Table from '@/components/Table/table'
import tableColumn from '@/components/Table/table-column'

         不带行内编辑

  <template>
    <Table
      :data="tableData"
      :isEdit="false"
    >
      <template v-slot:default="{ item }">
        <table-column
          label="日期"
          width="180">
          {{item.date}}
        </table-column>
        <table-column
          label="姓名"
          width="180">
          {{item.name}}
        </table-column>
        <table-column
          label="地址">
          {{item.address}}
        </table-column>
      </template>
    </Table>
  </template>

  <script>
    export default {
      data() {
        return {
          tableData: [{
            date: '2016-05-02',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1518 弄'
          }, {
            date: '2016-05-04',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1517 弄'
          }, {
            date: '2016-05-01',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1519 弄'
          }, {
            date: '2016-05-03',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1516 弄'
          }]
        }
      }
    }
  </script>

        带行内编辑

<template>
  <!-- isDelete: 鼠标悬浮是否出现删除按钮 -->
  <la-table
    :data="tableData"
    :isDelete="true"
    @currentClick="currentClickRow"
    @clickDelete="hoverDeleteRow"
  >
    <template v-slot:default="{ item, edit }">
      <div v-if="edit" class="edit">
        行内编辑部分
      </div>
      <div v-else class="content">
        <table-column label="图标">
          <img :src="item.icon" class="iconStyle" alt="" />
        </table-column>
        <table-column label="姓名" :toolTip="item.name">{{ item.name }}</table-column>
        <table-column label="时间" :toolTip="item.date">{{ item.date }}</table-column>
        <table-column label="地址" :toolTip="item.address">{{ item.address }}</table-column>
      </div>
    </template>
  </la-table>
</template>

  <script>
    export default {
      data() {
        return {
          tableData: [{
            date: '2016-05-02',
            name: '王小虎',
            icon: 'http://XXXXXX.jpg',
            address: '上海市普陀区金沙江路 1518 弄'
          }, {
            date: '2016-05-04',
            name: '王小虎',
            icon: 'http://XXXXXX.jpg',
            address: '上海市普陀区金沙江路 1517 弄'
          }, {
            date: '2016-05-01',
            name: '王小虎',
            icon: 'http://XXXXXX.jpg',
            address: '上海市普陀区金沙江路 1519 弄'
          }, {
            date: '2016-05-03',
            name: '王小虎',
            icon: 'http://XXXXXX.jpg',
            address: '上海市普陀区金沙江路 1516 弄'
          }]
        }
      },
      methods: {
        // 点击编辑 item: 当前点击数据
        currentClickRow(item) {},
        // 点击删除回调, items: 当前删除数据
        hoverDeleteRow(item) {}
      }
    }
  </script>

文档:

      

          Table Attributes

参数说明类型可选值默认值

data

显示的数据Array--

isEdit

是否支持点击编辑Boolean-true

isDelete

是否支持hover删除Boolean-false

currentRowNoEdit

限制某一行不可编辑,该值传入item的某个属性string/Boolean--

       

         Table Events

事件名说明参数

currentClick

点击某一行触发的事件

row,index

clickDelete

点击hover删除触发的事件( isDelete为true可用 )row,index

        Table Methods

方法名说明参数

closeE

关闭编辑状态

-

       

         Table-column Attributes

参数说明类型可选值默认值
width对应列的宽度string--
min-width对应列的最小宽度,与 width 的区别是 width 是固定的,min-width 会把剩余宽度按比例分配给没设置 width 的列string80px-
label显示的标题string--
align对齐方式Stringleft/center/rightleft
toolTip当内容过长被隐藏时显示 tooltipBoolean-false

源代码:

GitHub - JerryGit1/custom-table: 表格组件。保留<el-table>的开发习惯,样式更灵活

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值