vue element插件集成表格框选,右键事件

本项目依赖于https://www.npmjs.com/package/publicis-common

实现原理依赖于getClientRects() 方法返回一个指向客户端中每一个盒子的边界矩形的矩形集合,需要修改table数据源格式,即每个单元格都是一个小对象,通过单元格独一无二的name值实现定位框选,右键操作

<template>
<div class="table-box active" @mousedown="handleMouseDown" v-contextmenu.dark="contextmenus">
  <PocTable
    v-loading="loading"
    :data="tableData"
    cell-class-name="week-data-td"
    :cell-style="changeCell"
    @cell-dblclick="handleEdit"
    :current-page.sync="pageConfig.pageNum"
    :total="pageConfig.total"
    @size-change="pageSizeChange"
    @page-current-change="pageChange">
    <el-table-column
      v-for="item in columnConfig"
      :key="item.key"
      :prop="item.key"
      :label="item.name"
      :fixed="item.fixed"
      :sorter="item.sortable"
      :width="item.width">
        <template slot-scope="scope">
          <div class="cell-key" :name="scope.row[item.key].key">
              <span v-if="!scope.row[item.key].edit">{{scope.row[item.key].value}}</span>
              <select @blur="handleCancelEdit(scope.row[item.key],scope.$index)" v-else type="text" v-model="scope.row[item.key].value">
                <option label="111111111" value="1"></option>
                <option label="1222222222" value="2"></option>
              </select>
          </div>
        </template>
      </el-table-column>
  </PocTable>
  <div
       id="mask-background"
        class="mask"
        v-show="is_show_mask"
        :style="'width:'+mask_width()+'left:'+mask_left()+'height:'+mask_height()+'top:'+mask_top()"
      ></div>
</div>
  
</template>

<script>

