基於element-ui進行二次封裝的表格組件

来源:https://www.cnblogs.com/zz151/archive/2023/03/09/17198979.html
-Advertisement-
Play Games

<!-- * @description 表格組件 * @fileName TableList.vue * @authorQ * @date 2021/05/15 15:13:45 --> <template> <div class="table-container"> <el-table v-if= ...


<!--
* @description 表格組件
* @fileName TableList.vue
* @authorQ
* @date 2021/05/15 15:13:45
-->
<template>
  <div class="table-container">
    <el-table
      v-if="showTable"
      ref="filterTable"
      :span-method="spanName?objectSpanMethod:null"
      :data="data"
      :show-summary="showSummary.show ? showSummary.show : null"
      :summary-method="showSummary.show ? summaryMethod : null"
      :sum-text="showSummary.sumText ? showSummary.sumText : null"
      @filter-change="handleFilterChange"
      :border="border"
      :stripe="stripe"
      empty-text="暫無數據"
      style="width: 100%"
      :show-header="showHeader"
      :tooltip-effect="tooltipTheme"
      @selection-change="handleSelectionChange"
    >
      <!-- 選擇框列 -->
      <el-table-column
        v-if="selection"
        type="selection"
        :align="'center'"
      ></el-table-column>
      <!-- 排序列 -->
      <el-table-column
        v-if="indexShow"
        width="100"
        label="序號"
        :align="'center'"
      >
        <template slot-scope="scope">
          <div>
            <span>{{ scope.$index + 1 }}</span>
          </div>
        </template>
      </el-table-column>

      <template v-for="(item, index) in columns">
        <!-- 特殊列處理 -->
        <template v-if="item.render">
          <!-- visible 是否顯示該列 -->
          <el-table-column
            v-if="item.visible"
            :filters="item.filters ? item.filters : null"
            :column-key="item.prop"
            :key="index"
            :prop="item.prop ? item.prop : null"
            :align="item.align ? item.align : null"
            :fixed="item.fixed ? item.fixed : null"
            :label="item.label ? item.label : null"
            :show-overflow-tooltip="item.tooltip"
            :class-name="className"
            :sortable="item.sortable ? item.sortable : false"
            :width="item.width ? item.width : null"
          >
            <!-- 多級表頭 -->
            <template v-if="item.children && item.children.length > 0">
              <div v-for="(item1, index1) in item.children" :key="index1">
                <el-table-column
                  :key="index1"
                  :filters="item.filters ? item.filters : null"
                  :column-key="item.prop"
                  :prop="item1.prop ? item1.prop : null"
                  :align="item1.align ? item1.align : null"
                  :fixed="item1.fixed ? item1.fixed : null"
                  :label="item1.label ? item1.label : null"
                  :show-overflow-tooltip="item1.tooltip"
                  :class-name="className"
                  :sortable="item1.sortable ? item1.sortable : false"
                  :width="item1.width ? item1.width : null"
                >
                  <exSlot
                    :render="item1.render"
                    :row="scope.row"
                    :index1="scope.$index"
                    :column="item1"
                  />
                </el-table-column>
              </div>
            </template>
            <!-- 不是多級表頭 -->
            <template slot-scope="scope">
              <exSlot
                :render="item.render"
                :row="scope.row"
                :index="scope.$index"
                :column="item"
              />
            </template>
          </el-table-column>
        </template>

        <!-- 正常列 -->
        <template v-else>
          <!-- visible 是否顯示該列 -->
          <el-table-column
            v-if="item.visible"
            :key="index"
            :column-key="item.prop"
            :filters="item.filters ? item.filters : null"
            :prop="item.prop ? item.prop : null"
            :align="item.align ? item.align : null"
            :fixed="item.fixed ? item.fixed : null"
            :label="item.label ? item.label : null"
            :class-name="className"
            :show-overflow-tooltip="item.tooltip"
            :sortable="item.sortable ? item.sortable : false"
            :width="item.width ? item.width : null"
          >
            <!-- 多級表頭 -->
            <template v-if="item.children && item.children.length > 0">
              <template v-for="(item1, index1) in item.children">
                <el-table-column
                  :prop="item1.prop ? item1.prop : null"
                  :column-key="item.prop"
                  :filters="item.filters ? item.filters : null"
                  :align="item1.align ? item1.align : null"
                  :fixed="item1.fixed ? item1.fixed : null"
                  :label="item1.label ? item1.label : null"
                  :show-overflow-tooltip="item1.tooltip"
                  :class-name="className"
                  :sortable="item1.sortable ? item1.sortable : false"
                  :width="item1.width ? item1.width : null"
                >
                  <template slot-scope="scope">
                    <span v-html="formatter(scope.row[item1.prop])"></span>
                  </template>
                </el-table-column>
              </template>
            </template>
            <template slot-scope="scope">
              <!-- 字典處理 -->
              <template v-if="item.dict">
                <!-- 判斷原始數據是否有效,有效轉為字典數據,無效則轉為--占位符 -->
                <span
                  v-if="!scope.row[item.prop]"
                  v-html="formatter(scope.row[item.prop])"
                ></span>
                <dict-tag
                  v-else
                  :options="dict.type[item.prop]"
                  :value="scope.row[item.prop]"
                />
              </template>
              <!-- 時間格式化 -->
              <span v-else-if="item.time">{{
                parseTime(scope.row[item.prop], "{y}-{m}-{d}")
              }}</span>
              <!-- 不做處理 -->
              <span v-else v-html="formatter(scope.row[item.prop])"></span>
            </template>
          </el-table-column>
        </template>
      </template>

      <!-- 操作列 -->
      <el-table-column
        v-if="isEdit === true"
        label="操作"
        :align="'center'"
        width="200"
        :fixed="fixed"
      >
        <template slot-scope="scope">
          <slot name="editSlot">
            <template>
              <el-button type="primary" @click="editClick(scope.row)"
                >編輯</el-button
              >
              <el-button type="danger" @click="deleteClick(scope.row)"
                >刪除</el-button
              >
            </template>
          </slot>
        </template>
      </el-table-column>
    </el-table>
    <el-pagination
      :style="{ float: `${paginationPosition}` }"
      v-if="pagination"
      :background="background"
      :current-page.sync="currentPage"
      :page-size.sync="currentSize"
      :layout="layout"
      :page-sizes="pageSizes"
      :total="total"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
    />
  </div>
