当前位置: 首页 > news >正文

Vue+Element Ui实现el-table自定义表头下拉选择表头筛选

用vue+element ui开发管理系统时,使用el-table做表格,当表格列过多的时候,想要做成可选表头的,实现表格列的筛选显示,效果如下:

代码文件结构:

废话不多说,直接上代码:

第一步:新建名为 TableHeaderRender.vue 的文件

<template>

  <el-popover

    placement="bottom"

    width="200"

    trigger="manual"

    v-model="visible"

    @show="showPopover"

    popper-class="table-header-popover"

  >

    <div class="table-header-popover-template">

      <el-input

        placeholder="请输入内容"

        v-model="value"

        size="small"

        clearable

        @keyup.enter.native="confirm"

        ref="sInput"

      >

        <!-- <el-button slot="append" icon="el-icon-search" @click="confirm"> -->

        <!-- </el-button> -->

      </el-input>

    </div>

    <div class="el-table-filter__bottom">

      <button @click="confirm">筛选</button>

      <button @click="resetData">重置</button>

    </div>

    <span

      slot="reference"

      style="margin-left: 5px"

      @click.stop="popClick"

      v-click-outside="closeOver"

    >

      <i

        class="filter-icon el-icon-search"

        :style="{ color: iconColor ? '#9a4b9b' : '#909399' }"

      ></i>

      <!-- <i class="el-icon-search" :style="{'color':iconColor}" ></i> -->

      <!-- <svg

        viewBox="64 64 896 896"

        data-icon="search"

        width="1em"

        height="1em"

        fill="currentColor"

        :style="{

          color: iconColor ? '#9A4B9B' : '',

          'margin-right': '2px',

          cursor: 'pointer',

        }"

      >

        <path

          d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0 0 11.6 0l43.6-43.5a8.2 8.2 0 0 0 0-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"

        ></path>

      </svg> -->

    </span>

  </el-popover>

</template>

<script>

export default {

  name: "tableHeaderRender",

  data() {

    return {

      // input 绑定的值

      value: "",

      visible: false,

      iconColor: false,

    };

  },

  props: {

    tableColumn: {

      type: Object,

      default: () => {},

    },

    columnProp: {

      type: String,

      default: "",

    },

    defaultValue: {

      type: String,

      default: "",

    },

    inputFilteredMap: {

      type: Object,

      default: () => {},

    },

  },

  created() {

    this.value = this.defaultValue;

    this.iconColor = this.value.trim() ? true : false;

  },

  methods: {

    showPopover() {

      this.$nextTick(() => {

        this.$refs.sInput.focus();

      });

    },

    resetData() {

      console.log("reset");

      this.value = "";

      this.visible = false;

      this.iconColor = false;

      const self = this;

      if (this.inputFilteredMap[self.columnProp]) {

        delete this.inputFilteredMap[self.columnProp];

      }

      self.$emit("resetChangeMethod", this.tableColumn, self.columnProp);

    },

    closeOver() {

      this.visible = false;

    },

    popClick(e) {

      // e.stopPropagation()

      this.visible = !this.visible;

    },

    confirm() {

      this.visible = false;

      if (this.value.trim()) {

        this.iconColor = true;

        this.inputFilteredMap[this.columnProp] = this.value;

        this.$emit(

          "filterInputMethod",

          this.tableColumn,

          this.inputFilteredMap

        );

      } else {

        // 如果搜索input输入为空,等同重置

        this.resetData();

      }

    },

  },

  directives: {

    clickOutside: {

      bind(el, binding, vnode) {

        function clickHandler(e) {

          // 这里判断点击的元素是否是本身,是本身,则返回

          if (el.contains(e.target)) {

            return false;

          }

          // 判断指令中是否绑定了函数

          if (binding.expression) {

            // 如果绑定了函数 则调用那个函数,此处binding.value就是handleClose方法

            binding.value(e);

          }

        }

        // 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听

        el.__vueClickOutside__ = clickHandler;

        document.addEventListener("click", clickHandler);

      },

      update() {},

      unbind(el, binding) {

        // 解除事件监听

        document.removeEventListener("click", el.__vueClickOutside__);

        delete el.__vueClickOutside__;

      },

    },

  },

};

</script>

<style>

.filter-icon {

  font-size: 14px;

  color: #909399;

  cursor: pointer;

  font-weight: 400;

}

.table-header-popover {

  padding: 0;

}

.table-header-popover .table-header-popover-template {

  margin: 10px;

}

</style>




 

第二步:新建名为 operateTable.vue 的文件

