效果图:

项目代码结构:

代码示例

index.vue

<template>
  <div class="white-body-view">
    <el-button type="primary" @click="addNewRecord()">新增</el-button>
    <custom-tree ref="customTree" :tree-data="treeData" :tree-expand-all="treeExpandAll" :tree-node-key="treeNodeKey" @addItem="addTreeItem" @deleteItem="deleteTreeItem" @editItem="editTreeItem" />
    <!-- 地点弹窗 -->
    <place-dialog ref="placeDialog" @addData="addData" @editData="editData" />
  </div>
</template>
<script>
import CustomTree from './components/Tree'
import PlaceDialog from './components/PlaceDialog'
export default {
  components: {
    CustomTree,
    PlaceDialog
  },

  data() {
    return {
      treeData: [],
      treeExpandAll: true,
      treeNodeKey: 'id'
    }
  },

  created() {
    this.initTreeData()
  },

  methods: {
    // 初始化列表
    initTreeData() {
      this.treeData = [
        {
          children: [
            {
              children: [],
              name: '1楼',
              desc: '这是教学楼1楼',
              parentId: '1',
              id: '2'
            },
            {
              children: [],
              name: '2楼',
              desc: '这是教学楼1楼',
              parentId: '1',
              id: '3'
            },
            {
              children: [],
              name: '3楼',
              desc: '这是教学楼3楼',
              parentId: '1',
              id: '4'
            }
          ],
          name: '教学楼',
          parentId: '',
          id: '1'
        },
        {
          children: [
            {
              children: [],
              name: '办公1楼',
              desc: '这是办公楼',
              parentId: '5',
              id: '6'
            }
          ],
          name: '办公楼',
          parentId: '',
          id: '5'
        }
      ]
    },

    // 添加新记录
    addNewRecord() {
      this.$refs.placeDialog.openDialog(false)
    },

    // 新增表单数据
    addData(data) {
      // 新增树节点
      this.$refs.customTree.treeAddItem(data)
    },

    // 修改表单数据
    editData(data) {
      // 修改树节点
      this.$refs.customTree.treeEditItem(data)
    },

    // 增加树节点
    addTreeItem(data) {
      // 打开地点弹窗,设置默认父级节点
      this.$refs.placeDialog.openDialog(false, data.id)
    },

    // 删除树节点
    deleteTreeItem(data) {
      this.$confirm('确定删除吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        // 删除树节点
        this.$refs.customTree.treeDeleteItem(data)
        // 提示
        this.$message({
          type: 'success',
          message: '删除成功!'
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        })
      })
    },

    // 修改树节点
    editTreeItem(data) {
      // 打开地点编辑弹窗
      this.$refs.placeDialog.openDialog(true, data.parentId, data)
    }

  }
}
</script>

 Tree.vue

<template>
  <div class="white-body-view">
    <el-tree
      id="my-tree"
      ref="tree"
      class="tree-view structure-tree"
      :data="treeData"
      highlight-current
      :default-expand-all="treeExpandAll"
      :props="defaultProps"
      check-strictly
      :node-key="treeNodeKey"
      :auto-expand-parent="false"
      :expand-on-click-node="false"
    >
      <span slot-scope="{ node, data }" class="custom-tree-node">
        <span class="tooltip">
          <span class="add-f-s-14">{{ data.name }}</span>
        </span>
        <div v-if="node.isCurrent == true" class="operation-view">
          <i
            class="small-operation-btn el-icon-plus"
            @click.stop="handleAdd(data)"
          />
          <i
            class="small-operation-btn el-icon-edit "
            @click.stop="handleEdit(data)"
          />
          <i
            class="small-operation-btn el-icon-delete"
            @click.stop="handleDelete(data)"
          />
        </div>
      </span>
    </el-tree>
  </div>
</template>