</template>

<script>
// 自定義內容的組件
var exSlot = {
  functional: true,
  props: {
    row: Object,
    render: Function,
    index: Number,
    column: {
      type: Object,
      default: null,
    },
  },
  // render 函數
  render: (h, context) => {
    const params = {
      row: context.props.row,
      index: context.props.index,
    };
    if (context.props.columns) params.columns = context.props.columns;
    return context.props.render(h, params);
  },
};
export default {
  name: "TableList",
  components: { exSlot },
  props: {
    data: {
      type: Array,
      default: () => [],
    },
    update: {
      type: Number,
      default: () => null,
    },

    // 是否顯示合計列
    showSummary: {
      type: Object,
      default: () => {
        return {
          show: false,
          sumText: "總計",
        };
      },
    },
    // 需要通過那個欄位屬性進行比較合併
    spanName: {
      type: String,
      default: () => {
        return null;
      },
    },
    // 需要合併數組
    spanColumnArr:{
      type:Array,
      default:()=>{
        return [0]
      }
    },
    tooltipTheme: {
      type: String,
      default: "dark",
    },
    // 是否顯示表頭
    showHeader: {
      type: Boolean,
      default: true,
    },
    // 是否添加排序列
    indexShow: {
      type: Boolean,
      default: true,
    },
    showTable: {
      type: Boolean,
      default: true,
    },
    // 是否顯示選擇框列
    selection: {
      type: Boolean,
      default: false,
    },
    // 欄位名
    columns: {
      type: Array,
      default: () => [],
    },
    // 是否含有邊框
    border: {
      type: Boolean,
      default: false,
    },

    // 是否顯示斑馬條紋
    stripe: {
      type: Boolean,
      default: false,
    },
    // 是否是可以編輯的表格
    isEdit: {
      type: Boolean,
      default: false,
    },
    // 是否固定右側一列,只對右側操作欄起作用
    fixed: {
      type: String,
      default: "right",
    },

    // 是否顯示分頁
    pagination: {
      type: Boolean,
      default: false,
    },
    // 分頁的位置
    paginationPosition: {
      type: String,
      default: "center",
    },
    total: {
      required: false,
      type: Number,
    },
    page: {
      type: Number,
      default: 1, // 預設第一頁
    },
    limit: {
      type: Number,
      default: 10, // 預設每頁20條
    },
    pageSizes: {
      type: Array,
      // default: [10, 20, 30, 50]
      default: function () {
        return [1, 2, 3, 5]; // 預設顯示可選的每頁多少條數據
      },
    },
    layout: {
      type: String,
      default: "total, sizes, prev, pager, next, jumper",
    },
    background: {
      type: Boolean,
      default: true,
    },
    autoScroll: {
      type: Boolean,
      default: true,
    },
    hidden: {
      type: Boolean,
      default: false,
    },
    className: {
      type: String,
      default: "",
    },
    render: {
      type: Function,
      default: function () {},
    },
  },
  data() {
    return {
      cloneColumns: [],
      spanArr: [], // 跨行數組
      pos: null, // 跨行數組
    };
  },
  computed: {
    // 當前頁多少條數據並且賦值給父組件
    currentPage: {
      get() {
        return this.page;
      },
      set(val) {
        this.$emit("update:page", val);
      },
    },
    // 改變當前頁幾條數據得值賦值給父組件
    currentSize: {
      get() {
        return this.limit;
      },
      set(val) {
        this.$emit("update:limit", val);
      },
    },
  },
  created() {
    this.cloneColumns = JSON.parse(JSON.stringify(this.columns));
  },
  watch: {
    columns(value) {},
  },
  mounted() {
    if (this.spanName) {
      this.getSpanArr(this.data);
    }
  },

  methods: {
     // 合同單元格直接傳入:spanName="id或者其他欄位屬性名"
    getSpanArr(data) {
      for (let i = 0; i < data.length; i++) {
        if (i === 0) {
          this.spanArr.push(1);
          this.pos = 0;
        } else {
          // 判斷當前的元素和上一個元素是否相同
          // name 需要通過哪個欄位來進行比較合併
          if (data[i][this.spanName] === data[i - 1][this.spanName]) {
            this.spanArr[this.pos] += 1;
            this.spanArr.push(0);
          } else {
            this.spanArr.push(1);
            this.pos = i;
          }
        }
      }
    },

  // 合併
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
      if (this.spanColumnArr.includes(columnIndex)) {
        const _row = this.spanArr[rowIndex];
        const _col = _row > 0 ? 1 : 0;
        return {
          rowspan: _row,
          colspan: _col,
        };
      }
    },

    // 自定義合計行
    summaryMethod(params) {
      const { columns, data } = params;
      const sums = [];
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = "總計";
          return;
        }
        const values = data.map((item) => item[column.property]);
        let num = 0;
        for (let i = 0; i < values.length; i++) {
          if (values[i]) {
            num += Number(values[i]);
            sums[index] = num;
          } else {
            if (isNaN(values[i])) {
            } else {
              num += Number(values[i]);
              sums[index] = num;
            }
          }
        }
        if (column.property === "lv1Time" || column.property === "lv2Time") {
          if (values.filter(Boolean).length === 0) {
            sums[index] = "";
          } else {
            let num = 0;
            for (let i = 0; i < values.length; i++) {
              if (values[i]) {
                num += Number(values[i]);
                sums[index] = num;
              } else {
                if (isNaN(values[i])) {
                } else {
                  num += Number(values[i]);
                  sums[index] = num;
                }
              }
            }
          }
        }
      });
      let arr = [];
      sums.map((i, index) => {
        if (index === 0) {
          arr.push(i);
        } else {
          if (!isNaN(i)) {
            arr.push(i);
          } else {
            arr.push("");
          }
        }
      });
      return arr;
    },
    handleFilterChange(filters) {
      if (filters.length > 0) {
        this.$refs.filterTable.clearSelection();
        this.$refs.filterTable.toggleRowSelection(filters.pop());
      } else {
        this.columns.map((item) => {
          // 判斷當前是那一列進行了篩選
          if (item.prop === Object.keys(filters)[0]) {
            item.filterValues = filters;
          }
        });

        this.$emit("filtersParams", this.columns);
      }
    },
    // 當前行當前列數據是否有效,無效的話,返回--占位符
    formatter(row) {
      if (row) {
        return isNaN(parseFloat(row)) && isFinite(row)
          ? '<span class="isNaN">--</span>'
          : row;
      } else {
        return '<span class="isNaN">--</span>';
      }
    },
    /**
     * @param {*}
     * @return {*}
     * @author: Q
     * @Date: 2021-09-01 11:56:37
     * @description: 已選的數據項
     */
    handleSelectionChange(val) {
      this.$emit("selectVal", val);
    },
    handleSizeChange(val) {
      this.pageSize = val;
      this.$emit("pagination", { pageIndex: this.page, pageSize: val });
    },
    handleCurrentChange(val) {
      this.$emit("pagination", { pageIndex: val, pageSize: this.limit });
    },
    // 修改按鈕的點擊事件
    editClick(val) {
      this.$emit("edit", val);
    },
    // 刪除按鈕點擊事件
    deleteClick(val) {
      this.$confirm("此操作將永久刪除該文件, 是否繼續?", "提示", {
        confirmButtonText: "確定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          this.$emit("del", val);
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "已取消刪除",
          });
        });
    },
  },
};
</script>

