antdesignvue表格实现伸缩列并限制最大最小宽度和限制操作列不可拖动

antdesignvue表格实现伸缩列并限制最大最小宽度和限制操作

  • 先看效果动图:
    在这里插入图片描述

代码部分:

<template>
  <a-table :rowKey="(record,index)=>index" :columns="columns" :components="components" :data-source="tableData" :scroll="{ x: scrollX }">
    <template v-slot:action>
      <a href="javascript:;">Delete</a>
    </template>
  </a-table>
</template>

<script>
import Vue from "vue";
import VueDraggableResizable from "vue-draggable-resizable";
Vue.component("vue-draggable-resizable", VueDraggableResizable);
export default {
  name: "App",
  data() {
    return {
      columns: [
        {
          title: "项目名称",
          dataIndex: "name",
          key: "name",
          width: 150,
          fixed: "left",
          ellipsis: true // 伸缩列过小时省略号显示
        },
        {
          title: "项目类型",
          dataIndex: "type",
          key: "type",
          width: 150,
          ellipsis: true
        },
        {
          title: "项目编号",
          dataIndex: "num",
          key: "num",
          width: 150,
          ellipsis: true
        },
        {
          title: "项目状态",
          dataIndex: "status",
          key: "status",
          width: 100,
          ellipsis: true
        },
        {
          title: "备注1",
          dataIndex: "commet1",
          key: "commet1",
          width: 200,
          ellipsis: true
        },
        {
          title: "备注2",
          dataIndex: "commet2",
          key: "commet2",
          width: 200,
          ellipsis: true
        },
        {
          title: "备注3",
          dataIndex: "commet3",
          key: "commet3",
          width: 200,
          ellipsis: true
        },
        {
          title: "备注4",
          dataIndex: "commet4",
          key: "commet4",
          width: 200,
          ellipsis: true
        },
        {
          title: "操作",
          dataIndex: "action",
          key: "action",
          scopedSlots: { customRender: "action" },
          width: 200,
          fixed: "right",
        },
      ],
      tableData: [
        {
          name: "我是项目1111",
          type: "我是项目类型啊啊",
          num: "666-ffffa",
          status: "稳定中",
          commet1: "我是备注啊啊啊啊",
          commet2: "我是备注啊啊啊啊",
          commet3: "我是备注啊啊啊啊",
          commet4: "我是备注啊啊啊啊",
        },
        {
          name: "我是项目1111",
          type: "我是项目类型啊啊",
          num: "666-ffffa",
          status: "稳定中",
          commet1: "我是备注啊啊啊啊",
          commet2: "我是备注啊啊啊啊",
          commet3: "我是备注啊啊啊啊",
          commet4: "我是备注啊啊啊啊",
        },
        {
          name: "我是项目1111",
          type: "我是项目类型啊啊",
          num: "666-ffffa",
          status: "稳定中",
          commet1: "我是备注啊啊啊啊",
          commet2: "我是备注啊啊啊啊",
          commet3: "我是备注啊啊啊啊",
          commet4: "我是备注啊啊啊啊",
        },
      ],
    };
  },
  computed: {
    // 动态获取scrollX,防止数组固定列的大小变化
    scrollX() {
      return this.columns.reduce((preVal, curVal) => {
        return preVal + curVal.width
      }, 0)
    }
  },
  created() {
    this.initDrag(this.columns);
  },
  methods: {
    initDrag(columns) {
      const draggingMap = {};
      columns.forEach((col) => {
        draggingMap[col.key] = col.width;
      });
      const draggingState = Vue.observable(draggingMap);
      // resizeableTitle要小写,不然会有报错
      const resizeableTitle = (h, props, children) => {
        let thDom = null;
        const { key, ...restProps } = props;
        const col = columns.find((col) => {
          const k = col.dataIndex || col.key;
          return k === key;
        });
        // col.key === 'action'限制操作列不可伸缩
        if (!col.width || col.key === 'action') {
          return <th {...restProps}>{children}</th>;
        }
        const onDrag = (x) => {
          draggingState[key] = 0;
          let width = Math.max(x, 100) // 此处100为伸缩时的最小宽度
          width = Math.min(width, 400) // 此处400为伸缩时的最大宽度
          col.width = width 
        };

        const onDragstop = () => {
          draggingState[key] = thDom.getBoundingClientRect().width;
        };
        return (
          <th
            {...restProps}
            v-ant-ref={(r) => (thDom = r)}
            width={draggingState[key]}
            class="resize-table-th"
          >
            {children}
            <vue-draggable-resizable
              key={col.key}
              class="table-draggable-handle"
              w={10}
              x={col.width || draggingState[key]}
              z={1}
              axis="x"
              draggable={true}
              resizable={false}
              onDragging={onDrag}
              onDragstop={onDragstop}
            ></vue-draggable-resizable>
          </th>
        );
      };
      this.components = {
        header: {
          cell: resizeableTitle,
        },
      };
    },
  },
};
</script>
<style lang="less" scoped>
// 这里的deep必须,不然样式无法穿透内部
/deep/.resize-table-th {
  position: relative;
  .table-draggable-handle {
    height: 100% !important;
    bottom: 0;
    left: auto !important;
    right: 0px;
    cursor: col-resize;
    touch-action: none;
    position: absolute;
    transform: none !important;
    &:hover {
      background: #1890ff;
    }
    &::after {
      content: "|";
      position: absolute;
      top: 15px;
      left: 3px;
      color: #ccc;
    }
  }
}
</style>