<script>
export default {
  props: {
    // 源数据
    treeData: {
      type: Array,
      default: function() {
        return []
      }
    },

    // 树节点是否默认展开
    treeExpandAll: {
      type: Boolean,
      default: true
    },

    // 树节点唯一标识
    treeNodeKey: {
      type: String,
      default: ''
    }
  },

  data() {
    return {
      defaultProps: {
        children: 'children',
        label: 'name'
      },
      selectItem: {}
    }
  },

  methods: {
    // 添加新增按钮
    handleAdd(data) {
      this.$emit('addItem', data)
    },

    // 点击删除按钮
    handleDelete(data) {
      this.$emit('deleteItem', data)
    },

    // 点击编辑按钮
    handleEdit(data) {
      this.selectItem = data
      this.$emit('editItem', JSON.parse(JSON.stringify(data)))
    },

    // ============== 组件内事件 结束=============

    // ============== 父组件回调事件 开始=============

    // 添加新记录,树形列表回显
    treeAddItem(data) {
      this.$refs.tree.append(data, data.parentId)
    },

    // 删除节点
    treeDeleteItem(val) {
      this.$refs.tree.remove(val)
    },

    // 修改记录,树形列表回显
    treeEditItem(val) {
      Object.assign(this.selectItem, val)
      this.selectItem = {}
    }

    // ============== 父组件回调事件 结束=============

  }
}
</script>
<style lang="scss">
.structure-tree {
  .el-scrollbar .el-scrollbar__wrap {
    overflow-x: hidden;
  }
  #my-tree .el-tree > .el-tree-node {
    min-width: 100%;
    display: inline-block;
  }
  .el-tree-node__content {
    margin-bottom: 10px;
  }
  .tooltip {
    margin-right: 5px;
    font-size: 13px;
    border-radius: 4px;
    box-sizing: border-box;
    white-space: nowrap;
    padding: 4px;
  }
  .operation-view {
    display: inline-block;
    padding: 0px 5px;
    margin-left: 5px;
    color: #777777;
  }
  .small-operation-btn{
    margin:0px 3px;
  }
}

</style>

PlaceDialog.vue

<template>
  <div>
    <el-dialog
      :title="title"
      :visible.sync="dialogVisible"
      width="50%"
    >
      <el-form ref="form" :model="form" :rules="rules" label-width="100px" class="demo-form">
        <el-form-item label="名称" prop="name">
          <el-input v-model="form.name" />
        </el-form-item>
        <el-form-item label="描述" prop="desc">
          <el-input v-model="form.desc" resize="none" type="textarea" />
        </el-form-item>
        <el-form-item>
          <el-button class="pull-right" type="primary" @click="submitForm()">确定</el-button>
        </el-form-item>
      </el-form>
    </el-dialog>
  </div>
</template>
<script>
export default {
  data() {
    return {
      dialogVisible: false,
      title: '',
      form: {
        name: '',
        desc: ''
      },
      rules: {
        name: [
          { required: true, message: '请输入名称', trigger: 'blur' }
        ],
        desc: [
          { required: false, message: '请输入描述', trigger: 'blur' }
        ]
      },
      isEdit: false,
      parentId: '',
      data: {}
    }
  },
  methods: {
    /**
     * @description 打开弹窗
     * @param { Boolean } isEdit 是否是修改状态 true 修改 / false 新增
     * @param { String } parentId 父级id,新增时默认选中父级时使用
     * @param { Object } data 表单数据,编辑时使用
     */
    openDialog(isEdit, parentId, data) {
      this.isEdit = isEdit
      this.parentId = parentId
      this.data = data
      this.title = isEdit ? '编辑' : '新增'
      this.initFormData()
      this.dialogVisible = true
      if (this.isEdit) {
        this.$nextTick(() => {
          this.form = data
        })
      }
    },

    // 初始化表单数据
    initFormData() {
      this.form = {
        name: '',
        desc: ''
      }
    },

    // 提交表单
    submitForm() {
      this.$refs.form.validate((valid) => {
        if (valid) {
          const formData = JSON.parse(JSON.stringify(this.form))
          if (this.isEdit) {
            this.$emit('editData', formData)
          } else {
            // 设置新创建节点的父级编号
            formData.parentId = this.parentId ? this.parentId : ''
            // 随机生成id(仅为前端模拟使用,正常场景应为后台生成)
            formData.id = Math.random()
            this.$emit('addData', formData)
          }
          this.closeDialog()
        }
      })
    },

    // 关闭当前弹窗
    closeDialog() {
      this.$refs.form.resetFields()
      this.dialogVisible = false
    }
  }
}
</script>
<style scoped>
.pull-right {
  float: right
}
</style>

 

Logo

前往低代码交流专区

更多推荐