Skip to content

ProjectProblems

elementui table 树形 勾选父节点时勾选全部子节点

需要加以下三个方法 @select="selectChange" @select-all="selectAllChange" @selection-change="selectionChangeHandler"

vue
<template>
  <el-table ref="multiTable" v-loading="loading" lazy :load="getMenus" :data="list" :tree-props="{children: 'children', hasChildren: 'hasChildren'}" row-key="id" @select="selectChange" @select-all="selectAllChange" @selection-change="selectionChangeHandler"></el-table>
</template>

<script>
export default {
  data() {
    return {
      loading: false,
      getMenus: null,
      list: [],
    };
  },
  methods: {
    /**
     * 用于树形表格多选,单选的封装
     * @param selection
     * @param row
     */
    selectChange(selection, row) {
      // 如果selection中存在row代表是选中,否则是取消选中
      if (
        selection.find(val => {
          return this.getDataId(val) === this.getDataId(row);
        })
      ) {
        if (row.children) {
          //注意这里的children是后台返回数据的children字段
          row.children.forEach(val => {
            this.$refs.multiTable.toggleRowSelection(val, true);
            selection.push(val);
            if (val.children) {
              this.selectChange(selection, val);
            }
          });
        }
      } else {
        this.toggleRowSelection(selection, row);
      }
    },
    /**
     * 用于树形表格多选, 选中所有
     * @param selection
     */
    selectAllChange(selection) {
      // 如果选中的数目与请求到的数目相同就选中子节点,否则就清空选中
      if (selection && selection.length === this.list.length) {
        selection.forEach(val => {
          this.selectChange(selection, val);
        });
      } else {
        this.$refs.multiTable.clearSelection();
      }
    },
    // 选择改变
    selectionChangeHandler(val) {
      this.selections = val;
      this.unique(this.selections, "id"); //这里有一个问题就是这样点选完之后,数据有重复,所以根据id手动去重,期待优化
    },
    /**
     * 切换选中状态
     * @param selection
     * @param data
     */
    toggleRowSelection(selection, data) {
      if (data.children) {
        //注意这里的children也是后台返回数据的children字段
        data.children.forEach(val => {
          this.$refs.multiTable.toggleRowSelection(val, false);
          if (val.children) {
            this.toggleRowSelection(selection, val);
          }
        });
      }
    },
    getDataId(data) {
      return data["id"];
    },
    //数组去重
    unique(arr, i) {
      for (let i = 0; i < arr.length; i++) {
        for (let j = i + 1; j < arr.length; j++) {
          if (arr[i].id === arr[j].id) {
            arr.splice(j, 1);
            j--;
          }
        }
      }
    },
    //列表树懒加载
    getMenus(tree, treeNode, resolve) {
      const params = {pid: tree.id};
      setTimeout(() => {
        /*crudMenu.getMenus(params).then(res => {
         resolve(res.content)
         })*/
      }, 100);
    },
  },
};
</script>

vue
<!-- 存货 弹窗 -->
<template>
  <el-dialog :title="titleName" @open="open" v-if="IsShowPage" :visible.sync="IsShowPage" :append-to-body="true" width="70%" @close="cancel" :close-on-click-modal="false" :close-on-press-escape="false">
    <div class="sc-list-body">
      <div class="table-btn-warp flex_between_center">
        <search @search="cliSearch" placeholder="请输入编码、名称" />
      </div>
      <el-table ref="multiTable" row-key="stockCode" :data="tableData" :default-expand-all="defaultExpandAll" :row-class-name="tableRowClassName" max-height="500" @select="selectChange" @select-all="selectAllChange" @selection-change="selectionChangeHandler" :tree-props="treeProps">
        <el-table-column label="序号" type="index" align="center" width="60" />
        <el-table-column type="selection" :reserve-selection="true" align="center" />
        <el-table-column label="编号" prop="stockCode" width="180">
          <template slot-scope="{row}">
            <el-button type="text">{{ row.stockCode }}</el-button>
          </template>
        </el-table-column>
        <el-table-column label="名称" prop="stockName" show-overflow-tooltip width="180" />
        <el-table-column label="辅助属性" prop="customStockName" show-overflow-tooltip width="180" />
        <el-table-column label="存货类别" prop="stockTypeName" show-overflow-tooltip width="180" />
        <el-table-column label="规格型号" prop="specs" show-overflow-tooltip width="180" />
        <el-table-column label="单位" prop="measureUnit" show-overflow-tooltip align="center" width="180" />
        <el-table-column label="创建日期" prop="createTime" show-overflow-tooltip width="180" />
        <el-table-column label="创建者" prop="createUserName" show-overflow-tooltip align="center" width="180" />
        <el-table-column label="备注" prop="remark" show-overflow-tooltip width="180" />
      </el-table>
      <pagination :total="pagination.total" :page.sync="pagination.page" :limit.sync="pagination.pageSize" @pagination="getLists" />
    </div>
    <div slot="footer" class="dialog-footer">
      <el-button type="primary" @click="save">确定</el-button>
      <el-button @click="cancel">取消</el-button>
    </div>
  </el-dialog>