下面新增了拖动表头的功能

需要安装sortablejs $ npm install sortablejs --save
代码如下:

<template>
  <div class="box">
    <a-table
      :rowKey="(record, index) => index"
      :columns="columns"
      :components="components"
      :data-source="tableData"
      :scroll="{ x: scrollX, y: 100 }"
    >
      <template v-slot:action>
        <a href="javascript:;">Delete</a>
      </template>
    </a-table>
  </div>
</template>

<script>
import Sortable from 'sortablejs' 
import Vue from "vue";
import VueDraggableResizable from "vue-draggable-resizable";
Vue.component("vue-draggable-resizable", VueDraggableResizable);
export default {
  name: "App",
  data() {
    return {
      columns: [
        {
          title: "项目名称",
          dataIndex: "name",
          key: "name",
          width: 150,
          fixed: "left",
          ellipsis: true, // 伸缩列过小时省略号显示
        },
        {
          title: "项目类型",
          dataIndex: "type",
          key: "type",
          width: 150,
          ellipsis: true,
        },
        {
          title: "项目编号",
          dataIndex: "num",
          key: "num",
          width: 150,
          ellipsis: true,
        },
        {
          title: "项目状态",
          dataIndex: "status",
          key: "status",
          width: 100,
          ellipsis: true,
        },
        {
          title: "备注1",
          dataIndex: "commet1",
          key: "commet1",
          width: 200,
          ellipsis: true,
        },
        {
          title: "备注2",
          dataIndex: "commet2",
          key: "commet2",
          width: 200,
          ellipsis: true,
        },
        {
          title: "备注3",
          dataIndex: "commet3",
          key: "commet3",
          width: 200,
          ellipsis: true,
        },
        {
          title: "备注4",
          dataIndex: "commet4",
          key: "commet4",
          width: 200,
          ellipsis: true,
        },
        {
          title: "操作",
          dataIndex: "action",
          key: "action",
          scopedSlots: { customRender: "action" },
          width: 200,
          fixed: "right",
        },
      ],
      tableData: [
        {
          name: "我是项目1111",
          type: "我是项目类型啊啊",
          num: "666-ffffa",
          status: "稳定中",
          commet1: "我是备注啊啊啊啊",
          commet2: "我是备注啊啊啊啊",
          commet3: "我是备注啊啊啊啊",
          commet4: "我是备注啊啊啊啊",
        },
        {
          name: "我是项目1111",
          type: "我是项目类型啊啊",
          num: "666-ffffa",
          status: "稳定中",
          commet1: "我是备注啊啊啊啊",
          commet2: "我是备注啊啊啊啊",
          commet3: "我是备注啊啊啊啊",
          commet4: "我是备注啊啊啊啊",
        },
        {
          name: "我是项目1111",
          type: "我是项目类型啊啊",
          num: "666-ffffa",
          status: "稳定中",
          commet1: "我是备注啊啊啊啊",
          commet2: "我是备注啊啊啊啊",
          commet3: "我是备注啊啊啊啊",
          commet4: "我是备注啊啊啊啊",
        },
      ],
    };
  },
  computed: {
    // 动态获取scrollX,防止数组固定列的大小变化
    scrollX() {
      return this.columns.reduce((preVal, curVal) => {
        return preVal + curVal.width;
      }, 0);
    },
  },
  created() {
    this.initDrag(this.columns);
  },
  mounted() {
    this.columnDrop()
  },
  methods: {
    initDrag(columns) {
      const draggingMap = {};
      columns.forEach((col) => {
        draggingMap[col.key] = col.width;
      });
      const draggingState = Vue.observable(draggingMap);
      const resizeableTitle = (h, props, children) => {
        let thDom = null;
        const { key, ...restProps } = props;
        const col = columns.find((col) => {
          const k = col.dataIndex || col.key;
          return k === key;
        });
        // col.key === 'action'限制操作列不可伸缩
        if (!col.width || col.key === "action") {
          return <th {...restProps}>{children}</th>;
        }
        const onDrag = (x) => {
          draggingState[key] = 0;
          let width = Math.max(x, 100); // 此处100为伸缩时的最小宽度
          width = Math.min(width, 400); // 此处400为伸缩时的最大宽度
          col.width = width;
        };

        const onDragstop = () => {
          draggingState[key] = thDom.getBoundingClientRect().width;
        };
        return (
          <th
            {...restProps}
            v-ant-ref={(r) => (thDom = r)}
            width={draggingState[key]}
            class="resize-table-th"
          >
            {children}
            <vue-draggable-resizable
              key={col.key}
              class="table-draggable-handle"
              w={10}
              x={col.width || draggingState[key]}
              z={1}
              axis="x"
              draggable={true}
              resizable={false}
              onDragging={onDrag}
              onDragstop={onDragstop}
            ></vue-draggable-resizable>
          </th>
        );
      };
      this.components = {
        header: {
          cell: resizeableTitle,
        },
      };
    },
    //列拖拽
    columnDrop() {
      var _this = this;
      const wrapperTr = document.querySelector(".ant-table-wrapper tr");
      this.sortable = Sortable.create(wrapperTr, {
        handle: ".ant-table-header-column", // 防止拉伸时触发拖拽
        animation: 180,
        delay: 0,
        //之前调用onEnd方法会出现表格DOM不更新以及表头对不上的情况所以更换为onUpdate方法
        onUpdate: function (evt) {
          //修改items数据顺序
          var newIndex = evt.newIndex;
          var oldIndex = evt.oldIndex;
          const newItem = wrapperTr.children[newIndex];
          const oldItem = wrapperTr.children[oldIndex];

          // 先删除移动的节点
          wrapperTr.removeChild(newItem);
          // 再插入移动的节点到原有节点,还原了移动的操作
          if (newIndex > oldIndex) {
            wrapperTr.insertBefore(newItem, oldItem);
          } else {
            wrapperTr.insertBefore(newItem, oldItem.nextSibling);
          }
          // 更新items数组
          var item = _this.columns.splice(oldIndex, 1);
          _this.columns.splice(newIndex, 0, item[0]);
          // 下一个tick就会走patch更新

          // 如果需要缓存表头,比如缓存到vuex中
          //每次更新调取保存用户接口
          // _this.saveColumns("columnChange", _this.columns);
        },
      });
    },
  },
};
</script>
<style lang="less" scoped>
.box {
  padding: 20px;
}
/deep/.resize-table-th {
  position: relative;
  .table-draggable-handle {
    height: 100% !important;
    bottom: 0;
    left: auto !important;
    right: 0px;
    cursor: col-resize;
    touch-action: none;
    position: absolute;
    transform: none !important;
    &:hover {
      background: #1890ff;
    }
    &::after {
      content: "|";
      position: absolute;
      top: 15px;
      left: 3px;
      color: #ccc;
    }
  }
}
</style>