<template>

  <div class="operateTable">

    <el-dropdown

      size="small"

      trigger="click"

      v-if="options.columnsSelect || options.columnsTreeSelect"

      class="column-dropdown"

    >

      <el-button style="padding: 9px 10px!important" size="small">

        <i style="font-size: 12px" class="el-icon-menu"></i>

        <i class="el-icon-arrow-down el-icon--right"></i>

      </el-button>

      <el-dropdown-menu slot="dropdown">

        <div style="margin:10px;" class="caoz_ft_warp" v-if="isInit||isSave">

          <el-button

            v-if="isInit"

            size="small"

            type="primary" 

            plain

            style="width:70px;"

            @click="initColumns(true)"

          >初始化</el-button>

          <el-button

            v-if="isSave"

            size="small"

            type="primary" 

            plain

            style="width:70px;"

            @click="$emit('saveSettingColumns',checkedList)"

           >保存</el-button>

        </div>

        <div style="margin:10px;" class="caoz_ft_warp">

          <el-input size="small" placeholder="请输入关键字" v-model="cloumnKeyword" clearable></el-input>

        </div>

        <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange" style="padding-left:10px;">Select All</el-checkbox>

        <el-checkbox-group

          v-if="!options.columnsTreeSelect"

          v-model="checkedList"

          style="max-height: 300px"

          @change="handleCheckedCitiesChange"

        >

          <div class="checkboxScorll">

            <template v-for="(option, index) in checkBoxOptions">

              <template v-if="cloumnKeyword && option.toLowerCase().indexOf(cloumnKeyword.toLowerCase())>-1">

                <el-checkbox

                  :key="index"

                  class="checkbox"

                  :label="option"

                ></el-checkbox>

              </template>

              <template v-else-if="!cloumnKeyword">

                <el-checkbox

                  :key="index"

                  class="checkbox"

                  :label="option"

                ></el-checkbox>

              </template>

              <template v-else></template>

            </template>

          </div>

        </el-checkbox-group>

        <div v-else class="checkboxTree">

          <el-tree

            ref="tree"

            :check-on-click-node="true"

            :data="treeColumn"

            show-checkbox

            node-key="label"

            :default-expanded-keys="defaultExpanded"

            :default-checked-keys="defaultChecked"

            :props="{

              children: 'children',

              label: 'label',

            }"

            @check="checkChange"

            style="max-height: 300px; overflow-y: auto"

          >

          </el-tree>

        </div>

      </el-dropdown-menu>

    </el-dropdown>

    <el-table

      id="iTable"

      ref="operateTable"

      border

      :data="dataSource"

      :stripe="options.stripe"

      :highlight-current-row="options.highlightCurrentRow"

      :max-height="options.maxHeight"

      :size="options.size"

      :fit="options.fit"

      :show-header="options.showHeader"

      :empty-text="options.emptyText"

      :default-sort="options.defaultSort"

      :row-key="getRowKeys"

      :default-expand-all="options.defaultExpandAll"

      :tree-props="options.treeProps"

      :lazy="options.lazy"

      :load="load"

      @cell-mouse-enter="cellMouseEnter"

      @cell-mouse-leave="cellMouseLeave"

      @cell-click="cellClick"

      @cell-dblclick="cellDblclick"

      @row-click="rowClick"

      @row-contextmenu="rowContextmenu"

      @row-dblclick="rowDblclick"

      @header-click="headerClick"

      @header-contextmenu="headerContextmenu"

      @sort-change="sortChange"

      @select="select"

      @select-all="selectAll"

      @selection-change="checkboxSelected"

      @filter-change="filterChange"

    >

      <slot name="expandRow"></slot>

      <!-- 复选框 -->

      <el-table-column

        :reserve-selection="options.reserveSelection"

        :key="0"

        type="selection"

        :selectable="selectable"

        width="40"

        align="left"

        v-if="options.showCheckBox"

        :resizable="false"

      >

      </el-table-column>

      <el-table-column

        ref="fixedColumn"

        label="操作"

        align="left"

        :width="operates.dropDown ? '50' : operates.width"

        :fixed="operates.fixed"

        :min-width="operates.minwidth"

        :resizable="operates.resizable"

        v-if="operates.list.length > 0"

      >

        <template slot-scope="scope">

          <!-- 操作列 不折叠 全为icon-->

          <div

            class="operate-group"

            v-if="!operates.dropDown && !operates.isText"

          >

            <template

              v-for="item in operates.list[0] instanceof Array

                ? operates.list[scope.$index]

                : operates.list"

            >

              <div class="item" v-if="item.show" :key="item.id">

                <el-switch

                  v-if="item.type === 'switch'"

                  v-model="scope.row[item.prop]"

                  active-color="#13ce66"

                  @change="item.method(scope.$index, scope.row)"

                ></el-switch>

                <el-tooltip

                  v-else-if="item.type === 'tooltipIcon'"

                  :enterable="false"

                  effect="light"

                  placement="bottom"

                >

                  <div slot="content">{{ item.tooltip }}</div>

                  <el-button 

                    type="primary" 

                    plain 

                    :icon="item.icon"

                    size="mini" 

                    :disabled="item.disabled"

                    @click="item.method(scope.$index, scope.row)"

                  ></el-button>

                </el-tooltip>

                <el-button 

                  v-else-if="item.type === 'icon'"

                  type="primary" 

                  plain 

                  :icon="item.icon"

                  size="mini" 

                  :disabled="item.disabled"

                  @click="item.method(scope.$index, scope.row)"

                ></el-button>

              </div>

            </template>

          </div>

          <!-- 操作列 不折叠 全为文字-->

          <div

            class="operate-group"

            v-if="!operates.dropDown && operates.isText"

          >

            <template

              v-for="item in operates.list[0] instanceof Array

                ? operates.list[scope.$index]

                : operates.list"

            >

              <div class="item" v-if="item.show" :key="item.id">

                <el-button

                  size="small"

                  type="text"

                  :disabled="item.disabled"

                  @click.native.prevent="item.method(scope.$index, scope.row)"

                  >{{ item.label }}</el-button

                >

              </div>

            </template>

          </div>

          <!-- 操作列 折叠下拉-->

          <div class="operate-group" v-else-if="operates.dropDown">

            <el-dropdown

              @command="handleCommand"

              trigger="hover"

              placement="bottom-start"

            >

              <span class="el-dropdown-link">

                <i class="el-icon-s-unfold" style="font-size: 16px;"></i>

              </span>

              <!-- 根据operates.list 来渲染操作列下拉的内容 -->

              <el-dropdown-menu slot="dropdown">

                <el-dropdown-item

                  v-for="(item, index) in operates.list[0] instanceof Array

                    ? operates.list[scope.$index]

                    : operates.list"

                  :disabled="item.disabled"

                  :key="index"

                  :command="composeValue(item, scope.row, scope.$index)"

                  >{{ item.label }}</el-dropdown-item

                >

              </el-dropdown-menu>

            </el-dropdown>

          </div>

        </template>

      </el-table-column>

      <!--region 数据列-->

      <template v-for="column in columns">

        <!-- :filter-method="column.filters ? column.filterMethod : undefined" -->

        <!-- v-if="

            options.columnsSelect || options.columnsTreeSelect

              ? checkedList.includes(column.label)

              : true

          " -->

        <el-table-column

          v-if="

            options.columnsSelect || options.columnsTreeSelect

              ? checkedList.includes(column.label)

              : true

          "

          :prop="column.prop"

          :key="column.label"

          :label="column.label"

          align="left"

          :width="column.width"

          :min-width="column.minwidth"

          :resizable="column.resizable"

          :sortable="column.sortable"

          :filters="column.filters"

          :filter-method="column.filters ? column.filterMethod : undefined"

          :filtered-value="column.filteredValue"

          :fixed="column.fixed"

          :column-key="column.prop"

        >

          <template slot="header" slot-scope="scope"

            >{{ column.label }}

            <TableHeaderRender

              v-if="column.filterInput"

              :columnProp="column.prop"

              :tableColumn="scope.column"

              :defaultValue="column.defaultValue"

              :inputFilteredMap="inputFilteredMap"

              @filterInputMethod="filterInputMethod"

              @resetChangeMethod="resetChangeMethod"

            ></TableHeaderRender>

          </template>

          <!-- :filtered-value="column.filteredValue" -->

          <template slot-scope="scope">

            <!-- 如果传进来的column没有render函数执行以下代码 -->

            <template v-if="!column.render">

              <!-- 如果传进来的column没有render函数但有formatter函数执行以下代码 -->

              <template v-if="column.formatter">

                <span v-html="column.formatter(scope.row, column)"></span>

              </template>

              <!-- 如果传进来的column既没有render函数也没有formatter函数执行以下代码 -->

              <template v-else>

                <span>{{ scope.row[column.prop] }}</span>

              </template>

            </template>

            <!-- 如果传进来的column有render函数执行以下代码 -->

            <template v-else>

              <expand-dom

                :column="column"

                :row="scope.row"

                :render="column.render"

                :index="scope.$index"

              ></expand-dom>

            </template>

          </template>

        </el-table-column>

      </template>

      <!--endregion-->

    </el-table>

  </div>

