Element ui table

新增了一堆功能,在element 原生官方的table 並沒有寫好在操縱大量dom的時候會非常的lag,後期再來進行維護,不過發現了另一個寫好的table https://github.com/xuliangzhan/vxe-table

這個issue 好像蠻久的 大概兩年 https://github.com/ElemeFE/element/issues/6089

可以考慮?

虛擬滾動 or 滾動載入 https://zhuanlan.zhihu.com/p/53455289

我寫的code是寫類似於 滾動載入,本來想進行優化的...底子不夠深再看一陣子

javascript
// :data="filtermethod(list,search)"
<template>
  <div class="app-container">
    <el-table
      ref="singleTable"
      oncontextmenu="return false"
      v-loading="listLoading"
      :data="filteredData"
      element-loading-text="Loading"
      fit
      highlight-current-row
      height="800"
      @current-change="handleCurrentChange"
      @cell-mouse-enter="openDetails"
      @cell-click="tmp"
      @row-contextmenu="showmenu($row,$event, { name: item, index })"
      :data-size="list"
    >
      <el-table-column type="selection" width="55"></el-table-column>
      <el-table-column align="center" label="ID" width="95" sortable prop="id">
        <template slot-scope="scope">{{ scope.row.id }}</template>
      </el-table-column>
      <el-table-column label="Name" sortable prop="name">
        <template slot-scope="scope">
          <span class="link-type" @click="dialogFormVisible = true">{{ scope.row.name }}</span>
        </template>
      </el-table-column>
      <el-table-column label="Author" width="110" align="center">
        <template slot-scope="scope">
          <span>{{ scope.row.author }}</span>
        </template>
      </el-table-column>
      <el-table-column label="Pageviews" width="110" align="center">
        <template slot-scope="scope">{{ scope.row.pageviews }}</template>
      </el-table-column>
      <el-table-column class-name="status-col" label="Status" width="110" align="center">
        <template slot-scope="scope">
          <el-tag :type="scope.row.status | statusFilter">{{ scope.row.status }}</el-tag>
        </template>
      </el-table-column>
      <el-table-column label="city" width="120">
        <template scope="scope">
          <el-select v-model="list[scope.$index].city" placeholder="請選擇">
            <el-option
              v-for="item in cities"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
              <span style="float: left">{{ item.label }}</span>
              <span style="float: right; color: #8492a6; font-size: 13px">{{ item.value }}</span>
            </el-option>
          </el-select>
        </template>
      </el-table-column>

      <el-table-column align="center" prop="created_at" label="Display_time" width="200">
        <template slot-scope="scope">
          <i class="el-icon-time"/>
          <span>{{ scope.row.displaytime }}</span>
        </template>
      </el-table-column>

      <el-table-column min-width="300px" label="Title" prop="title">
        <template slot-scope="{row}">
          <template v-if="row.edit">
            <el-input v-model="row.title" class="edit-input" size="small"/>
            <el-button
              class="cancel-btn"
              size="small"
              icon="el-icon-refresh"
              type="warning"
              @click="cancelEdit(row)"
            >cancel</el-button>
          </template>
          <span v-else>{{ row.title }}</span>
        </template>
      </el-table-column>

      <el-table-column align="center" label="Actions" width="200">
        <template slot-scope="{row}">
          <el-button
            v-if="row.edit"
            type="success"
            size="small"
            icon="el-icon-circle-check-outline"
            @click="confirmEdit(row)"
          >Ok</el-button>
          <el-button
            v-else
            type="primary"
            size="small"
            icon="el-icon-edit"
            @click="row.edit=!row.edit"
          >Edit</el-button>
        </template>
        <template slot="header" slot-scope="scope">
          <el-input v-model="search" size="mini" placeholder="請輸入要搜尋文字"/>
        </template>
      </el-table-column>
    </el-table>
    <el-dialog
      title="Edit"
      :close-on-click-modal="false"
      :visible.sync="dialogFormVisible"
      ref="testdialog"
    >
      <el-form :model="form">
        <el-form-item label="搜尋">
          <el-input v-model="form.name" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="院區">
          <el-select v-model="form.region" placeholder="請選擇院區">
            <el-option label="区域一" value="shanghai"></el-option>
            <el-option label="区域二" value="beijing"></el-option>
          </el-select>
        </el-form-item>
        <el-table :data="gridData">
          <el-table-column property="date" label="日期" width="150"></el-table-column>
          <el-table-column property="name" label="姓名" width="200"></el-table-column>
          <el-table-column property="address" label="地址"></el-table-column>
        </el-table>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false"> </el-button>
        <el-button type="primary" @click="tmp2"> </el-button>
      </div>
    </el-dialog>

    <vue-context ref="menu">
      <template slot-scope="child" v-if="child.data">
        <li>
          <a class="textder" href="#" @click.prevent="alertName">
            Alert name : {{currentRow.name}}
            <br>
            Status : {{ currentRow.status }}
            <br>
            City : {{ currentRow.city }}
            <br>
            Title : {{ currentRow.title }}
          </a>
        </li>
        <li>
          <a class="textder" href="#" @click.prevent="remove( list)">Delete</a>
        </li>
      </template>
      <span>{{ result1 }}</span>
    </vue-context>
    <div style="margin-top: 20px ">
      <el-button @click="reload">reload</el-button>
      <el-button @click="toggleSelection([list[1], list[2]])">切换第二第三行的选中状态</el-button>
      <el-button @click="toggleSelection()">取消选择</el-button>
    </div>
  </div>
