Bootstrap

Vue+Element中Table树形懒加载,添加,修改,删除后数据动态更新

数据准备

结果呈现

添加最外层菜单 

添加子菜单界面

直接上代码

index.vue

<template>
  <div class="table-container">
    <vab-query-form>
      <vab-query-form-left-panel :span="3">
        <el-button icon="el-icon-plus" type="success" @click="handleAdd">
          添加
        </el-button>
      </vab-query-form-left-panel>
      <vab-query-form-right-panel :span="21">
        <el-form
          ref="form"
          :inline="true"
          label-width="80px"
          :model="queryForm"
          @submit.native.prevent
        >
          <el-form-item label="品牌名称">
            <el-input
              v-model="queryForm.brandName"
              clearable
              placeholder="请输入品牌名称"
              style="width: 140px"
            />
          </el-form-item>
          <el-form-item>
            <el-button
              icon="el-icon-search"
              native-type="submit"
              type="primary"
              @click="handleQuery"
            >
              查询
            </el-button>
          </el-form-item>
        </el-form>
      </vab-query-form-right-panel>
    </vab-query-form>
    <el-table
      :key="Math.random()"
      ref="tables"
      v-loading="listLoading"
      border
      :data="list"
      :default-expand-all="false"
      fit
      :height="height"
      lazy
      :load="loadChild"
      row-key="brandNo"
      :tree-props="{
        children: 'lstChildren',
        hasChildren: 'hasChildren',
      }"
    >
      <el-table-column
        label="品牌名称"
        prop="brandName"
        show-overflow-tooltip
      />
      <el-table-column label="品牌编码" prop="brandNo" show-overflow-tooltip />
      <el-table-column label="描述" prop="desr" show-overflow-tooltip />
      <el-table-column label="排序" prop="sort" show-overflow-tooltip />
      <el-table-column
        label="创建人名称"
        prop="createName"
        show-overflow-tooltip
      />
      <el-table-column label="操作">
        <template #default="{ row }">
          <el-button
            circle
            icon="el-icon-plus"
            size="mini"
            type="primary"
            @click="handleChildrenAdd(row)"
          />

          <el-button
            circle
            icon="el-icon-edit"
            size="mini"
            type="success"
            @click="handleEdit(row)"
          />
          <el-button
            circle
            icon="el-icon-delete"
            size="mini"
            type="danger"
            @click="handleDelete(row)"
          />
        </template>
      </el-table-column>
    </el-table>
    <el-pagination
      :background="background"
      :current-page="queryForm.pageModel.pageIndex"
      :layout="layout"
      :page-size="queryForm.pageModel.pageSize"
      :total="total"
      @current-change="handleCurrentChange"
      @size-change="handleSizeChange"
    />
    <brand-add-edit
      ref="edit"
      @fetch-data="fetchData"
      @fetch-edit-data="fetchEditData"
    />
  </div>