</template>

<script>

import TableHeaderRender from "./TableHeaderRender.vue";

export default {

  name: "OperateTable",

  props: {

    // 表格的数据源

    dataSource: {

      type: Array,

      default: () => [],

    },

    // 需要展示的列

    columns: {

      type: Array,

      default: () => [{}],

    },

    // table 表格的控制参数

    options: {

      type: Object,

      default: () => {

        return {

          stripe: true, // 是否为斑马纹 table

        };

      },

    },

    // 操作按钮组 === label: 文本,show:是否显示,icon:按钮图标,disabled:是否禁用,method:回调方法, 等等

    operates: {

      type: Object,

      default: () => {

        return {

          list: [],

        };

      },

    },

    defaultSelectedColumn: {

      type: Array,

      default: () => [],

    },

    defaultColumn: {

      type: Array,

      default: () => [],

    },

    totalColumn: {

      type: Array,

      default: () => [],

    },

    treeColumn: {

      type: Array,

      default: () => [],

    },

    defaultChecked: {

      type: Array,

      default: () => [],

    },

    defaultExpanded: {

      type: Array,

      default: () => [],

    },

    isInit: {

      type: Boolean,

      default: false

    },

    isSave: {

      type: Boolean,

      default: false

    }

  },

  components: {

    TableHeaderRender,

    expandDom: {

      functional: true,

      props: {

        row: Object,

        render: Function,

        index: Number,

        column: {

          type: Object,

          default: null,

        },

      },

      render: (h, ctx) => {

        const params = {

          row: ctx.props.row,

          index: ctx.props.index,

        };

        if (ctx.props.column) params.column = ctx.props.column;

        return ctx.props.render(h, params);

      },

    },

  },

  data() {

    return {

      cloumnKeyword:"",//字段关键字搜索

      isIndeterminate:true,//全选状态

      checkAll:false,//字段全选

      checkBoxOptions: [], // 全部表头

      checkedList: [], // 选中表头

      count: 0, // 用于判断表格是否刚渲染

      isCheckBoxSort: false, // 用于判断是否是由自定义数据列引发的排序

      // 以下是之前放于vuex中用于记录状态

      preCheckedList: [], // 前一次的checkbox

      // 排序的状态

      sort: {

        prop: "",

        order: "",

        label: "",

      },

      // 筛选的状态

      checkBoxFilteredMap: {},

      // input 所有的筛选

      inputFilteredMap: {},

      // columns label及prop对应的键值对

      columnsLabelMap: {}

    };

  },

  watch: {

    // 监听defaultColumn,若这个发生变化,代表传入的默认column变化,即数据表格发生了切换

    defaultColumn() {

      this.initColumns();

    },

    checkedList() {

      // if(this.checkedList.length>0){

      //   this.$emit("selectedColumn",this.checkedList);

      // }

      // 处理当点击checkbox显示的是排序列时,恢复排序列的显示

      let showLabelArray = this.checkboxShowLabel();

      console.log("showLabelArray", showLabelArray);

      // if (value.length !== 0) {

      //   value.map((item) => {

      //     this.handleStatusRevert(item);

      //   });

      this.columns.map((column, index) => {

        this.handleStatusRevert(column, index, showLabelArray);

      });

    },

  },

  created() {

    this.normalizeColumnsLabelMap();

  },

  mounted() {

    if (!this.options.columnsTreeSelect) {

      this.checkedList = this.$props.defaultColumn;

      this.checkBoxOptions = this.$props.totalColumn;

    } else {

      this.checkedList = this.$refs.tree

        .getCheckedNodes()

        .map((item) => item.label);

    }

    // 挂载时将defaultSort属性传给vuex

    this.handleDefaultSort();

  },

  // 动态切换表头的时候闪烁是因为表头重新计算高度导致的,以下方法解决此bug

  beforeUpdate() {

    this.$nextTick(() => {

      //在数据加载完,重新渲染表格

      this.$refs["operateTable"].doLayout();

    });

  },

  methods: {

    //全选字段

    handleCheckAllChange(val){

      this.checkedList = val ? this.checkBoxOptions : [];

      this.isIndeterminate = false;

    },

    //反选

    handleCheckedCitiesChange(value){

      let checkedCount = value.length;

      this.checkAll = checkedCount === this.checkBoxOptions.length;

      this.isIndeterminate = checkedCount > 0 && checkedCount < this.checkBoxOptions.length;

    },

    //初始化字段

    initColumns(flag){

      if(flag){

        this.checkedList = this.$props.defaultSelectedColumn;

      }else{

        this.checkedList = this.$props.defaultColumn;

      }

      this.checkBoxOptions = this.$props.totalColumn;

    },

    // 处理判断checkbox 点击时,显示的是哪个字段名

    checkboxShowLabel() {

      // 判断显示的字段是哪个字段,如果是树形,可能有多个,故更改为数组接收

      let value = [];

      console.log("this.checkedList", this.checkedList);

      if (this.count === 0) {

        this.saveCheckedList(this.checkedList);

        // this.$componentsStore.commit("table/saveCheckedList", this.checkedList);

        this.count++;

      } else {

        if (this.checkedList.length > this.preCheckedList.length) {

          for (let index = 0; index < this.checkedList.length; index++) {

            if (!this.preCheckedList.includes(this.checkedList[index])) {

              value.push(this.checkedList[index]);

            }

            // if (this.checkedList[index] !== this.preCheckedList[index]) {

            //   value = this.checkedList[index];

            // }

          }

        }

        this.saveCheckedList(this.checkedList);

        // this.$componentsStore.commit("table/saveCheckedList", this.checkedList);

      }

      return value;

    },

    // 处理sort\filterd由隐藏变为显示状态的恢复

    handleStatusRevert(column, index, showLabelArray) {

      let compareLabel = column.label;

      if (showLabelArray.includes(compareLabel)) {

        // 如果是有checkbox 筛选的字段,恢复筛选

        let filteredValue =

          this.checkBoxFilteredMap[this.columnsLabelMap[compareLabel]];

        // 如果是有input 筛选的字段,恢复筛选

        let filteredInputValue =

          this.inputFilteredMap[this.columnsLabelMap[compareLabel]];

        this.columns[index].filteredValue = filteredValue;

        this.columns[index].defaultValue = filteredInputValue;

        this.$nextTick(() => {

          this.$refs.operateTable.store.states.columns.map((column) => {

            if (column.filteredValue && column.filteredValue.length) {

              this.$refs.operateTable.store.commit("filterChange", {

                column,

                values: column.filteredValue,

                silent: true,

              });

            }

          });

        });

      } else {

        this.columns[index].filteredValue = [];

        this.columns[index].defaultValue = "";

      }

      // 如果是有排序的字段,恢复排序

      if (showLabelArray.includes(this.sort.label)) {

        this.$nextTick(() => {

          //在数据加载完,重新渲染表格

          this.isCheckBoxSort = true;

          this.$refs.operateTable.sort(this.sort.prop, this.sort.order);

        });

      }

      /**

      // 如果是有checkbox 筛选的字段,恢复筛选

      let filteredValue = this.checkBoxFilteredMap[this.columnsLabelMap[value]];

      // 如果是有input 筛选的字段,恢复筛选

      let filteredInputValue = this.inputFilteredMap[

        this.columnsLabelMap[value]

      ];

      for (let i = 0; i < this.columns.length; i++) {

        if (this.columns[i].label === value) {

          this.columns[i].filteredValue = filteredValue;

          this.columns[i].defaultValue = filteredInputValue;

          this.$nextTick(() => {

            this.$refs.operateTable.store.states.columns.map((column) => {

              if (column.filteredValue && column.filteredValue.length) {

                console.log("!11");

                this.$refs.operateTable.store.commit("filterChange", {

                  column,

                  values: column.filteredValue,

                  silent: true,

                });

              }

            });

          });

        } else {

          this.columns[i].filteredValue = [];

          this.columns[i].defaultValue = "";

        }

      }

      // for (let i = 0; i < this.columns.length; i++) {

      //   if (this.columns[i].label === value) {

      //     this.columns[i].defaultValue = filteredInputValue;

      //   } else {

      //     this.columns[i].defaultValue = "";

      //   }

      // }

      // 如果是有排序的字段,恢复排序

      if (value === this.sort.label) {

        this.$nextTick(() => {

          //在数据加载完,重新渲染表格

          this.isCheckBoxSort = true;

          this.$refs.operateTable.sort(this.sort.prop, this.sort.order);

        });

      }

      */

    },

    // 处理生成columns 的label prop键值对

    normalizeColumnsLabelMap() {

      this.columns.map((column) => {

        this.columnsLabelMap[column.label] = column.prop;

      });

    },

    filterInputMethod(column, inputFilteredMap) {

      console.log("column, inputFilteredMap", column, inputFilteredMap);

      this.inputFilteredMap = inputFilteredMap;

      this.$emit("filterInputMethod", column, inputFilteredMap);

    },

    resetChangeMethod(tableColumn, columnProp) {

      this.$emit("resetChangeMethod", tableColumn, this.inputFilteredMap);

    },

    cellMouseEnter(row, column, cell, event) {

      this.$emit("cell-mouse-enter", row, column, cell, event);

    },

    cellMouseLeave(row, column, cell, event) {

      this.$emit("cell-mouse-leave", row, column, cell, event);

    },

    cellClick(row, column, cell, event) {

      this.$emit("cell-click", row, column, cell, event);

    },

    cellDblclick(row, column, cell, event) {

      this.$emit("cell-dblclick", row, column, cell, event);

    },

    rowClick(row, column, event) {

      this.$emit("row-click", row, column, event);

    },

    rowContextmenu(row, column, event) {

      this.$emit("row-contextmenu", row, column, event);

    },

    rowDblclick(row, column, event) {

      this.$emit("row-dblclick", row, column, event);

    },

    headerClick(column, event) {

      this.$emit("header-click", column, event);

    },

    headerContextmenu(column, event) {

      this.$emit("header-contextmenu", column, event);

    },

    sortChange(sortObj) {

      this.changeSort(sortObj);

      // this.$componentsStore.commit("table/changeSort", sortObj);

      if (!this.isCheckBoxSort) {

        this.$emit("sort-change", sortObj);

      }

      // 还原isCheckBoxSort

      this.isCheckBoxSort = false;

    },

    handleDefaultSort() {

      if (this.options.defaultSort !== undefined) {

        let column = { label: "" };

        // for (let index = 0; index < this.columns.length; index++) {

        //   if (this.columns[index].prop === this.options.defaultSort.prop) {

        //     column.label = this.columns[index].label;

        //     break;

        //   }

        // }

        column.label = this.columnsLabelMap[this.options.defaultSort.prop];

        this.changeSort({

          ...this.options.defaultSort,

          column,

        });

      }

    },

    // 点击操作的下拉项目后触发事件

    handleCommand(command) {

      if (command.method) {

        command.method(command.index, command.row, command.label);

      }

    },

    // 点击dropDown传参方法

    composeValue(item, row, index) {

      return {

        label: item.label,

        row: row,

        index: index,

        method: item.method,

      };

    },

    select(selection, row) {

      this.$emit("select", selection, row);

    },

    selectAll(selection) {

      this.$emit("select-all", selection);

    },

    checkboxSelected(selection) {

      this.$emit("selection-change", selection);

    },

    selectable(row, index) {

      let data = true;

      this.$emit("selectable", row, index, (val) => {

        data = val;

      });

      return data;

    },

    getRowKeys(row) {

      let data;

      for (let index = 0; index < this.dataSource.length; index++) {

        if (row === this.dataSource[index]) {

          data = index;

          break;

        }

      }

      // this.dataSource.map((item, index) => {

      //   if (row === item) {

      //     data = index;

      //   }

      // });

      this.$emit("row-key", row, (val) => {

        data = val;

      });

      return data;

    },

    load(tree, treeNode, resolve) {

      this.$emit("load", tree, treeNode, resolve);

    },

    // 记录表格总的筛选状态,用于列显示隐藏时保存checkbox状态

    filterChange(filters) {

      let currKey = Object.keys(filters)[0];

      if (filters[currKey].length === 0) {

        delete this.checkBoxFilteredMap[currKey];

      } else {

        this.checkBoxFilteredMap[currKey] = filters[currKey];

      }

      this.$emit("filter-change", filters);

    },

    checkChange(nodeObj, checkObj) {

      this.checkedList = checkObj.checkedNodes.map((item) => {

        return item.label;

      });

    },

    // 之前写在vuex里的方法

    changeSort(sort) {

      this.sort.prop = sort.prop;

      this.sort.order = sort.order;

      this.sort.label = sort.column.label;

    },

    saveCheckedList(preCheckedList) {

      this.preCheckedList = preCheckedList;

    },

  },

};

