前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >实现表格行的拖拽以及分页

实现表格行的拖拽以及分页

作者头像
itclanCoder
发布2021-12-06 16:05:51
2.9K0
发布2021-12-06 16:05:51
举报
文章被收录于专栏:itclanCoder

背景

在做一些后台管理系统时,表格的数据信息展示是很常见的需求,而对应的都是一些增删改查的操作

有的表格甚至要求会做拖拽,排序等

涉及到的知识

1: 如何渲染表头数据以及表格数据

2: 最右侧管理的按钮(查看,编辑,上线,下线)是怎么插入进去的

3: 管理操作(查看,编辑,上线,下线)按钮的状态显示

4: 表格的分页数据展示

5: 表格的横向拖拽实现

操作按钮状态

它的状态是根据后端返回的具体status来决定显示,隐藏以及是否禁用

1: "待发布",即编辑状态,下线按钮置灰

2: "待上线",即编辑状态,上线,下线按钮置灰

3: "已上线",即上线按钮置灰,查看按钮隐藏

100: "已结束,查看按钮显示,上下线按钮置灰

具体内容,代码就是最好的解释哈

具体实例效果(拖拽行)

点击文末左下方阅读原文即可体验

https://coder.itclan.cn/fontend/css/business-col-draw/

行拖拽的具体实现

这里的拖拽主要借用的是sortablejs实现的,具体代码如下所示

代码语言:javascript
复制
import Sortable from 'sortablejs'; // 引入sortable
// 拖拽方法
dropRow(endHandle) {
    const tbody = document.querySelector(
        ".el-table__body-wrapper tbody"
    );
    if (tbody) {
        Sortable.create(tbody, {
        animation: 300,
        delay: 0,
        handle: '.drop_handle',
        onEnd: endHandle,
        });
    }
},

// 在mounted函数中
 // 表格拖拽
this.$nextTick(() => {
    this.dropRow((oldIndex,newIndex) => {
    const currRow = this.tableData.splice(oldIndex, 1)[0]
    this.tableData.splice(newIndex, 0, currRow);
    })
})

整个实例代码如下所示

tableRowDraw.vue

代码语言:javascript
复制
<template>
  <div>
    <!-- 表格内容展示开始 -->
    <div class="table-content">
      <tableComp
        :pageSize="pageSize"
        :pageNo="pageNo"
        :total="total * 1"
        :tableData="tableData.slice((pageNo - 1) * pageSize, pageNo * pageSize)"
        :table-colist="tableColist"
        @look="handleLook"
        @copy="handleCopy"
        @edit="handleEdit"
        @online="handleOnline"
        @offline="handleOffline"
        @pageCurrentChange="pageCurrentChange"
        @pageSizeChange="pageSizeChange"
      >
      </tableComp>
    </div>
    <!-- 表格内容展示结束 -->
    <!-- 点击表格上下线按钮弹出模态框开始 -->
    <el-dialog
      :visible.sync="isDialogModel"
      width="30%"
      center
      custom-class="dialog-model"
    >
      <p class="dalog-content">{{ popModelContent }}</p>
      <span slot="footer" class="dialog-footer">
        <el-button @click="isDialogModel = false">取 消</el-button>
        <el-button type="primary" @click="handleSubmit">确 定</el-button>
      </span>
    </el-dialog>
    <!-- 点击表格上下线按钮弹出模态框结束 -->
  </div>
</template>

<script>
import { tableColist } from "./tableColist.js"; // 表格表头配置数据
import tableComp from "./tableComp.vue";
import Sortable from 'sortablejs'; // 表格拖拽

