vue 控制表格列的数量组件

基于Ant-Design-Vue 封装一个可拖拽控制table 列数量的组件

前置准备:
1.安装 Ant-Design-Vue https://www.antdv.com/docs/vue/use-with-vue-cli-cn/
yarn add ant-design-vue 或者 npm install ant-design-vue
2.安装 vue-smooth-dnd vuedraggable
yarn add vuedraggable , yarn add vue-smooth-dnd

main.js

import Vue from 'vue'
import App from './App.vue'
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css'
import { Container, Draggable } from "vue-smooth-dnd";
Vue.component('Container',Container)
Vue.component('Draggable',Draggable)


Vue.config.productionTip = false
Vue.use(Antd)
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

TableSetting.vue (基于render函数封装)

<script>
import { Container, Draggable } from "vue-smooth-dnd"; //使用拖拽插件
export default {
  data() {
    return {
      columns: [],
      checkAll: true,
      indeterminate: false,
      keepColumns: [],
    };
  },
  props: {
    cloumnsTitle: {
      type: Array,
      default: () => [],
    },
    isReload: {
      type: Boolean,
      default: false,
    },
    isSize: {
      type: Boolean,
      default: false,
    },
  },
  watch: {
    columns: {
      //监听选中 拖拽时数据变化
      async handler() {
        this.keepColumns = this.columns.filter((v) => {
          if (v.checked) {
            return v;
          }
        });
        this.$emit("onDragAndDrop", this.keepColumns);
      },
      deep: true,
      immediate: false,
    },
  },
  mounted() {
    this.columns = this.cloumnsTitle.map((v) => {
      v.checked = true;
      return v;
    });
  },
  methods: {
    //全选
    onChangeAll(e) {
      this.columns.forEach((v) => {
        v.checked = e.target.checked;
      });
      Object.assign(this, {
        checkAll: e.target.checked,
        indeterminate: false,
      });
    },
    //选中一列
    onChangeItem(e, menu) {
      menu.checked = e.target.checked;
      this.keepColumns = this.columns.filter((v) => {
        if (!v.checked) {
          return v;
        }
      });

      Object.assign(this, {
        checkAll: this.columns.every((v) => v.checked),
        indeterminate:
          this.keepColumns.length == this.columns.length
            ? false
            : this.keepColumns.length == 0
            ? false
            : true,
      });
    },
    //拖拽列
    onDrop(e) {
      //获取拖拽内容和替换内容的值
      let cloumnsTitle = JSON.parse(JSON.stringify(this.columns));
      let startItem = cloumnsTitle.filter((v, i) => i == e.removedIndex)[0];
      let endTtem = cloumnsTitle.filter((v, i) => i == e.addedIndex)[0];
      // 将拖拽内容 和 替换内容互换
      cloumnsTitle[e.addedIndex] = startItem;
      cloumnsTitle[e.removedIndex] = endTtem;
      this.columns = cloumnsTitle;
    },
    //设置表格宽度
    onColumnHeight(e) {
      this.$emit("onChangeSize", e.key);
    },
    //刷新表格
    onReload() {
      this.$emit("onReload");
    },

    renderDragMenu() {
      //生成拖拽列
      const dropMenu = this.columns.map((menu, index) => {
        return (
          <Draggable>
            <div class="draggable-item">
              <div class="lable">
                <a-icon type="more" />
                <a-checkbox
                  checked={menu.checked}
                  onClick={(e) => this.onChangeItem(e, menu)}
                >
                  {menu.title}
                </a-checkbox>
              </div>
            </div>
          </Draggable>
        );
      });

      return <Container onDrop={(e) => this.onDrop(e)}>{dropMenu}</Container>;
    },
    renderDragPane() {
      const Drag = this.renderDragMenu();
      return (
        <div class="setting-box">
          <a-tooltip v-show={this.$props.isReload}>
            <div slot="title">刷新</div>
            <a-icon
              onClick={() => this.onReload()}
              style={{ cursor: "pointer" }}
              type="reload"
            />
          </a-tooltip>
          <a-tooltip v-show={this.$props.isSize}>
            <div slot="title">密度</div>
            <a-popover trigger="click">
              <div slot="content">
                <a-menu slot="overlay" onClick={(e) => this.onColumnHeight(e)}>
                  <a-menu-item key="middle">默认</a-menu-item>
                  <a-menu-item key="default">中等</a-menu-item>
                  <a-menu-item key="small">紧凑</a-menu-item>
                </a-menu>
              </div>
              <a-icon type="column-height" style={{ cursor: "pointer" }} />
            </a-popover>
          </a-tooltip>
          <a-tooltip>
            <div slot="title">列设置</div>
            <a-popover trigger="click">
              <div slot="title">
                <div class="column-handle">
                  <div>
                    <a-checkbox
                      v-model={this.checkAll}
                      onClick={(e) => this.onChangeAll(e)}
                      indeterminate={this.indeterminate}
                    >
                      列展示
                    </a-checkbox>
                  </div>
                  <div></div>
                </div>
              </div>
              <div slot="content">{Drag}</div>
              <a-icon type="setting" style={{ cursor: "pointer" }} />
            </a-popover>
          </a-tooltip>
        </div>
      );
    },
  },
  render() {
    const dragList = this.renderDragPane();
    if (this.columns.length == 0) {
      return <div>请传入正确的表头参数值</div>;
    }
    return <div class="table-setting">{dragList}</div>;
  },
};
</script>