</template>
<script>
  import {
    get_brands_page,
    get_brands_all,
    brand_delete,
  } from '@/api/infoBrand'
  import BrandAddEdit from './components/brandAddEdit.vue'
  export default {
    name: 'Brand',
    components: { BrandAddEdit },
    data() {
      return {
        total: 0,
        layout: 'total, sizes, prev, pager, next, jumper',
        background: true,
        queryForm: {
          brandNo: '',
          brandName: '',
          parentNo: '',
          isDelete: false,
          pageModel: {
            pageIndex: 1,
            pageSize: 10,
            totalCount: 0,
          },
        },
        list: [],
        maps: new Map(),
        listLoading: true,
        currParentNo: '', //定义父级编码
      }
    },
    computed: {
      height() {
        return this.$baseTableHeight(1) + 30
      },
    },
    created() {
      this.fetchData()
    },
    mounted() {},
    methods: {
      //加载模块的数据
      async fetchData() {
        this.listLoading = true
        const { results, pageModel } = await get_brands_page(this.queryForm)
        this.list = results
        this.total = pageModel.totalCount
        setTimeout(() => {
          this.listLoading = false
        }, 500)
      },
      //懒加载
      async loadChild(tree, treeNode, resolve) {
        let _this = this
        const pid = tree.brandNo //取出当前的编码
        _this.maps.set(pid, { tree, treeNode, resolve }) //将当前选中节点数据存储到maps中
        get_brands_all({
          parentNo: pid,
          brandNo: '',
          brandName: '',
        }).then((res) => {
          if (res.results.length) {
            resolve(res.results)
          } else {
            resolve([])
          }
        })
      },
      fetchEditData(row) {
        let _this = this
        const { parentNo } = row
        if (_this.currParentNo) {
          //懒加载刷新当前菜单
          if (parentNo && _this.maps.get(parentNo)) {
            const { tree, treeNode, resolve } = _this.maps.get(parentNo)
            _this.loadChild(tree, treeNode, resolve)
          }
          //懒加载刷新父级
          if (_this.currParentNo && _this.maps.get(_this.currParentNo)) {
            const { tree, treeNode, resolve } = _this.maps.get(
              _this.currParentNo
            )
            _this.loadChild(tree, treeNode, resolve)
          }
        } else {
          _this.fetchData()
        }
      },
      handleDelete(row) {
        let _this = this
        _this.currParentNo = '' //清除父节点得历史数据
        _this.$baseConfirm('你确定要删除当前项吗?', null, async () => {
          const { msg, hasErr } = await brand_delete({
            brandNo: row.brandNo,
            isDelete: true,
          })
          _this.$baseMessage(msg, 'success')
          //重新获取所有菜单,更新vuex中得所有类目得最新数据
          _this.$store.dispatch(
            'infobrand/updateBrandList',
            _this.$refs['edit'].brandForm
          )
          const { parentNo } = row //取出当前删除行的parentNo (父编码)
          //判断是否是一级删除
          if (parentNo) {
            const { tree, treeNode, resolve } = _this.maps.get(parentNo) //根据parentNo (父编码)取出对应的节点数据
            //将对应节点下的数据清空,从而实现数据的重新加载
            this.$set(
              _this.$refs.tables.store.states.lazyTreeNodeMap,
              parentNo,
              []
            )
            _this.currParentNo = tree.parentNo //获取当前父级编码进行重新加载节点
            _this.fetchEditData(tree)
          } else {
            //重新加载数据
            _this.fetchData()
          }
        })
      },
      handleAdd() {
        //最外层添加
        this.$refs['edit'].showEdit()
      },
      handleEdit(row) {
        this.$refs['edit'].showEdit(row)
      },
      handleChildrenAdd(row) {
        //添加子菜单
        this.$refs['edit'].showEdit(row, 'childrenAdd')
      },
      handleQuery() {
        this.queryForm.pageModel.pageIndex = 1
        this.fetchData()
      },
      handleSizeChange(val) {
        this.queryForm.pageModel.pageSize = val
        this.fetchData()
      },
      handleCurrentChange(val) {
        this.queryForm.pageModel.pageIndex = val
        this.fetchData()
      },
    },
  }
</script>

 brandAddEdit.vue

<template>
  <el-drawer
    :before-close="close"
    direction="rtl"
    :title="title"
    :visible.sync="dialogFormVisible"
  >
    <el-form
      ref="form"
      label-width="100px"
      :model="form"
      :rules="rules"
      style="padding: 20px"
    >
      <el-form-item label="父菜单" prop="brandNo">
        <el-cascader
          v-model.trim="form.brandNo"
          clearable
          :disabled="disabled"
          :options="brandList"
          placeholder="根目录"
          :props="{
            checkStrictly: true,
            children: 'lstChildren',
            value: 'brandNo',
            label: 'brandName',
          }"
          style="width: 100%"
        />
      </el-form-item>
      <el-form-item label="品牌名称" prop="brandName">
        <el-input
          v-model.trim="form.brandName"
          autocomplete="off"
          placeholder="输入品牌名称"
        />
      </el-form-item>
      <el-form-item label="描述" prop="desr">
        <el-input
          v-model.trim="form.desr"
          autocomplete="off"
          placeholder="输入描述"
          type="textarea"
        />
      </el-form-item>
      <el-form-item label="排序" prop="sort">
        <el-input
          v-model.trim="form.sort"
          autocomplete="off"
          placeholder="输入排序"
        />
      </el-form-item>
      <el-form-item>
        <el-button @click="close">取 消</el-button>
        <el-button type="primary" @click="save">确 定</el-button>
      </el-form-item>
    </el-form>
  </el-drawer>