export default {
  components: {
    tableComp,
  },
  name: "tableRowDraw",
  data() {
    return {
      tableColist, // 表格列表头数据
      // 当前页
      pageNo: 1,
      // 每页条数
      pageSize:10,
      // 总条数
      total: "50",
      tableData: [],
      isDialogModel: false, // 上下线模态框
      popModelContent: "",
    };
  },

  created() {
       this.pageNo = this.getStorageData("currentPage") || 1;
  },

  mounted() {
     this.mockTableData();
    // 表格拖拽
    this.$nextTick(() => {
        this.dropRow((oldIndex,newIndex) => {
        const currRow = this.tableData.splice(oldIndex, 1)[0]
        this.tableData.splice(newIndex, 0, currRow);
        })
    })
  },

  methods: {

   dropRow(endHandle) {
    const tbody = document.querySelector(
        ".el-table__body-wrapper tbody"
    );
    if (tbody) {
        Sortable.create(tbody, {
        animation: 300,
        delay: 0,
        handle: '.drop_handle',
        onEnd: endHandle,
        });
    }
   },
    mathRandom(arr) {
        return arr[Math.floor(Math.random()*arr.length)]
    },  

    startTime() {
        return `${new Date().getFullYear()}-${new Date().getMonth() < 10?0+new Date().getMonth()+1:new Date().getMonth()+1}-${new Date().getDate()<10?0+new Date().getDate():new Date().getDate()}`
    },

    endTime() {
        return `${new Date().getFullYear()}-${new Date().getMonth() < 10?0+new Date().getMonth()+1:new Date().getMonth()+1}-${new Date().getDate()<10?0+new Date().getDate():new Date().getDate()}`
    },

    mockTableData() {
            const tnames = ["单图单链接","多图N链接","H5_iframe","视频模板"];
            const status = ["1","2","3","100"];
            const pidNames =  ["浏览器","安全卫士","全部"];
            const areas = ["北京","上海","广州","深圳","福建","杭州"];
            const levels = ["p0","p1","p2"];
            const updaters = ["张三","李四","王五","小河"];
            for(let i = 0;i<= 50;i++) {
               this.tableData.push({
                    id:i,
                    tname: `${this.mathRandom(tnames)}`,
                    name: 'xxx1项目',
                    reco_key: '项目描述....',
                    status: `${this.mathRandom(status)}`,
                    pid_names: `${this.mathRandom(pidNames)}`,
                    areas: `${this.mathRandom(areas)}`,
                    level: `${this.mathRandom(levels)}`,
                    pv_max: Math.floor(Math.random()*10000),
                    start_time: this.startTime(),
                    end_time: this.endTime(),
                    update_time: this.startTime(),
                    update_user: this.mathRandom(updaters)
                });
            }
    },
    // 编辑
    handleEdit(Row) {
    //   this.$router.push({
    //     path: "/newAddProject",
    //     query: { id: Row.id },
    //   });
       this.$message({
          message: "编辑项目",
          type: "success",
        });
    },
    // 上线
    handleOnline(Row) {
      const now_date = new Date().getTime(); // 当前时间
      const end_time = new Date(Row.end_time).valueOf(); // 结束时间
      console.log(now_date, end_time);
      if (now_date > end_time) {
        this.$message({
          message: "上线时间已过期,请重新编辑时间",
          type: "warning",
        });
      } else {
        this.isDialogModel = true;
        console.log(Row.id, Row.status);
        this.status = Row.status;
        console.log(this.status);
        this.id = Row.id;
        console.log("上线");
        this.popModelContent = "确定要上线当前项目,定时投放?";
      }
    },

    // 下线
    handleOffline(Row) {
      this.isDialogModel = true;
      this.popModelContent = "确定要下线当前项目,停止投放?";
      this.status = Row.status;
      //this.id = Row.id;
      console.log("下线");
    },

    // 确认上线与下线
    handleSubmit() {
      if (this.status == 1) {
        // 1-待发布,2-待上线,3-已上线,100-结束
        const params = {};
        params.id = this.id;
        params.status = 2;
        // this.updateStatus(params);
        this.isDialogModel = false;
        // this.getProjectList(); // 重新拉取一下列表数据
      } else if (this.status == 3) {
        const params = {};
        params.id = this.id;
        params.status = 100;
        // this.updateStatus(params);
        this.isDialogModel = false;
        // this.getProjectList(); // 重新拉取一下列表数据
        this.isDialogModel = false;
      }
    },
    // 查看
    handleLook(Row) {
    //   this.$router.push({
    //     path: "/newAddProject",
    //     query: { id: Row.id },
    //   });
    //   console.log("查看");
      this.$message({
          message: "查看项目",
          type: "success",
        });
    },

    // 复制
    handleCopy() {
      console.log("复制");
    },

    setStorageData(key, value) {
      console.log(value);
      sessionStorage.setItem(key, value);
    },

    getStorageData(key) {
      const str = sessionStorage.getItem(key);
      if (typeof str == "string") {
        try {
          return JSON.parse(str);
        } catch (e) {
          return str;
        }
      }
      return str;
    },
    // 跳转页,currentPage 当前页改变时会触发
    pageCurrentChange(pageNo) {
      this.pageNo = pageNo;
      this.setStorageData("currentPage", this.pageNo);
    //   this.getProjectList();
      console.log("跳转页,currentPage 当前页改变时会触发");
    },

    // 每页条数,pageSize 改变时会触发
    pageSizeChange(PageSize) {
      this.pageSize = PageSize;
    //   this.getProjectList();
      console.log("跳转页,currentPage 当前页改变时会触发");
    },
  },
};
</script>