有疑问欢迎一起讨论啊~

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要在Vue3中实现左侧伸缩菜单功能,可以使用自定义组件和Vue的响应式特性来实现。 首先,你可以创建一个名为`NavSide`的组件,用来实现侧边菜单栏的功能。在这个组件中,可以使用`ref`来定义一个`isCollapse`的响应式变量,用来表示菜单是否折叠。然后,在模板中使用条件渲染来展示不同状态下的菜单内容。例如,当`isCollapse`为`true`时,渲染折叠图标;当`isCollapse`为`false`时,渲染展开图标。 接下来,你可以创建一个名为`NavHeader`的组件,用来实现头部组件的功能。在这个组件中,可以使用`props`来接收`collapse`属性,并通过`emits`来定义一个`update:collapse`事件,用来更新菜单的折叠状态。在模板中,可以通过点击事件来触发`shrink`方法,并通过`emits`来触发`update:collapse`事件,从而改变菜单的折叠状态。 最后,你可以在父组件中使用这两个自定义组件,并通过`v-model`来双向绑定菜单的折叠状态。在父组件的模板中,可以使用`el-aside`和`el-header`来放置侧边菜单栏和头部组件,并通过`router-view`来展示其他内容。 总结起来,要实现左侧伸缩菜单功能,你需要: 1. 创建一个名为`NavSide`的组件,用来实现侧边菜单栏的功能。 2. 创建一个名为`NavHeader`的组件,用来实现头部组件的功能。 3. 在父组件中使用这两个自定义组件,并通过`v-model`来双向绑定菜单的折叠状态。 注意,以上代码只是简单的示例,你可能需要根据实际需求进行修改和完善。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [vue3 伸缩菜单组件](https://blog.csdn.net/m0_58565372/article/details/128549497)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

King_960725

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值