demand

It’s time for a new demand every day. Capitalism has found a new continent out of nowhere.

You can drag columns on the original EL-Table, adjust column width, save locally according to the user, and control the display of dynamic column items.

If not see in my love study just don’t give you development !!!!

Without further ado, here’s the picture:

This is a 6-column page, and the user doesn’t want the last column, just click the button to the right of the column header, in the popup layer, and perform the following operations:

  • Drag and drop to change column order,
  • To control which columns are displayed,
  • Reset to restore the initial code configuration order,

Train of thought

Implement close browser can also cache that last must be stored in localstorage. Table column data must be configured items. Then control the configuration items. Then roll up your sleeves. 0.o

The table component

<script lang="ts"> import { Component, Prop, Mixins, Emit } from 'vue-property-decorator'; import { TableMix } from 'feok-lib'; import TableSettingMix from '@/views/mixins/TableSettingMix'; import ColumnsDrawer from '@/components/ColumnsDrawer'; @Component({ components: { ColumnsDrawer, }, }) export default class Table extends Mixins( TableMix, TableSettingMix, ) { @Prop({ default: 'XXXX' }) public tableUserKey! : string; Public COLUMNS: any[] = [{prop: 'order_id', label: 'order_id', sort: 0, width: '', minWidth: '120', drag: false, // whether to drag display: true, // whether to display disabled: true, // To disable popup select operation slot: 'order_id', // if the same as prop, consider order_id as slot},... } </script> <template> <div class="test-table"> <el-table size="small" border :data="data" :ref="refStr" v-bind="$attrs"  v-on="$listeners" v-loading="loading" :empty-text="emptyText" row-key="id" @header-dragend="headerDragend" > <! -- I'm used to leaving a slot at the beginning and a slot at the end, <slot name="firstColumn"></slot> <template v-for="(item, index) of removelastColumnsWidth(columns)"> <! - slot configuration items - > < slot: name = "item. The slot" v - if = "item. Prop = = = item. Slot" : the item = "item" : the index = "index" > < / slot > <el-table-column v-if="item.prop === 'order_id'" prop="order_id" :width="item.width" :key="`${index}-${item.prop}`" :minWidth="item.minWidth" :resizable="item.resizable" :label="label" > <template slot-scope="{row}"> <div>{{$ph(row.order_id)}}</div> </template> </el-table-column> <! </template> <! -- I'm used to leaving a slot at the beginning and a slot at the end, <slot name="handle" :setting="settingColumns"></slot> </el-table> :visiable="visiable" :columns="columns" @close="close" @reset="reset" @on-done="saveSetting" @closed="destoryDrawer=false" /> </div> </template>Copy the code

After looking at the code above, you must be wondering what the ColumnsDrawer component is, if you really need to, let’s take a look at it. It’s actually a popbox component.

You will see that this is ultimately implemented in el-drawer + El-tree.

Bounced components

<script lang="ts"> import { Component, Vue, Prop } from 'vue-property-decorator'; @component export default class ColumnsDrawer extends Vue {public get defaultCheckedKeys() { Return this.data.filter ((item: any) => item.display).map((item: any) => item.prop); } @Prop() public visiable! : boolean; @prop ({default: () => []}) public columns! : any[]; // Table configuration item Public data: any[] = []; // Public defaultProps = {// Children: 'children', label: 'label',}; Public handleDragStart(snode: any, event:) public handleDragStart(snode: any, event:) Event) { // console.log(snode, event); } public handleDragEnter(snode: any, enode: any, event: Event) { // console.log(snode, enode, event); } public handleDragLeave(snode: any, enode: any, event: Event) { // console.log(snode, enode, event); } public handleDragOver(snode: any, enode: any, event: Event) { // console.log(snode, enode, event); } public handleDragEnd(snode: any, enode: any, event: Const tempSort = snode.data.sort; const tempSort = snode.data.sort; snode.data.sort = enode.data.sort; enode.data.sort = tempSort; } public handleDrop(snode: any, enode: any, event: Event) { // console.log(snode, enode, event); } public allowDrop(draggingNode: any, dropNode: any, type: string) { // console.log(dropNode.data.drag); if (dropNode.data.drag === false || type === 'inner') { return false; } else { return true; }} public allowDrag(node: any) {return node.data.drag; } public save() {this.$emit('on-done', this.data); } public checkChange(item: any, checked: Boolean) {item.display = checked; } public created() { this.data = JSON.parse(JSON.stringify(this.columns)); }} </script> <template> <div class="test-drawer"> <el-drawer V-on ="$listeners" title=" unavailable ":visible=" unavailable" :show-close="false" :wrapper-closable="true" direction=" RTL "size="auto" > <template slot="title"> <span> Configuration column </span> <sub class="feok-link re-md-sm-margin-left" @click="$emit('reset')" title=" reset "> </sub> <! -- <i class="el-icon-refresh re-md-sm-margin-left" @click="$emit('reset')"></i> --> </template> <div class="columns-setting"> <el-tree class="setting-columns" :data="data" :props="defaultProps" draggable show-checkbox node-key="prop" :default-checked-keys="defaultCheckedKeys" @node-drag-start="handleDragStart" @node-drag-enter="handleDragEnter" @node-drag-leave="handleDragLeave" @node-drag-over="handleDragOver" @node-drag-end="handleDragEnd" @node-drop="handleDrop" @check-change="checkChange" :allow-drop="allowDrop" :allow-drag="allowDrag" > <div class="custom-tree-node" slot-scope="{ node, data }"> <span>{{ node.label }}</span> <i class="el-icon-rank" v-if="data.drag"></i> </div> </el-tree> <div <el-button size="small" type="primary" @click="save"> </el-button> <el-button size="small" @ click = "$emit (' close ')" > cancel < / el - button > < / div > < / div > < / el - the drawer > < / div > < / template > < style lang = "less" >. The test - the drawer { .columns-setting { display: flex; flex-direction: column; min-width: 210px; height: 100%; padding: 10px; .setting-columns { flex: 1; li { list-style: none; } } .setting-btn { flex: 0 0 auto; } .custom-tree-node { display: flex; justify-content: space-between; width: 100%; [class * = 'el - icon] {opacity: 0.6; } } } .el-drawer__header { margin-bottom: 0; padding: 20px; border-bottom: 1px solid #f0f0f0; font-weight: bold; background: rgb(243, 243, 244); } .el-tree-node { margin-bottom: 10px; [class*='el-tree-node__expand'] { display: none; } } } </style>Copy the code

Ok, the component is finished, can you use it directly? Wait, there’s something missing for me. Am I hiding it?

I got caught. I’ll tell you what.

TableSettingMix hybrid

/ * * *@author Yuanr
 * @description Adjust the table column to mix */
import { Component, Vue, Prop } from 'vue-property-decorator';
import { get } from 'lodash';
import ColumnsDrawer from '@/components/ColumnsDrawer';

interface COLUMNS_SETTING {
	prop: string; // 列key
  label: string; / / column name
  sort: number; // Column sort, each item must have the sort value
  width: string; / / column width
  drag: boolean; // Whether columns can be dragged and sorted
  display: boolean; // Whether the column is displayed
  disabled: boolean; // Disable selection when setting column items
  slot: string; // Whether the column is slot
}

@Component({
  components: {
    ColumnsDrawer,
  },
})
export default class TableSettingMix extends Vue {
  @Prop({ default: 'TableColumns' }) publictableUserKey! :string; // TABLE_USER_KEY tableUserKey
  @Prop({ default: ' ' }) publictableVersion! :string; // I wanted to add a version number, but it didn't work

  public readonly USER_KEY = `${get(JSON.parse(sessionStorage.getItem('userinfo')! .'account'.' ').trim()}`;
  public REFNAME = 'TABLE_REF';
  public COLUMNS: COLUMNS_SETTING[] = [
    / / {
    // prop: 'name', // column key
    // label: 'name ', // column name
    // sort: 0, // column sort, each item must have sort value
    // width: ", // column width
    // drag: false, // Whether columns can be dragged and sorted
    // display: true, // whether the column is displayed
    // disabled: true, // Disables the selection operation when setting column items
    // slot: 'default', // whether the column is slot
    // },
  ];
  public visiable = false; // el-drawer visible
  public destoryDrawer = false; // el-drawer v-if
  public columns: any[] = [];

  // Local storage format Table__USER_KEY__TABLE_USER_KEY__TABLE_VERSION
  get localstorageKey() {
    return `Table__The ${this.USER_KEY}__The ${this.tableUserKey}__The ${this.tableVersion}`;
  }
	/ / get the table
  get refStr() {
    return (this as any).refName || this.REFNAME;
  }
  // Column model rule: TABLECOLUMNS__ Item __ module __Table name
  // Sort the column items
  public sort(data: any[]) {
    return data.sort((s, e) = > {
      return s.sort - e.sort;
    });
  }
  // Pop up column Settings
  public settingColumns() {
    this.destoryDrawer = true;
    this.visiable = true;
  }
  public close() {
    this.visiable = false;
  }
  // Change the column width
  public headerDragend(newWidth: number, oldWidth: number, column: any, event: Event) {
    if(! column.resizable) {return false;
    }
    const data = JSON.parse(JSON.stringify(this.columns));
    const item: any = data.find((item: any) = > item.prop === column.property);
    if (item) {
      item.width = newWidth;
      this.setColumns(data);
      this.syncColumns(data); }}// Save the Settings
  public saveSetting(data: any[]) {
    this.setColumns(data);
    this.syncColumns(data);
    this.sortColumns();
    this.close();
  }
  public sortColumns() {
    this.columns = this.sort(this.columns);
  }
  // Remove the width adjustment of the last item based on the actual situation
  public get removelastColumnsWidth() {
    return (data: any[]) = > {
      return data.filter((item: any) = > item.display).map((item: any, index: number, arr: any[]) = > {
        if (index === arr.length - 1) {
          return {
            ...item,
            width: ' '.resizable: false}; }else {
          returnitem; }}); }; }// sessionStorage.getItem('token');
  / / get the columns
  public getColumns() {
    if (this.tableUserKey && (localStorage as any) [this.localstorageKey]) {
      return JSON.parse((localStorage as any) [this.localstorageKey]);
    } else {
      return[]; }}/ / set the columns
  public setColumns(data: any[]) {
    if (this.tableUserKey) {
      (localStorage as any) [this.localstorageKey] = JSON.stringify(data); }}public syncColumns(data: any[]) {
    const map: any = {};
    for (const column of data) {
      map[column.prop] = column;
    }
    this.columns = this.columns.map((column: any) = >({... column, ... (map[column.prop] || {}),prop: column.prop,
      label: column.label,
    }));
  }
  public created() {
    // Initialize the data
    this.columns = this.COLUMNS;
    // Synchronize Settings
    if (this.tableUserKey && (localStorage as any) [this.localstorageKey]) {
      this.syncColumns(this.getColumns());
    } else {
      this.syncColumns(this.COLUMNS);
    }
    / / sorting
    this.sortColumns();
  }
  public mounted() {
    // elementUI Bug fixed
    try {
      const tableHeaderRef: any = ((this.$refs as any) [this.refStr] as any).$refs.tableHeader;
      const handleMouseMove = tableHeaderRef.handleMouseMove;
      const handleMouseOut = tableHeaderRef.handleMouseOut;
      tableHeaderRef.handleMouseMove = (event: Event, column: any) = > {
        if(! column.resizable) {return false;
        }
        handleMouseMove(event, column);
        const target: any = get(event, 'target.tagName') = = ='TH' ? get(event, 'target') : (get(event, 'target.classList').value === 'cell' ? get(event, 'target.parentNode') : undefined);
        if(! target) {return false;
        }
        if (tableHeaderRef.draggingColumn) {
          target.classList.add('th-draging');
        } else {
          target.classList.remove('th-draging');
        }
        if (tableHeaderRef.dragging) {
          target.classList.remove('th-draging'); }}; tableHeaderRef.handleMouseOut =() = > {
        handleMouseOut();
        const draggingArr: NodeList = document.querySelectorAll('.th-draging');
        for (const drag of draggingArr) {
          (drag as any).classList.remove('th-draging'); }}; }catch (e) {
      throw Error('elementUI Bug to be fixed '); }}// Delete the user-defined function
  public reset() {
    if (this.tableUserKey) {
      (localStorage as any) [this.localstorageKey] = ' ';
      this.columns = this.COLUMNS;
    }
    this.close();
    this.$nextTick(() = > {
      this.setColumns(this.COLUMNS); }); }}Copy the code

Well, that leaves component calls

<PurchaseOrderTable
		ref="PurchaseOrderTable"
    refName="PurchaseOrderTable"
/>
Copy the code

conclusion

In fact, the focus is on popovers and how to implement the inside. When we found a way, the rest fell into place. At this time to big brothers remind, nothing to see the official website documents, every time there will be new harvest ~

Excuse me, Sir. There are a few points to note here

Problem 1: Note the local storage format definition in the mix

Because the rules defined by each project are not necessarily the same, they are modified here

  // Local storage format Table__USER_KEY__TABLE_USER_KEY__TABLE_VERSION
  get localstorageKey() {
    return `Table__The ${this.USER_KEY}__The ${this.tableUserKey}__The ${this.tableVersion}`;
  }
Copy the code

Question 2: Does each table have a configuration item written by hand

I’m sorry to tell you that, yes, this is only a preliminary solution. If you had a simpler solution. Welcome to leave a message

Question3: Why do you call me dog

I may be a dog, the message which small friends they do not – when – human – ah. Soon then. 👋

eggs

Aha, hello, it’s Easter eggs again, and today’s Easter eggs are. Element-ui announced for Vue3.0 !!!!

Those of you forced to use Ant can wait!

Show funny horse ~~~~~~~~~

Published address: juejin.cn/post/690073…

Git address: github.com/element-plu…

Element-plus.gize. IO /#/ zh-cn


If this article is useful, feel free to comment, like, and follow.

I’m Leo: I wish you all a promotion and a raise soon.