<style lang="scss" scoped>

  .table-content {
    margin: 30px 0 0 0;
    flex: 1;
    overflow: auto;
  }

  .dialog-model {
    .dalog-content {
      text-align: center;
    }
  }
</style>

tableComp.vue

代码语言:javascript
复制
<template>
  <div class="table-wrap">
    <!-- 表格开始 -->
    <div class="table-container">
      <el-table :data="tableData" resizable border height="100%" row-key="id">
        <el-table-column
          v-for="(item, index) in tableColist"
          :key="index"
          :prop="item.prop"
          :label="item.label"
          :size="item.medium"
          :align="item.align"
          :width="item.width"
          :showOverflowTooltip="item.showOverflowTooltip"
          :scoped-slot="labelHead"
          :class-name="item.dropHandle ? 'drop_handle' : ''"
        >
          <template slot-scope="scope">
            <!-- <p>{{scope.row[scope.column.property]}}</p> -->
            <p v-if="item.prop === 'status'">
              {{ onlineStatusEnum[scope.row[item.prop]] }}
            </p>
            <p v-else-if="item.prop === 'pid_names'">
              {{ scope.row[item.prop] }}
            </p>
            <p v-else-if="item.prop === 'level'">
              {{ levelEnum[scope.row[item.prop]] }}
            </p>
            <p v-else-if="item.prop == 'pv_max'">
              {{ scope.row[item.prop] }}万
            </p>
            <p v-else-if="item.prop == 'areas'">
              {{ scope.row[item.prop] == "" ? "全部" : scope.row[item.prop] }}
            </p>
            <p v-else>{{ scope.row[item.prop] }}</p>
          </template>
        </el-table-column>
        <el-table-column label="管理" min-width="290" align="center">
          <template slot-scope="scope">
            <el-button
              v-if="scope.row.status == 100 ? true : false"
              type="primary"
              size="mini"
              @click="handleLook(scope.row, scope.$index)"
              >查看</el-button
            >
            <!-- <el-button
              v-if="scope.row.status == 100 ? true : false"
              type="info"
              size="mini"
              @click="handleCopy(scope.row, scope.$index)"
              >复制</el-button
            > -->
            <el-button
              :disabled="scope.row.status !== 100 ? false : true"
              type="primary"
              size="mini"
              @click="handleEdit(scope.row, scope.$index)"
              >编辑</el-button
            >
            <el-button
              :disabled="scope.row.status == 1 ? false : true"
              size="mini"
              type="success"
              @click="handleOnline(scope.row, scope.$index)"
              >上线</el-button
            >
            <el-button
              :disabled="scope.row.status == 3 ? false : true"
              size="mini"
              type="danger"
              @click="handleOffline(scope.row, scope.$index)"
              >下线</el-button
            >
          </template>
        </el-table-column>
      </el-table>
    </div>
    <!-- 表格结束 -->
    <!-- 分页开始 -->
    <div class="pagination-container">
      <el-pagination
        v-if="tableData.length != 0"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="pageNo"
        :page-sizes="pageSizeList"
        :page-size="pageSize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="total"
      >
      </el-pagination>
    </div>
    <!-- 分页结束 -->
  </div>
</template>