</template>

<script>
import { getList } from "@/api/table";
import { VueContext } from "vue-context";

export default {
  name: "loadmore",
  components: { VueContext },
  filters: {
    statusFilter(status) {
      const statusMap = {
        published: "success",
        draft: "gray",
        deleted: "danger"
      };
      return statusMap[status];
    }
  },
  computed: {
    showReset() {
      return this.items.length < items.length;
    },
    filteredData() {
      return this.list.filter((item, index) => {
        if (index < this.currentStartIndex) {
          return false;
        } else if (index > this.currentEndIndex) {
          return false;
        } else {
          return true;
        }
      });
    }
  },

  data() {
    return {
      testdata: null,
      result1: null,
      result2: null,
      list: [],
      listLoading: true,
      currentRow: null,
      search: "",
      multipleSelection: [],
      cities: [
        {
          value: "Beijing",
          label: "北京"
        },
        {
          value: "Shanghai",
          label: "上海"
        },
        {
          value: "Nanjing",
          label: "南京"
        },
        {
          value: "Chengdu",
          label: "成都"
        },
        {
          value: "Shenzhen",
          label: "深圳"
        },
        {
          value: "Guangzhou",
          label: "广州"
        }
      ],
      gridData: [
        {
          date: "2016-05-02",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1518 弄"
        },
        {
          date: "2016-05-04",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1518 弄"
        },
        {
          date: "2016-05-01",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1518 弄"
        },
        {
          date: "2016-05-03",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1518 弄"
        }
      ],

      value6: "",
      dialogFormVisible: false,
      form: {
        name: "",
        region: "",
        date1: "",
        date2: "",
        delivery: false,
        type: [],
        resource: "",
        desc: ""
      },
      currentStartIndex: 0,
      currentEndIndex: 20
    };
  },
  created() {
    this.fetchData();
  },
  computed: {
    filteredData() {
      return this.list.filter((item, index) => {
        if (index < this.currentStartIndex) {
          return true;
        } else if (index > this.currentEndIndex) {
          console.log("teeeeeeeeeeeeeeee1");
          return false;
        } else {
          console.log("teeeeeeeeeeeeeeee2");
          return true;
        }
      });
    }
  },
  methods: {
    fetchData() {
      this.listLoading = true;

      getList({
        id: this.currentStartIndex.toString()
      }).then(response => {
        const items = response.data.items;

        this.list = items.map(v => {
          this.$set(v, "edit", false); // https://vuejs.org/v2/guide/reactivity.html
          v.originalTitle = v.title; //  will be used when user click the cancel botton
          return v;
        });
        this.listLoading = false;
        this.list = this.list;
        this.filteredData;
      });
      // console.log(this.list);
    },
    alertName() {
      // event.preventDefault();
      // var x = event.clientX;
      // var y = event.clientY;

      // this.$refs.menu.positionMenu(x, y);
      // console.log(x, y);
      alert(`You clicked on "${this.testdata.title}"!`);
      // alert(`You clicked on "${name}"!`);
    },

    remove(list) {
      //console.log(this.currentRow.id);
      // console.log(this.testdata.title);
      // console.log(list);
      for (var i = 0; i < list.length; i++) {
        if (list[i].id == this.currentRow.id) {
          list.splice(i, 1);
        }
      }

      //this.$delete(this.items, index);
    },

    reset() {
      this.items = [...items];
    },
    mouseIsMoving(e) {
      setTimeout(() => {
        this.result1 = e.pageX;
        this.result2 = e.pageY;
      }, 100);
    },
    selectitem(item, id) {
      for (var i = 0; i < item.length; i++) {
        if (item[i] == id) {
          this.$refs.singleTable.setCurrentRow(i);
          break;
        }
      }
    },
    showmenu(row, event, data) {
      this.$refs.menu.data = data;
      this.$refs.menu.show = true;
      //  console.log(this.$refs.singleTable);
      // console.log(this.$refs.singleTable.data[this.testdata.id]);
      //this.selectitem(this.$refs.singleTable.data, id);
      let length = this.$refs.singleTable.data.length;
      for (var i = 0; i < length; i++) {
        if (this.$refs.singleTable.data[i].id == this.testdata.id) {
          this.$refs.singleTable.setCurrentRow(this.$refs.singleTable.data[i]);
          //   console.log("qwe");
          break;
        }
      }
      // this.$refs.singleTable.setCurrentRow(this.list[this.testdata.id]);
      this.$refs.menu.$nextTick(() => {
        this.$refs.menu.positionMenu(this.result2, this.result1);

        this.$refs.menu.$el.focus();
        this.$refs.menu.setItemRoles();

        if (this.$refs.menu.closeOnScroll) {
          this.$refs.menu.addScrollEventListener();
        }

        this.$refs.menu.$emit("open", event, this.data, this.top, this.left);
      });

      //alert(this.result1 + "," + this.result2);
    },

    openDetails(row, column, cell, event) {
      this.testdata = row;
      //  console.log(row);
    },
    filtermethod(val, search) {
      // val.filter(
      //   data =>
      //     !search || data.title.toLowerCase().includes(search.toLowerCase())
      // );

      let new_serach = search.split(" ");
      var new_data = [];
      //  console.log(tmp);
      if (!search == false) {
        val.filter(function(data) {
          let tmp = data;
          // var args = Array.from(data);
          // if (data.indexOf(search)) console.log(data);

          // console.log($.inArray((search, data)));
          // console.log(Object.values(data));

          let newsp = Object.values(data);
          let newspkey = Object.keys(data);
          let pass;
          for (let i = 0; i < new_serach.length; i++) {
            ///簡單搜尋
            // console.log(Object.values(data).indexOf(new_serach[i]));
            // if (Object.values(data).indexOf(new_serach[i]) >= 0) {
            //   pass = true;
            //簡單搜尋 ex

            for (let j = 0; j < newsp.length; j++) {
              // if (newsp[j].indexOf(new_serach[i]) >= 0) pass = true;
              // console.log(newsp[j]);

              //針對各個欄位 自訂義 篩選邏輯
              if (newspkey[j].toString() == "name") {
                pass = newsp[j] == new_serach[i];
              } else if (newspkey[j].toString() == "status") {
                pass = newsp[j].toString().indexOf(new_serach[i]) >= 0 || pass;
              } else if (newspkey[j].toString() == "title") {
                pass = newsp[j].toString().indexOf(new_serach[i]) >= 0;
              }
              if (new_data.includes(data) == false)
                if (pass) new_data.push(data);
              // if (newsp[j].toString().indexOf(new_serach[i]) >= 0) pass = true;
            }

            // newsp.forEach(function(element) {
            //   console.log(newsp);
            //   // if (element.indexOf(new_serach[i]) >= 0) pass = true;
            // });
          }

          //詳細搜尋 針對字串 不多做討論
          // let newsp = Object.values(data);
          // // for (let j = 0; j < newsp; j++)
          // //   if (newsp.indexOf(new_serach[i]) >= 0) {
          // //     pass = true;
          // //   }
          // newsp.forEach(function(element) {
          //   //console.log(element);
          //   for (var j = 0; j < element.length; j++) {
          //     // if (new_serach[i].indexOf(element.charAt(i)) >= 0) pass = true;
          //     console.log(new_serach[i]);
          //   }
          // });

          // for (var i = 0; i < data.length; i++) {
          //   new_data.push(data[i]);
          // }
          // data =>
          //   !search || data.title.toLowerCase().includes(tmp.toLowerCase());

          // console.log("test");
          // console.log(new_data);
          return pass;
        });
      }
      if (new_data.length == 0) return val;
      return new_data;
    },
    handleCurrentChange(val) {
      this.currentRow = val;

      // console.log(val.id);
    },
    toggleSelection(rows) {
      if (rows) {
        rows.forEach(row => {
          this.$refs.singleTable.toggleRowSelection(row);
          console.log(row);
        });
      } else {
        this.$refs.singleTable.clearSelection();
      }
    },
    handleSelectionChange(val) {
      this.multipleSelection = val;
      console.log(this.multipleSelection);
    },
    cancelEdit(row) {
      row.title = row.originalTitle;
      row.edit = false;
      this.$message({
        message: "The title has been restored to the original value",
        type: "warning"
      });
    },
    confirmEdit(row) {
      row.edit = false;
      row.originalTitle = row.title;
      this.$message({
        message: "The title has been edited",
        type: "success"
      });
    },
    rowdblclcik(row, column, event) {
      if (row.edit == false) {
        row.edit = true;
        row.originalTitle = row.title;
        this.$message({
          message: "The title has been edited" + row.edit,
          type: "success"
        });
      }
    },
    handleUpdate(row) {
      this.temp = Object.assign({}, row); // copy obj
      this.temp.timestamp = new Date(this.temp.timestamp);
      this.dialogStatus = "update";
      this.dialogFormVisible = true;
      this.$nextTick(() => {
        this.$refs["dataForm"].clearValidate();
      });
    },
    tmp(row, column, cell, event) {
      console.log(cell);
      //console.log(row[column.property]);

      console.log(column.property);
      if (row.edit == false && column.property == "title") {
        row.edit = true;
        row.originalTitle = row.title;
        this.$message({
          message: "The title has been edited" + row.edit,
          type: "success"
        });
      }
    },
    tmp2() {
      this.$notify({
        title: "成功",
        message: "更新成功",
        type: "success",
        duration: 2000
      });
      this.dialogFormVisible = false;
    },
    reload() {
      this.fetchData();
    },

    getMoreLog() {
      console.log("scrollTop not");

      this.dom = this.$refs.singleTable.bodyWrapper;
      this.dom.scrollTop = this.dom.scrollTop - 100;
      this.currentStartIndex = this.currentStartIndex + 20;

      this.currentEndIndex = 0;
      this.fetchData();
    }
  },
  mounted() {
    window.addEventListener("mousemove", this.mouseIsMoving);
    // 获取需要绑定的table
    this.dom = this.$refs.singleTable.bodyWrapper;
    this.dom.addEventListener("scroll", () => {
      // 滚动距离
      let scrollTop = this.dom.scrollTop;
      // 变量windowHeight是可视区的高度
      let windowHeight = this.dom.clientHeight || this.dom.clientHeight;
      // 变量scrollHeight是滚动条的总高度
      let scrollHeight = this.dom.scrollHeight || this.dom.scrollHeight;
      if (scrollTop + windowHeight === scrollHeight) {
        // 获取到的不是全部数据 当滚动到底部 继续获取新的数据
        if (!this.allData) this.getMoreLog();
        console.log(
          "scrollTop",
          scrollTop + "windowHeight",
          windowHeight + "scrollHeight",
          scrollHeight
        );
      }
      console.log(
        "scrollTop",
        scrollTop + "windowHeight",
        windowHeight + "scrollHeight",
        scrollHeight
      );
    });
  }, //mounted

  destroyed: function() {
    window.removeEventListener("mousemove", this.mouseIsMoving);
  }
};
</script>

<style scoped>
.edit-input {
  padding-right: 100px;
}
.cancel-btn {
  position: absolute;
  right: 15px;
  top: 10px;
}
.link-type,
.link-type:focus {
  color: #337ab7;
  cursor: pointer;
}
</style>




<style scoped>
.el-table__body-wrapper .el-table__row td {
  display: none;
}
.el-table__body-wrapper .el-table__row {
  height: 38px;
}
</style>