<style lang="scss">
.table-container {
  text-align: center;
  .el-pagination {
    margin-left: 0 !important;
    margin-top: 0 !important;
    background: #fff !important;
    height: 112px;
    line-height: 112px;
    display: flex;
    justify-content: center;
    align-items: center;
    ul {
      display: flex;
      justify-content: space-around;
      align-items: center;
      li {
        border-radius: 6px !important;
        color: #666666 !important;
      }
      .active {
        color: #fff !important;
        background: #1677ffff !important;
      }
    }
    button {
      border-radius: 6px !important;
      color: #666666 !important;
    }
  }
}
.table-container.el-table {
  margin-top: 20px;
}

.table-container .el-pagination {
  margin-top: 20px;
  margin-left: 20px;
}
.isNaN {
  color: red;
}
</style>

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 數據治理是推動大型集團企業轉型升級、提升競爭優勢、實現高質量發展的重要引擎。通過全鏈數據結構化,實現業務對象、業務規則、業務流程數字化,推進全鏈業務深度數字化,夯實數據運營底座。 廈門國貿集團股份有限公司(簡稱“國貿股份”)是國有控股上市公司,同時也是首批全國供應鏈創新與應用示範企業,在“十四五”規 ...
  • 摘要:其實游戲客戶對資料庫的訴求是很明確的,資料庫應當“放心存放心用”。 本文分享自華為雲社區《華為雲GaussDB(for Redis)揭秘第27期:聊聊游戲業務怎麼用高斯Redis》,作者:高斯Redis官方博客。 華為雲資料庫團隊是比較重視技術洞察的,對客戶真實的業務場景也比較看重。年初出差了 ...
  • GreatSQL社區原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。 GreatSQL是MySQL的國產分支版本,使用上與MySQL一致。 作者: 花家舍 文章來源:GreatSQL社區原創 前文回顧 實現一個簡單的Database系列 譯註:cstack在github維護了一個簡單的、類似 ...
  • 生活中存在同時使用兩個微信的情況,一個工作一個生活,這時希望同時在電腦上登錄兩個賬號。如何做到呢?步驟如下: 右鍵單擊“微信”圖標,選擇屬性,目標框內的路徑就是微信安裝路徑,複製目標框里的內容。 將如下命令複製到 TXT 文件保存,再將該文件重命名,主要是將尾碼名改成“.bat”文件。 @echo ...
  • 好家伙,本篇為做題思考 書接上文 題目如下: 1.請給出下列代碼的輸出結果,並配合"消息隊列"寫出相關解釋 async function foo() { console.log(2); console.log(await Promise.resolve(8)); console.log(9); } ...
  • 一般來說,項目由子模塊組成,拿到後端提供過來的介面,一般也是按照子模塊來分類提供的.請教一下各位,你們前端項目是如何管理api的? 希望各位貼點你們的優秀代碼段上來學習學習. 常見: 各個模塊的api存放到單獨的js文件里,返回一個請求實例promise對象 使用的時候根據需求引入相應的請求方法 / ...
  • 其他章節請看: webgl 系列 變換矩陣和動畫 動畫就是不停地將某個東西變換(transform)。例如將三角形不停地旋轉就是一個動畫 和 CSS transform 類似,變換有三種形式:平移、縮放和旋轉。 簡單的變換用普通表達式容易實現,如果事情複雜,比如旋轉後平移,這時就可以使用變換矩陣。 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 網站效果演示:ashuai.work:8888/#/myLoad GitHub倉庫地址代碼:github.com/shuirongshu… 載入中思路分析 實現載入中效果,一般有兩種方式: 第一種是:搞一個load組件,然後使用Vue.e ...