</script>

<style>

    .operateTable{

        position: relative;

        width: 100%;

    }

    .operateTable .column-dropdown{

        position: absolute;

        right: 0px;

        top: -42px;

        z-index: 99;

    }

    .caoz_ft_warp{

      text-align: center;

    }

    .caoz_ft_warp .el-input.is-active .el-input__inner, .caoz_ft_warp .el-input__inner:focus{

        border-color: #9A4B9B;

        outline: 0;

    }

    .el-checkbox__input.is-checked .el-checkbox__inner,.el-checkbox__input.is-indeterminate .el-checkbox__inner {

        background-color: #9a4b9b;

        border-color: #9a4b9b;

    }

    .el-checkbox__inner:hover {

        border-color: #9A4B9B;

    }

    .el-checkbox__input.is-focus .el-checkbox__inner{

        border-color: #9A4B9B;

    }

    .el-checkbox__input.is-checked+.el-checkbox__label {

        color: #9A4B9B;

    }

    .checkboxScorll .el-checkbox__input.is-checked + .el-checkbox__label {

        color: #666;

    }

    .column-dropdown .el-button{margin-right: 0 !important;min-width:0;}

    .column-dropdown .el-button:focus, .el-button:hover{

        color: #9A4B9B;

        border-color: #e1c9e1;

        background-color: #f5edf5;

    }

    .checkboxScorll {

        max-height: 300px;

        overflow-y: auto;

    }

    .checkboxScorll .checkbox {

        display: block;

        margin-top: 10px;

        padding-left: 20px;

    }