export default {
  mixins: [$PCommon.TableMixin],

  data() {
    return {
      loading: false,
      columnConfig: [
        {
          key: 'a',
          name: 'a',
          dataType: 'number', // 字段的数值类型,字符串(string)、数字(number)、日期(date)、布尔(boolean)。
          visible: true, // 是否展示在表格列中
          sortable: true, // 是否可以排序
          fixed: 'left', // 固定列的位置(left, right)
          width: 200, // 默认宽度,像素
        },
        {
          key: 'b',
          name: 'b',
          dataType: 'string',
          visible: true,
          sortable: true,
          fixed: null,
          width: 200,
        },
        {
          key: 'c',
          name: 'c',
          dataType: 'number',
          visible: true,
          sortable: true,
          fixed: null,
          width: 200,
        },
        {
          key: 'd',
          name: 'd',
          dataType: 'number',
          visible: true,
          sortable: true,
          fixed: null,
          width: 200,
        },
        {
          key: 'e',
          name: 'e',
          dataType: 'number',
          visible: true,
          sortable: true,
          fixed: null,
          width: 200,
        },
        {
          key: 'f',
          name: 'f',
          dataType: 'number',
          visible: true,
          sortable: true,
          fixed: null,
          width: 200,
        },
        {
          key: 'g',
          name: 'g',
          dataType: 'number',
          visible: true,
          sortable: true,
          fixed: null,
          width: 200,
        },
        {
          key: 'h',
          name: 'h',
          dataType: 'number',
          visible: true,
          sortable: true,
          fixed: null,
          width: 200,
        },
        {
          key: 'i',
          name: 'i',
          dataType: 'number',
          visible: true,
          sortable: true,
          fixed: null,
          width: 200,
        },
        {
          key: 'j',
          name: 'j',
          dataType: 'number',
          visible: true,
          sortable: true,
          fixed: null,
          width: 200,
        },
        {
          key: 'k',
          name: 'k',
          dataType: 'number',
          visible: true,
          sortable: true,
          fixed: null,
          width: 200,
        },
        {
          key: 'l',
          name: 'l',
          dataType: 'number',
          visible: true,
          sortable: true,
          fixed: null,
          width: 200,
        },
        {
          key: 'm',
          name: 'm',
          dataType: 'number',
          visible: true,
          sortable: true,
          fixed: null,
          width: 200,
        },
        {
          key: 'n',
          name: 'n',
          dataType: 'number',
          visible: true,
          sortable: true,
          fixed: null,
          width: 200,
        },
        {
          key: 'o',
          name: 'o',
          dataType: 'number',
          visible: true,
          sortable: true,
          fixed: null,
          width: 200,
        },
        {
          key: 'p',
          name: 'p',
          dataType: 'number',
          visible: true,
          sortable: true,
          fixed: null,
          width: 200,
        },
        {
          key: 'q',
          name: 'q',
          dataType: 'number',
          visible: true,
          sortable: true,
          fixed: null,
          width: 200,
        },
        {
          key: 'r',
          name: 'r',
          dataType: 'number',
          visible: true,
          sortable: true,
          fixed: null,
          width: 200,
        },
      ],
      tableData: [],

      start_x: 0,
      start_y: 0,
      end_x: 0,
      end_y: 0,
      box_screen_left: '60',  //框选盒子距左边距离
      box_screen_top: '60',   //框选盒子距顶部距离
      is_show_mask: false,
      // rightmenus: false,
    };
  },

  mounted() {
    this.queryApi();
  },

  methods: {
    // 右键菜单
    contextmenus() {
      // this.rightmenus = true;
      return [
        {
          text: this.$t('nv:标记为未上刊'),
          action: () => {this.handleSign(0)} 
        },
        {
          text: this.$t('nv:标记为上刊'),
          action: () => {this.handleSign(1)}  
        },
      ]
    },
    handleSign(value) {
      // this.rightmenus = false;
    },
    queryApi() {
      this.loading = true;
      this.tableData = [];
      const list = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r']
      window.setTimeout(() => {
        for (let i = 0; i < 4; i++) {
          const item = {};
          list.forEach((v,index) => {
            item[v] = {
              key: `${v + Math.random() * 10}`,
              value: `${v + Math.random() * 10}`,
              edit: false,
            }
          })
          this.tableData.push(item);
        }
        this.pageConfig.total = 1;
        this.loading = false;
      }, 20);
    },
    changeCell(row, column, rowIndex, columnIndex) {
      if(row.row[row.column.property].checked) {
        return "background: #3af";
      }else {
        return "background: #FFF";
      }
    },
    handleEdit(row, column, rowIndex, columnIndex) {
      row[column.property].edit = true;
      row[column.property].checked = false;
    },
    handleCancelEdit(item) {
      item.edit = false;
    },
    // 框选操作
    mask_width() {
      return `${Math.abs(this.end_x - this.start_x)}px;`;
    },

    mask_height() {
      return `${Math.abs(this.end_y - this.start_y)}px;`;
    },

    mask_left() {
      return `${
        Math.min(this.start_x, this.end_x) - this.box_screen_left
      }px;`;
    },

    mask_top() {
      return `${
        Math.min(this.start_y, this.end_y) - this.box_screen_top
      }px;`;
    },
    handleMouseDown(e) {
      this.is_show_mask = true;
      this.start_x = e.pageX;
      this.start_y = e.pageY;
      this.end_x = e.pageX;
      this.end_y = e.pageY;
      document.body.addEventListener("mousemove", this.handleMouseMove);
      document.body.addEventListener("mouseup", this.handleMouseUp);
    },
    handleMouseMove(e) {
      this.end_x = e.pageX;
      this.end_y = e.pageY;
    },
    handleMouseUp(e) {
      if(Math.abs(this.end_x - this.start_x) < 5 && Math.abs(this.end_y - this.start_y) < 5) {
        // 位移不够,按点击算
        document.body.removeEventListener("mousemove", this.handleMouseMove);
        document.body.removeEventListener("mouseup", this.handleMouseUp);
        this.is_show_mask = false;
        this.resetXY();
        return false;
      }
      document.body.removeEventListener("mousemove", this.handleMouseMove);
      document.body.removeEventListener("mouseup", this.handleMouseUp);
      this.is_show_mask = false;
      this.handleDomSelect();
      this.resetXY();
    },
    resetXY() {
      this.start_x = 0;
      this.start_y = 0;
      this.end_x = 0;
      this.end_y = 0;
    },
    handleDomSelect() {
      
      const dom_mask = window.document.querySelector("#mask-background");
      // getClientRects() 方法返回一个指向客户端中每一个盒子的边界矩形的矩形集合
      const rect_select = dom_mask.getClientRects()[0];
      let selectKeys = [];
      document.querySelectorAll(".week-data-td").forEach((node, index) => {
        if(node.className.split(/\s+/).includes('is-hidden')) {
          // 隐藏单元格不错处理
          return false;
        }
        const rects = node.getClientRects()[0];
        if (this.collide(rects, rect_select) === true) {
          selectKeys.push(node.getElementsByClassName('cell-key')[0].getAttribute('name'));
        }
      });
      let tableList = JSON.parse(JSON.stringify(this.tableData));
      // 单选时
      if (selectKeys.length === 1) {
        tableList = tableList.map((item, key) => {
        for(let k in item){
          if (selectKeys.indexOf(item[k].key) > -1){
            item[k].checked = !item[k].checked;
          }else {
            item[k].checked = false;
          }
        }
        return item;
      });
        this.tableData = tableList;
        return false;
      };
      tableList = tableList.map((item, key) => {
        for(let k in item){
          if (selectKeys.indexOf(item[k].key) > -1){
            item[k].checked = true;
          }else{
            item[k].checked = false;
          }
        }
        return item;
      });
      this.tableData = tableList;
    },

    collide(rect1, rect2) {
      const maxX = Math.max(rect1.x + rect1.width, rect2.x + rect2.width);
      const maxY = Math.max(rect1.y + rect1.height, rect2.y + rect2.height);
      const minX = Math.min(rect1.x, rect2.x);
      const minY = Math.min(rect1.y, rect2.y);
      if (
        maxX - minX <= rect1.width + rect2.width &&
        maxY - minY <= rect1.height + rect2.height
      ) {
        return true;
      } else {
        return false;
      }
    }
  },
};
</script>
<style scoped lang="scss">
#mask-background {
  position: absolute;
  background: #409eff;
  opacity: 0.4;
  z-index: 10000000000000;
}
//禁止文本选中
.table-box {
  &.active {
    -moz-user-select:none;
      -webkit-user-select:none;
      user-select:none;   
  }
       
} 
</style>
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值