一周排行
    -Advertisement-
    Play Games
  • 前言 微服務架構已經成為搭建高效、可擴展系統的關鍵技術之一,然而,現有許多微服務框架往往過於複雜,使得我們普通開發者難以快速上手並體驗到微服務帶了的便利。為瞭解決這一問題,於是作者精心打造了一款最接地氣的 .NET 微服務框架,幫助我們輕鬆構建和管理微服務應用。 本框架不僅支持 Consul 服務註 ...
  • 先看一下效果吧: 如果不會寫動畫或者懶得寫動畫,就直接交給Blend來做吧; 其實Blend操作起來很簡單,有點類似於在操作PS,我們只需要設置關鍵幀,滑鼠點來點去就可以了,Blend會自動幫我們生成我們想要的動畫效果. 第一步:要創建一個空的WPF項目 第二步:右鍵我們的項目,在最下方有一個,在B ...
  • Prism:框架介紹與安裝 什麼是Prism? Prism是一個用於在 WPF、Xamarin Form、Uno 平臺和 WinUI 中構建鬆散耦合、可維護和可測試的 XAML 應用程式框架 Github https://github.com/PrismLibrary/Prism NuGet htt ...
  • 在WPF中,屏幕上的所有內容,都是通過畫筆(Brush)畫上去的。如按鈕的背景色,邊框,文本框的前景和形狀填充。藉助畫筆,可以繪製頁面上的所有UI對象。不同畫筆具有不同類型的輸出( 如:某些畫筆使用純色繪製區域,其他畫筆使用漸變、圖案、圖像或繪圖)。 ...
  • 前言 嗨,大家好!推薦一個基於 .NET 8 的高併發微服務電商系統,涵蓋了商品、訂單、會員、服務、財務等50多種實用功能。 項目不僅使用了 .NET 8 的最新特性,還集成了AutoFac、DotLiquid、HangFire、Nlog、Jwt、LayUIAdmin、SqlSugar、MySQL、 ...
  • 本文主要介紹攝像頭(相機)如何採集數據,用於類似攝像頭本地顯示軟體,以及流媒體數據傳輸場景如傳屏、視訊會議等。 攝像頭採集有多種方案,如AForge.NET、WPFMediaKit、OpenCvSharp、EmguCv、DirectShow.NET、MediaCaptre(UWP),網上一些文章以及 ...
  • 前言 Seal-Report 是一款.NET 開源報表工具,擁有 1.4K Star。它提供了一個完整的框架,使用 C# 編寫,最新的版本採用的是 .NET 8.0 。 它能夠高效地從各種資料庫或 NoSQL 數據源生成日常報表,並支持執行複雜的報表任務。 其簡單易用的安裝過程和直觀的設計界面,我們 ...
  • 背景需求: 系統需要對接到XXX官方的API,但因此官方對接以及管理都十分嚴格。而本人部門的系統中包含諸多子系統,系統間為了穩定,程式間多數固定Token+特殊驗證進行調用,且後期還要提供給其他兄弟部門系統共同調用。 原則上:每套系統都必須單獨接入到官方,但官方的接入複雜,還要官方指定機構認證的證書 ...
  • 本文介紹下電腦設備關機的情況下如何通過網路喚醒設備,之前電源S狀態 電腦Power電源狀態- 唐宋元明清2188 - 博客園 (cnblogs.com) 有介紹過遠程喚醒設備,後面這倆天瞭解多了點所以單獨加個隨筆 設備關機的情況下,使用網路喚醒的前提條件: 1. 被喚醒設備需要支持這WakeOnL ...
  • 前言 大家好,推薦一個.NET 8.0 為核心,結合前端 Vue 框架,實現了前後端完全分離的設計理念。它不僅提供了強大的基礎功能支持,如許可權管理、代碼生成器等,還通過採用主流技術和最佳實踐,顯著降低了開發難度,加快了項目交付速度。 如果你需要一個高效的開發解決方案,本框架能幫助大家輕鬆應對挑戰,實 ...