</style>

第三步:在页面中引入operateTable并使用

<template>

  <div class="tableView">

    <div class="content">

      <operateTable

        v-loading="loading"

        :dataSource="operateTableData"

        :columns="operateTableColumns"

        :options="operateTableOption"

        :defaultColumn="defaultColumns"

        :totalColumn="totalColumns"

        :defaultSelectedColumn="defaultSelectedColumn"

        @sort-change="sortChange"

        @saveSettingColumns="saveSettingColumns"

      ></operateTable>

    </div>

  </div>

</template>

<script>

import operateTable from "./components/operateTable.vue";

export default {

  name: "",

  components: {

    operateTable,

  },

  data() {

    return {

      loading: false,

      operateTableData: [

        {

          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 弄",

        },

      ],

      operateTableColumns: [

        {

          prop: "action",

          label: "操作",

          width: 100,

          fixed: true,

          render: (h, params) => {

            return h(

              "div",

              {

                class: "operate-group",

              },

              [

                h(

                  "el-tooltip",

                  {

                    props: {

                      content: "处理",

                      placement: "bottom",

                      enterable: false,

                      effect: "light",

                    },

                    class: "item",

                  },

                  [

                    h("i", {

                      props: {},

                      class: "el-icon-edit",

                      on: {

                        click: () => {

                          console.log(params.row);

                        },

                      },

                    }),

                  ]

                ),

              ]

            );

          },

        },

        {

          prop: "date",

          label: "日期",

          minwidth: 150,

          sortable: "custom",

        },

        {

          prop: "name",

          label: "姓名",

          minwidth: 150,

          sortable: "custom",

        },

        {

          prop: "address",

          label: "地址",

          minwidth: 150,

          sortable: "custom",

        },

      ],

      operateTableOption: {

        stripe: true, // 是否为斑马纹 table

        highlightCurrentRow: true, // 是否要高亮当前行

        columnsSelect: true,

        maxHeight: 300,

      },

      defaultColumns: ["操作", "日期", "姓名", "地址"],

      totalColumns: ["操作", "日期", "姓名", "地址"],

      //所有用户默认勾选的列  用于初始化

      defaultSelectedColumn: [],

    };

  },

  methods: {

    //表头排序

    sortChange(column, prop, order) {

      if (column.order === "ascending") {

        this.orderfield = column.prop;

        this.orderby = "ASC";

      } else if (column.order === "descending") {

        this.orderfield = column.prop;

        this.orderby = "DESC";

      } else {

        this.orderfield = "";

        this.orderby = "";

      }

      //   this.getTabldHandle();

    },

    //保存自定义字段

    saveSettingColumns(data) {

      console.log(data);

    },

  },

  mounted() {},

};