</template>
<script>
  import { brand_save_or_update } from '@/api/infoBrand'
  import { mapGetters } from 'vuex'
  export default {
    name: 'BrandAddEdit',
    data() {
      return {
        form: {
          brandNo: '',
          brandName: '',
          sort: '',
          parentNo: '',
          desr: '',
          isDelete: false,
        },
        rules: {
          brandName: [
            { required: true, trigger: 'blur', message: '请输入品牌名称' },
          ],
        },
        title: '',
        pname: '根目录',
        dialogFormVisible: false,
        disabled: false,
        brandForm: {
          brandNo: '',
          brandName: '',
          parentNo: '',
          isDelete: false,
        },
      }
    },
    computed: {
      ...mapGetters({ brandList: 'infobrand/brandList' }),
    },
    created() {},
    mounted() {},
    methods: {
      showEdit(row, type) {
        this.disabled = false
        this.dialogFormVisible = true
        if (!row) {
          this.title = '当前全局添加'
        } else if (type == 'childrenAdd') {
          this.title = '添加子菜单'
          this.disabled = true //添加当前子菜单的时候不能选择其他类目
          this.form.brandNo = row.brandNo //回显
          this.form.parentNo = row.brandNo //一级添加子菜单的时候需要把当前编码作为添加时的父编码
          if (!row.parentNo) {
            //一级菜单添加
            this.$parent.currParentNo = row.parentNo
          } else {
            //当前节点添加 (如果当前父节点编码没有数据,就取当前节点编码为父级)
            this.$parent.currParentNo = row.parentNo || row.brandNo
          }
        } else {
          this.title = '编辑'
          this.disabled = true //编辑当前子菜单的时候不能选择其他类目
          this.form = Object.assign({}, row)
        }
      },
      close() {
        this.$refs['form'].resetFields()
        this.form = this.$options.data().form
        this.dialogFormVisible = false
        this.$emit('fetch-data')
      },
      save() {
        let _this = this
        _this.$refs['form'].validate(async (valid) => {
          if (valid) {
            const { parentNo } = _this.form
            if (_this.title == '编辑') {
              _this.$parent.currParentNo = _this.form.parentNo
              _this.getFormCommit(_this.form)
            } else {
              if (!parentNo) {
                //最外层添加
                _this.getFormCommit(_this.form)
              } else {
                //当前节点添加
                _this.form.brandNo = '' //在添加子菜单的时候需要把当前编码清空,因为添加编码是自动生成的,但是在回显的时候还是需要加上,添加就清空
                _this.getFormCommit(_this.form)
              }
            }
          } else {
            return false
          }
        })
      },
      //调用更新接口
      async getFormCommit(formdata) {
        let _this = this
        //添加和修改
        const { msg } = await brand_save_or_update(formdata)
        if (!formdata.parentNo) {
          //刷新一级菜单
          _this.$emit('fetch-data')
        } else {
          //添加成功后执行懒加载获取当前下得子菜单
          _this.$emit('fetch-edit-data', formdata)
        }
        //重新获取所有菜单,更新vuex中得所有类目得最新数据
        _this.$store.dispatch('infobrand/updateBrandList', _this.brandForm)
        //重置form表单
        _this.$refs['form'].resetFields()
        _this.form = _this.$options.data().form
        _this.dialogFormVisible = false
        _this.$baseMessage(msg, 'success')
      },
    },
  }
</script>

;