</template>

<script>
import search from "@/views/setting/supplyChainSys/components/search";
import pagination from "@/views/setting/supplyChainSys/components/pagination";
import {getStockList} from "@/api/supplyChain";

export default {
  props: {
    dialogFormVisible: {type: Boolean, default: false},
    parent: {type: Boolean, default: false}, //勾选项带有子项时,父项是否可选默认为false不可选,true可选
    defaultExpandAll: {type: Boolean, default: true}, //带有子项时,是否默认展开所有子项
  },
  components: {search, pagination},
  data() {
    return {
      IsShowPage: false,
      titleName: "存货",
      tableData: [],
      keyword: "",
      pagination: {total: 0, pageSize: 10, page: 1},
      checkBoxData: [],
      treeProps: {children: "children", hasChildren: "hasChildren"},
    };
  },
  watch: {
    dialogFormVisible(val) {
      this.IsShowPage = val;
      if (val) {
        console.log(this.checkBoxData);
        this.getStockList();
      }
    },
  },
  methods: {
    // 弹窗每次打开都会执行一次这个方法,但是这个方法在列表接口调用之后才执行
    open() {},
    /**
     * 用于树形表格多选,单选的封装
     * @param selection
     * @param row
     */
    selectChange(selection, row) {
      // 如果selection中存在row代表是选中,否则是取消选中
      if (
        selection.find(val => {
          return this.getDataId(val) === this.getDataId(row);
        })
      ) {
        if (row.children) {
          //注意这里的children是后台返回数据的children字段
          row.children.forEach(val => {
            this.$refs.multiTable.toggleRowSelection(val, true);
            selection.push(val);
            if (val.children) {
              this.selectChange(selection, val);
            }
          });
        }
      } else {
        this.toggleRowSelection(selection, row);
      }
    },
    /**
     * 用于树形表格多选, 选中所有
     * @param selection
     */
    selectAllChange(selection) {
      // 如果选中的数目与请求到的数目相同就选中子节点,否则就清空选中
      if (selection && selection.length === this.tableData.length) {
        selection.forEach(val => {
          this.selectChange(selection, val);
        });
      } else {
        this.$refs.multiTable.clearSelection();
      }
    },
    // 选择改变
    selectionChangeHandler(val) {
      this.checkBoxData = val;
      this.unique(this.checkBoxData, "stockCode");
    },
    /**
     * 切换选中状态
     * @param selection
     * @param data
     */
    toggleRowSelection(selection, data) {
      if (data.children) {
        //注意这里的children也是后台返回数据的children字段
        data.children.forEach(val => {
          this.$refs.multiTable.toggleRowSelection(val, false);
          if (val.children) {
            this.toggleRowSelection(selection, val);
          }
        });
      }
    },
    getDataId(data) {
      return data["stockCode"];
    },
    //数组去重
    unique(arr, key) {
      for (let i = 0; i < arr.length; i++) {
        for (let j = i + 1; j < arr.length; j++) {
          if (arr[i][key] === arr[j][key]) {
            arr.splice(j, 1);
            j--;
          }
        }
      }
    },
    // 把每一行的索引放进row
    tableRowClassName({row, rowIndex}) {
      row.index = rowIndex;
    },
    getLists(val) {
      this.pagination.page = val.page;
      this.pagination.pageSize = val.pageSize;
      this.getStockList();
    },
    cliSearch(val) {
      this.keyword = val;
      this.pagination.page = 1;
      this.getStockList();
    },
    // 存货格式化 ps:阿威转一飞   (去除带有children的项)
    formatSotck(arr) {
      let stockArr = JSON.parse(JSON.stringify(arr));
      if (!this.parent) {
        stockArr = stockArr.filter(val => {
          return !val.children;
        });
      } //默认关闭带有children的项(根结点带有chindren,这个根结点在`parent`是false是会生效(把带有children的项过滤))
      stockArr.forEach(item => {
        item.stockId = item.id;
        item.stockSkuId = item.skuId;
        item.attributeType = item.customStockName;
        item.desc = item.remark;
        item.hasShelfLife = item.shelfLife;
        item.hasBatchNo = item.batch;
        item.hasSerialNo = item.serialNum;
        delete item.id;
        if (item.multimeasureUnit === 1) {
          item.unitList.forEach(unitItem => {
            unitItem.unitId = unitItem.id;
            unitItem.unitRatio = unitItem.exchangeRatio;
            delete unitItem.id;
            delete unitItem.exchangeRatio;
          });
        } else {
          this.$set(item, "unitList", [{unitId: item.measureUnitId, unitName: item.measureUnit, unitRatio: 1}]);
        }
        if (item.children && item.children.length) {
          this.formatSotck(item.children);
        }
      });
      return stockArr;
    },
    // 列表
    getStockList(obj = {}) {
      obj = Object.assign(obj, {
        page: this.pagination.page,
        pageSize: this.pagination.pageSize,
        stockTypeId: "000",
        status: 1,
        keyword: this.keyword,
      });
      getStockList(obj).then(res => {
        let {list, total} = res.data;
        this.tableData = list;
        this.pagination.total = total;
      });
    },
    cancel() {
      this.IsShowPage = false;
      this.$emit("cancel");
      this.reset();
    },
    save() {
      // 校验勾选项
      if (this.checkBoxData.length === 0) {
        this.$message.error("请勾选需要添加的存货");
        return false;
      }
      if (!this.parent) {
        // 开启根结点不可选, 则过滤父节点留下根节点
        let gather = []; //存放父级stockCode
        this.checkBoxData.forEach(item => {
          if (item.children && item.children.length) {
            gather.push(item.stockCode);
          }
        });
        // console.log(gather, 'gather');
        // console.log(this.checkBoxData, 'checkBoxData');
        //0时不提示
        if (gather.length === 0) {
          let arr = this.formatSotck(this.checkBoxData);
          this.$emit("save", arr);
          this.$emit("cancel");
          this.IsShowPage = false;
          this.reset();
        } else {
          this.$confirm(`勾选的存货中编号${gather.join(",")}是作为根结点的存货,不能录入,继续将过滤掉该项`, "提示", {
            confirmButtonText: "继续",
            cancelButtonText: "取消",
            type: "warning",
          })
            .then(() => {
              let arr = this.formatSotck(this.checkBoxData);
              this.$emit("save", arr);
              this.$emit("cancel");
              this.IsShowPage = false;
              this.reset();
            })
            .catch(() => {
              return false;
            });
        }
      } else {
        // 开启根结点可选
        let arr = this.formatSotck(this.checkBoxData);
        this.$emit("save", arr);
        this.$emit("cancel");
        this.IsShowPage = false;
        this.reset();
      }
      // 校验勾选项 \\
    },
    visible() {},
    reset() {
      this.keyword = "";
      this.tableData = [];
      this.checkBoxData = [];
      this.treeProps = {children: "children", hasChildren: "hasChildren"};
      this.pagination = {total: 0, pageSize: 10, page: 1};
    },
  },
};
</script>
<style lang="scss" scoped>
.table-btn-warp {
  margin-bottom: 16px;
}
</style>