<script>
export default {
  name: "tableComp",
  props: {
    // 表头数据
    tableColist: [],
    // 列表数据
    tableData: [],
    // 页每条
    pageSize: {
      type: Number,
      default: 10,
    },
    // 当前页
    pageNo: {
      type: Number,
      default: 1,
    },
    // 总数
    total: [Number],
  },
  data() {
    return {
      pageSizeList: [10, 25, 40, 50], // 每页显示个数选择器的选项设置
      onlineStatusEnum: {
        1: "待发布",
        2: "待上线",
        3: "已上线",
        100: "已结束",
      },
      levelEnum: {
        p0: "P0(紧急项目)",
        p1: "P1(日常项目)",
        p2: "P2(兜底项目)",
      },
    };
  },

  methods: {
    // 编辑
    handleEdit(Row, Index) {
      this.$emit("edit", Row, Index);
    },

    // 上线
    handleOnline(Row, Index) {
      this.$emit("online", Row, Index);
    },

    // 下线
    handleOffline(Row, Index) {
      this.$emit("offline", Row, Index);
    },
    // 查看
    handleLook(Row, Index) {
      this.$emit("look", Row, Index);
    },

    // 复制
    handleCopy() {
      this.$emit("copy");
    },

    // 每页条数,pageSize 改变时会触发
    handleSizeChange(PageSize) {
      console.log(PageSize);
      this.$emit("pageSizeChange", PageSize);
    },
    // 跳转页,currentPage 当前页改变时会触发
    handleCurrentChange(pageNo) {
      console.log("跳转当当前页", pageNo);
      this.$emit("pageCurrentChange", pageNo);
    },

    // 解决表格表头文字过多换行的问题
    labelHead(h, { column }) {
      let l = column.label.length;
      let f = 16;
      column.minWidth = f * l;
      return h("div", { class: "table-head", style: { width: "100%" } }, [
        column.label,
      ]);
    },
  },
};
</script>

<style lang="scss" scoped>
.table-wrap {
  height: 100%;
  display: flex;
  flex-direction: column;
  //  align-items: center;
  box-sizing: border-box;
  /deep/.table-container {
    flex: 1;
    height: 100%;
    .el-table__body-wrapper {
      height: auto !important;
      overflow-x: auto;
    }
  }

  .table-head {
    font-size: 14px !important; //设置固定的字体大小
  }
  .pagination-container {
    margin: 30px auto 30px;
  }
}

  /* 手型 */
.drop_handle{
  cursor: cursor;
}
</style>

tableColist.js

代码语言:javascript
复制
export const tableColist = [
    {
      label: "ID",
      prop: "id",
      width: "auto",
      size: "medium",
      align: "center",
      showOverflowTooltip: false,
      dropHandle: true
    },
    {
      label: "投放模板",
      prop: "tname",
      width: "auto",
      size: "medium",
      align: "center",
      showOverflowTooltip: true,
      dropHandle: true
    },
    {
      label: "项目名称",
      prop: "name",
      width: "auto",
      size: "medium",
      align: "center",
      showOverflowTooltip: true,
      dropHandle: true
    },
    {
      label:"项目描述",
      prop: "reco_key",
      width: "auto",
      size: "medium",
      align: "center",
      showOverflowTooltip: true,
      dropHandle: true
    },
    {
      label: "上线状态",
      prop: "status",
      width: "auto",
      size: "medium",
      align: "center",
      showOverflowTooltip: true,
      dropHandle: true
    },
    {
      label: "投放渠道",
      prop: "pid_names",
      width: "auto",
      size: "medium",
      align: "center",
      showOverflowTooltip: true,
      dropHandle: true
    },
    {
      label: "投放地区",
      prop: "areas",
      width: "auto",
      size: "medium",
      align: "center",
      showOverflowTooltip: true,
      dropHandle: true
    },
    {
      label: "项目优先级",
      prop: "level",
      width: "auto",
      size: "medium",
      align: "center",
      showOverflowTooltip: true,
      dropHandle: true
    },
    {
      label: "投放流量",
      prop: "pv_max",
      width: "auto",
      size: "medium",
      align: "center",
      showOverflowTooltip: true,
      dropHandle: true
    },
    {
      label: "上线时间",
      prop: "start_time",
      width: "auto",
      size: "medium",
      align: "center",
      showOverflowTooltip: true,
      dropHandle: true
    },
    {
      label: "下线时间",
      prop: "end_time",
      width: "auto",
      size: "medium",
      align: "center",
      showOverflowTooltip: true,
      dropHandle: true
    },
  
    {
      label: "操作时间",
      prop: "update_time",
      width: "auto",
      size: "medium",
      align: "center",
      showOverflowTooltip: true,
      dropHandle: true
    },
  
    {
      label: "操作人",
      prop: "update_user",
      width: "auto",
      size: "medium",
      align: "center",
      showOverflowTooltip: true,
      dropHandle: true
    },
  ];

总结

表格中的数据是模拟的,具体在实际的业务里,根据后端返回的数据,前端请求后端接口,就可以了的,表格的分页也在上面

反正代码很简单,一看就懂~如有不明白的,可以喊我,一起交流学习

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 itclanCoder 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 涉及到的知识
  • 具体实例效果(拖拽行)
  • 行拖拽的具体实现
  • 整个实例代码如下所示
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档