</script>

<style>

.tableView {

  width: 100%;

  height: 100%;

}

.content {

  padding: 60px;

}

.disableIcon {

  color: #c0c4cc;

  cursor: not-allowed;

}

</style>

 

 

相关文章:

Vue+Element Ui实现el-table自定义表头下拉选择表头筛选

用vueelement ui开发管理系统时&#xff0c;使用el-table做表格&#xff0c;当表格列过多的时候&#xff0c;想要做成可选表头的&#xff0c;实现表格列的筛选显示&#xff0c;效果如下&#xff1a; 代码文件结构&#xff1a; 废话不多说&#xff0c;直接上代码&#xff1a; 第…...

使用Java连接MongoDB (6.0.12) 报错

报错&#xff1a; Exception in thread "main" com.mongodb.MongoCommandException: Command failed with error 352: Unsupported OP_QUERY command: create. 上图中“The client driver may require an upgrade”说明了“客户端驱动需要进行升级”&#xff0c;解…...

数学建模day16-预测模型

本讲首先将介绍灰色预测模型&#xff0c;然后将简要介绍神经网络在数据预测中的应用&#xff0c;在本讲的最 后&#xff0c;我将谈谈清风大佬对于数据预测的一些看法。 注&#xff1a;本文源于数学建模学习交流相关公众号观看学习视频后所作 目录 灰色系统 GM(1,1)…...