dialog 可拖拽移动

vue
<script>
export default {
  // v-directives
  directives: {
    dialogDrag: {
      inserted: function (el) {
        const dialogHeaderEl = el.querySelector(".el-dialog__header");
        const dragDom = el.querySelector(".el-dialog");
        dialogHeaderEl.style.cursor = "move";
        dialogHeaderEl.onmousedown = e => {
          const disX = e["clientX"] - dialogHeaderEl.offsetLeft;
          const disY = e["clientY"] - dialogHeaderEl.offsetTop;
          document.onmousemove = function (e) {
            const l = e["clientX"] - disX;
            const t = e["clientY"] - disY;
            dragDom.style.left = `${l}px`;
            dragDom.style.top = `${t}px`;
          };
          document.onmouseup = function (e) {
            document.onmousemove = null;
            document.onmouseup = null;
          };
        };
      },
    },
  },
};
</script>

Element UI 低版本使用 el-cascader 数据量大造成的卡顿[^13.2]

vue
<template>
  <el-cascader @visible-change="visibleChange"></el-cascader>
</template>
<script>
export default {
  methods: {
    visibleChange() {
      this.$nextTick(() => {
        let $el = document.querySelectorAll(".el-cascader-panel .el-cascader-node[aria-owns]");
        Array.from($el).map(el => el.removeAttribute("aria-owns"));
      });
    },
  },
};
</script>

version 2.3.3