<style scoped>
.setting-box {
  width: 60px;
  margin: 0 auto;
  justify-content: space-between;
  display: flex;
}
.setting-box i {
  font-size: 16px;
}

.table-setting >>> .ant-popover-inner-content {
  padding: 0 !important;
}
.column-handle {
  display: flex;
  justify-content: space-between;
}
.table {
  width: 70%;
  margin: 0 auto;
}
.draggable-item {
  padding: 4px 16px 4px 2px;
  box-shadow: 1px 1px 3px #cacaca;
  cursor: move !important;
}

</style>

在界面中去使用

<template>
  <div class="about">
    <div class="table">
      <a-table
        :columns="columns"
         bordered
        :loading="loading"
        :data-source="data"
        :size="size"
      >
        <div class="title" slot="title">
          <table-setting
            :cloumnsTitle="columns"
            @onDragAndDrop="onDragAndDrop"
            @onChangeSize="onChangeSize"
            @onReload="onReload"
            :isSize="true"
            :isReload="true"
          ></table-setting>
        </div>
      </a-table>
    </div>
  </div>
</template>
<script>
import TableSetting from "@/components/TableSetting";

var data = [];
//表格数据
for (var i = 0; i < 20; i++) {
  data.push({
    key: i,
    name: "John Brown",
    age: 32,
    address: "New York No. 1 Lake Park",
  });
}
//表头参数
var columns = [
  {
    title: "name",
    dataIndex: "name",
    key: "name",
    slots: { title: "customTitle" },
    scopedSlots: { customRender: "name" },
  },
  {
    title: "Age",
    dataIndex: "age",
    key: "age",
  },
  {
    title: "Address",
    dataIndex: "address",
    key: "address",
  },
  {
    title: "Tags",
    key: "tags",
    dataIndex: "tags",
    scopedSlots: { customRender: "tags" },
  },
  {
    title: "Action",
    key: "action",
    scopedSlots: { customRender: "action" },
  },
];
export default {
  data() {
    return {
      columns,
      data,
      size: "middle", //表格比列大小 默认 middle
      loading: false, 
    };
  },
  components: {
    TableSetting,
  },
  methods: {
    //拖拽时触发
    onDragAndDrop(columns) {
      this.columns = columns;
    },
    //设置表格比列大小
    onChangeSize(size) {
      this.size = size;
    },
    //刷新表格
    onReload() {
      this.loading = true;
      //模拟向后端请求数据 
      setTimeout(() => {
        this.loading = false;
      }, 2000);
    },
  },
};
</script>
<style scoped>
.table {
  width: 70%;
  margin: 0 auto;
}
.title{
  display: flex;
  justify-content: flex-end;
}
</style>

界面效果

在这里插入图片描述

参数说明类型默认值
@onDragAndDrop拖拽回调funtion-
@onChangeSize设置大小回调funtion-
@onReload刷新表格回调funtion-
isSize是否显示操作大小按钮booleanfalse
isReload是否显示刷新按钮booleanfalse
cloumnsTitle要操作的表头数据(必填)Array[]
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值