Vue3响应式系统(一)

一、副作用函数。 副作用函数指的是会产生副作用的函数。例如&#xff1a;effect函数会直接或间接影响其他函数的执行&#xff0c;这时我们便说effect函数产生了副作用。 function effect(){document.body.innerText hello vue3 } 再例如&#xff1a; //全局变量let val 2f…...

MStart | MStart开发与学习

MStart | MStart开发与学习 1.学习 1.MStart |开机LOG显示异常排查及调整...

GoZero微服务个人探索之路(一)Etcd:context deadline exceeded原因探究及解决

产生错误原因就是与etcd交互时候需要指定&#xff1a; 证书文件的路径 客户端证书文件的路径 客户端密钥文件的路径 &#xff08;同时这貌似是强制默认就需要指定了&#xff09; 但我们怎么知道这三个文件路径呢&#xff0c;如下方法 1. 找到etcd的配置文件&#xff0c;里…...

C语言从入门到实战——结构体与位段

结构体与位段 前言一、结构体类型的声明1.1 结构体1.1.1 结构的声明1.1.2 结构体变量的创建和初始化 1.2 结构的特殊声明1.3 结构的自引用 二、 结构体内存对齐2.1 对齐规则2.2 为什么存在内存对齐2.3 修改默认对齐数 三、结构体传参四、 结构体实现位段4.1 什么是位段4.2 位段…...

java如何修改windows计算机本地日期和时间?

本文教程&#xff0c;主要介绍&#xff0c;在java中如何修改windows计算机本地日期和时间。 目录 一、程序代码 二、运行结果 一、程序代码 package com;import java.io.IOException;/**** Roc-xb*/ public class ChangeSystemDate {public static void main(String[] args)…...

flink中的row类型详解

在Apache Flink中&#xff0c;Row 是一个通用的数据结构&#xff0c;用于表示一行数据。它是 Flink Table API 和 Flink DataSet API 中的基本数据类型之一。Row 可以看作是一个类似于元组的结构&#xff0c;其中包含按顺序排列的字段。 Row 的字段可以是各种基本数据类型&…...

漏洞复现-Yearning front 任意文件读取漏洞(附漏洞检测脚本)

免责声明 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直接或者间接的…...

K8S中SC、PV、PVC的理解

存储类&#xff08;StorageClass&#xff09;定义了持久卷声明&#xff08;PersistentVolumeClaim&#xff09;所需的属性和行为&#xff0c;而持久卷&#xff08;PersistentVolume&#xff09;是实际的存储资源&#xff0c;持久卷声明&#xff08;PersistentVolumeClaim&#…...

Agisoft Metashape 基于影像的外部点云着色

Agisoft Metashape 基于影像的外部点云着色 文章目录 Agisoft Metashape 基于影像的外部点云着色前言一、添加照片二、对齐照片三、导入外部点云四、为点云着色五、导出彩色点云前言 本教程介绍了在Agisoft Metashape Professional中,将照片中的真实颜色应用于从不同源获取的…...

图解结算平台:准确高效给商户结款

这是《百图解码支付系统设计与实现》专栏系列文章中的第&#xff08;4&#xff09;篇。 本章主要讲清楚支付系统中商户结算涉及的基本概念&#xff0c;产品架构、系统架构&#xff0c;以及一些核心的流程和相关领域模型、状态机设计等。 1. 前言 收单结算是支付系统最重要的子…...

修改和调试 onnx 模型

1. onnx 底层实现原理 1.1 onnx 的存储格式 ONNX 在底层是用 Protobuf 定义的。Protobuf&#xff0c;全称 Protocol Buffer&#xff0c;是 Google 提出的一套表示和序列化数据的机制。使用 Protobuf 时&#xff0c;用户需要先写一份数据定义文件&#xff0c;再根据这份定义文…...

不同整数的最少数目和单词直接最短距离

写是为了更好的思考&#xff0c;坚持写作&#xff0c;力争更好的思考。 今天分享两个关于“最小、最短”的算法题&#xff0c;废话少说&#xff0c;show me your code&#xff01; 一、不同整数的最少数目 给你一个整数数组arr和一个整数k。现需要从数组中恰好移除k个元素&…...

【Microsoft Edge】版本 109.0.1518.55 (正式版本) (64 位) 更新失败解决方案

Microsoft Edge 版本号 109.0.1518.55&#xff08;正式版本&#xff09;&#xff08;64位&#xff09; 更新直接报错 检查更新时出错: 无法创建该组件(错误代码 3: 0x80040154 – system level) 问题出现之前 之前电脑日常硬盘百分百&#xff08;删文件和移动文件都慢得像…...

深度学习笔记(四)——使用TF2构建基础网络的常用函数+简单ML分类实现

文中程序以Tensorflow-2.6.0为例 部分概念包含笔者个人理解&#xff0c;如有遗漏或错误&#xff0c;欢迎评论或私信指正。 截图和程序部分引用自北京大学机器学习公开课 TF2基础常用函数 1、张量处理类 强制数据类型转换&#xff1a; a1 tf.constant([1,2,3], dtypetf.floa…...

大模型学习篇(一):初识大模型

目录 一、大模型的定义 二、大模型的基本原理与特点 三、大模型的分类 四、大模型的相关落地产品 五、总结 一、大模型的定义 大模型是指具有数千万甚至数亿参数的深度学习模型。大模型具有以下特点&#xff1a; 参数规模庞大&#xff1a;大模型的一个关键特征是其包含了…...

uni-app的学习【第二节】

四 路由配置及页面跳转 (1)路由配置 uni-app页面路由全部交给框架统一管理,需要在pages.json里配置每个路由页面的路径以及页面样式(类似小程序在app.json中配置页面路由) 接着第一节的文件,在pages里面新建三个页面 将之前的首页替换为下面的内容,其他页面如下图 然…...

matlab行操作快?还是列操作快?

在MATLAB中&#xff0c;通常情况下&#xff0c;对矩阵的列进行操作比对行进行操作更有效率。这是因为MATLAB中内存是按列存储的&#xff0c;因此按列访问数据会更加连续&#xff0c;从而提高访问速度。 一、实例代码 以下是一个简单的测试代码&#xff0c; % 测试矩阵大小 ma…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...