树形结构数据的增删改

树形结构的组件:

<template>
	<span class="tree-expand">
		<span class="tree-label" v-show="DATA.isEdit">
			<el-input class="edit" size="mini" autofocus
			v-model="DATA.name"
			:ref="'treeInput'+DATA.id"
			@click.stop.native="nodeEditFocus"
			@blur.stop="nodeEditPass(STORE,DATA,NODE)"
			@keyup.enter.stop.native="nodeEditPass(STORE,DATA,NODE)"></el-input>
		</span>
		<span v-show="!DATA.isEdit" 
		:class="[DATA.id > maxexpandId ? 'tree-new tree-label' : 'tree-label']">
			<span>{{DATA.name}}</span>
		</span>
		<span class="tree-btn" v-show="!DATA.isEdit">
			<i class="el-icon-plus" @click.stop="nodeAdd(STORE,DATA,NODE)"></i>
			<i class="el-icon-edit" @click.stop="nodeEdit(STORE,DATA,NODE)"></i>
			<i class="el-icon-delete" @click.stop="nodeDel(STORE,DATA,NODE)"></i>
		</span>
	</span>
</template>

<script>
	export default{
	  name: 'nx-tree-render',
	  props: ['NODE', 'DATA', 'STORE', 'maxexpandId'],
	  methods: {
	    nodeAdd(s, d, n) { // 新增
	      this.$emit('nodeAdd', s, d, n)
	    },
	    nodeEdit(s, d, n) { // 编辑
	      d.isEdit = true
	      this.$nextTick(() => {
	        this.$refs['treeInput' + d.id].$refs.input.focus()
	      })
	      this.$emit('nodeEdit', s, d, n)
	    },
	    nodeDel(s, d, n) { // 删除
	      this.$emit('nodeDel', s, d, n)
	    },
	    // 编辑完成
	    nodeEditPass(s, d, n) { // 编辑完成
	      console.log('编辑完成', d)
	      this.$emit('finishEdit', s, d, n)
	      d.isEdit = false
	    },
	    nodeEditFocus() {
	      // 阻止点击节点的事件冒泡
	    }
	  }
	}
</script>

<style>
	.tree-expand{
		overflow:hidden;
	}
	.tree-expand .tree-label.tree-new{
		font-weight:600;
	}
	.tree-expand .tree-label{
		font-size:0.9em;
	}
	.tree-expand .tree-label .edit{
		width:80%;
	}
	.tree-expand .tree-btn{
		display:none;
		float:right;
		margin-right:20px;
	}
	.tree-expand .tree-btn i{
		color:#8492a6;
		font-size:0.9em;
		margin-right:3px;
	}
</style>

组件的应用:

<template>
  <div class="expand">
     <p class="warn-content">
      <a href="https://xiaoniezi.github.io/2017-10-16/vue-ElementUI-tree-expand/" target="_blank">Tree组件参考 tree
      </a>
    </p>
    <div>
        <el-button @click="handleAddTop">添加顶级节点</el-button>
        <el-tree ref="expandMenuList" class="expand-tree"
        v-if="isLoadingTree"
        :data="setTree"
        node-key="id"
        highlight-current
        :props="defaultProps"
        :expand-on-click-node="false"
        :render-content="renderContent"
        
        @node-click="handleNodeClick"></el-tree>
      </div>
  </div>
</template>
<script>
import TreeRender from '@/components/nx-tree'
import api from '@/api/treeApi'

export default{
  name: 'tree',
  data() {
    return {
      maxexpandId: api.maxexpandId, // 新增节点开始id
      non_maxexpandId: api.maxexpandId, // 新增节点开始id(不更改)
      isLoadingTree: false, // 是否加载节点树
      setTree: api.treelist, // 节点树数据
      defaultProps: {
        children: 'children',
        label: 'name'
      },
      defaultExpandKeys: [] // 默认展开节点列表
    }
  },
  mounted() {
    console.log(api)
    this.initExpand()
  },
  methods: {
    initExpand() {
      this.setTree.map((a) => {
        this.defaultExpandKeys.push(a.id)
      })
      this.isLoadingTree = true
    },
    handleNodeClick(d, n, s) { // 点击节点
      // console.log(d,n)
      d.isEdit = false// 放弃编辑状态
    },
    renderContent(h, { node, data, store }) { // 加载节点
      const that = this
      return h(TreeRender, {
        props: {
          DATA: data,
          NODE: node,
          STORE: store,
          maxexpandId: that.non_maxexpandId
        },
        on: {
          nodeAdd: (s, d, n) => that.handleAdd(s, d, n),
          nodeEdit: (s, d, n) => that.handleEdit(s, d, n),
          nodeDel: (s, d, n) => that.handleDelete(s, d, n)
          finishEdit: (s, d, n) => that.handleFinishEdit(s, d, n) // 编辑完成状态
        }
      })
    },
    handleAddTop() {
      this.setTree.push({
        id: ++this.maxexpandId,
        name: '新增节点',
        pid: '',
        isEdit: false,
        children: []
      })
    },
    handleAdd(s, d, n) { // 增加节点
      console.log(s, d, n)
      if (n.level >= 6) {
        this.$message.error('最多只支持五级!')
        return false
      }
      // 添加数据
      d.children.push({
        id: ++this.maxexpandId,
        name: '新增节点',
        pid: d.id,
        isEdit: false,
        children: []
      })
      // 展开节点
      if (!n.expanded) {
        n.expanded = true
      }
    },
    handleEdit(s, d, n) { // 编辑节点
      console.log(s, d, n)
    },
    // 此处编辑完成(点击页面任意处)
    handleFinishEdit() {
      console.log('触发了编辑完成')
    },
    handleDelete(s, d, n) { // 删除节点
      console.log(s, d, n)
      const that = this
      // 有子级不删除
      if (d.children && d.children.length !== 0) {
        this.$message.error('此节点有子级,不可删除!')
        return false
      } else {
        // 新增节点直接删除,否则要询问是否删除
        const delNode = () => {
          const list = n.parent.data.children || n.parent.data // 节点同级数据
          let _index = 99999// 要删除的index
          /* if(!n.parent.data.children){//删除顶级节点,无children
              list = n.parent.data
            }*/
          list.map((c, i) => {
            if (d.id === c.id) {
              _index = i
            }
          })
          const k = list.splice(_index, 1)
          console.log(_index, k)
          this.$message.success('删除成功!')
        }
        const isDel = () => {
          that.$confirm('是否删除此节点?', '提示', {
            confirmButtonText: '确认',
            cancelButtonText: '取消',
            type: 'warning'
          }).then(() => {
            delNode()
          }).catch(() => {
            return false
          })
        }
        // 判断是否新增
        d.id > this.non_maxexpandId ? delNode() : isDel()
      }
    }
  }

}
</script>

<style>
.expand{
  width:100%;
  height:100%;
  overflow:hidden;
}
.expand>div{
  height:85%;
  padding-top:20px;
  width:50%;
  margin:20px auto;
  max-width:400px;
  overflow-y:auto;
}
.expand>div::-webkit-scrollbar-track{
  box-shadow: inset 0 0 6px rgba(0,0,0,.3);
  border-radius:5px;
}
.expand>div::-webkit-scrollbar-thumb{
  background-color:rgba(50, 65, 87, 0.5);
  outline:1px solid slategrey;
  border-radius:5px;
}
.expand>div::-webkit-scrollbar{
  width:10px;
}
.expand-tree{
  border:none;
  margin-top:10px;
}
.expand-tree .el-tree-node.is-current,
.expand-tree .el-tree-node:hover{
  overflow:hidden;
}
.expand-tree .is-current>.el-tree-node__content .tree-btn,
.expand-tree .el-tree-node__content:hover .tree-btn{
  display:inline-block;
}
.expand-tree .is-current>.el-tree-node__content .tree-label{
  font-weight:600;
  white-space:normal;
}
</style>

注意:树形节点部分的样式一定不能加scoped,否则增删改的图标就会无法显示

API部分的数据:

export default {
  maxexpandId: 95,
  treelist: [{
    id: 1,
    name: '北京市',
    ProSort: 1,
    remark: '直辖市',
    pid: '',
    isEdit: false,
    children: [{
      id: 35,
      name: '朝阳区',
      pid: 1,
      remark: '',
      isEdit: false,
      children: []
    }, {
      id: 36,
      name: '海淀区',
      pid: 1,
      remark: '',
      isEdit: false,
      children: []
    }, {
      id: 37,
      name: '房山区',
      pid: 1,
      remark: '',
      isEdit: false,
      children: []
    }, {
      id: 38,
      name: '丰台区',
      pid: 1,
      remark: '',
      isEdit: false,
      children: []
    }, {
      id: 39,
      name: '昌平区',
      pid: 1,
      remark: '',
      isEdit: false,
      children: []
    }, {
      id: 40,
      name: '大兴区',
      pid: 1,
      remark: '',
      isEdit: false,
      children: []
    }]
  }, {
    id: 2,
    name: '天津市',
    ProSort: 2,
    remark: '直辖市',
    pid: '',
    isEdit: false,
    children: [{
      id: 41,
      name: '北辰区',
      pid: 2,
      remark: '',
      isEdit: false,
      children: []
    }, {
      id: 42,
      name: '河北区',
      pid: 2,
      remark: '',
      isEdit: false,
      children: []
    }, {
      id: 43,
      name: '西青区',
      pid: 2,
      remark: '',
      isEdit: false,
      children: []
    }, {
      id: 44,
      name: '东丽区',
      pid: 2,
      remark: '',
      isEdit: false,
      children: []
    }]
  }, {
    id: 3,
    name: '河北省',
    ProSort: 5,
    remark: '省份',
    pid: '',
    isEdit: false,
    children: [{
      id: 45,
      name: '衡水市',
      pid: 3,
      remark: '',
      isEdit: false,
      children: []
    }, {
      id: 46,
      name: '张家口市',
      pid: 3,
      remark: '',
      isEdit: false,
      children: []
    }, {
      id: 47,
      name: '秦皇岛市',
      pid: 3,
      remark: '',
      isEdit: false,
      children: []
    }, {
      id: 48,
      name: '承德市',
      pid: 3,
      remark: '',
      isEdit: false,
      children: []
    }, {
      id: 49,
      name: '邯郸市',
      pid: 3,
      remark: '',
      isEdit: false,
      children: []
    }]
  }, {
    id: 4,
    name: '山西省',
    ProSort: 6,
    remark: '省份',
    pid: '',
    isEdit: false,
    children: [{
      id: 50,
      name: '大同市',
      pid: 4,
      remark: '',
      isEdit: false,
      children: []
    }]
  }, {
    id: 5,
    name: '内蒙古自治区',
    ProSort: 32,
    remark: '自治区',
    pid: '',
    isEdit: false,
    children: [{
      id: 51,
      name: '包头市',
      pid: 5,
      remark: '',
      isEdit: false,
      children: []
    }]
  }, {
    id: 6,
    name: '辽宁省',
    ProSort: 8,
    remark: '省份',
    pid: '',
    isEdit: false,
    children: [{
      id: 52,
      name: '大连市',
      pid: 6,
      remark: '',
      isEdit: false,
      children: []
    }, {
      id: 53,
      name: '太原市',
      pid: 6,
      remark: '',
      isEdit: false,
      children: []
    }]
  }, {
    id: 20,
    name: '海南省',
    ProSort: 24,
    remark: '省份',
    pid: '',
    isEdit: false,
    children: [{
      id: 68,
      name: '海口市',
      pid: 20,
      remark: '',
      isEdit: false,
      children: []
    }]
  }, {
    id: 21,
    name: '广西壮族自治区',
    ProSort: 28,
    remark: '自治区',
    pid: '',
    isEdit: false,
    children: [{
      id: 69,
      name: '玉林市',
      pid: 21,
      remark: '',
      isEdit: false,
      children: []
    }, {
      id: 86,
      name: '贺州市',
      pid: 21,
      remark: '',
      isEdit: false,
      children: []
    }]
  }, {
    id: 22,
    name: '甘肃省',
    ProSort: 21,
    remark: '省份',
    pid: '',
    isEdit: false,
    children: [{
      id: 70,
      name: '兰州市',
      pid: 22,
      remark: '',
      isEdit: false,
      children: []
    }]
  }, {
    id: 23,
    name: '陕西省',
    ProSort: 27,
    remark: '省份',
    pid: '',
    isEdit: false,
    children: [{
      id: 71,
      name: '咸阳市',
      pid: 23,
      remark: '',
      isEdit: false,
      children: []
    }, {
      id: 87,
      name: '安康市',
      pid: 23,
      remark: '',
      isEdit: false,
      children: []
    }]
  }, {
    id: 24,
    name: '新疆维吾尔自治区',
    ProSort: 31,
    remark: '自治区',
    pid: '',
    isEdit: false,
    children: [{
      id: 72,
      name: '乌鲁木齐市',
      pid: 24,
      remark: '',
      isEdit: false,
      children: []
    }, {
      id: 88,
      name: '和田地区',
      pid: 24,
      remark: '',
      isEdit: false,
      children: []
    }, {
      id: 89,
      name: '阿勒泰州',
      pid: 24,
      remark: '',
      isEdit: false,
      children: []
    }]
  }, {
    id: 25,
    name: '青海省',
    ProSort: 26,
    remark: '省份',
    pid: '',
    isEdit: false,
    children: [{
      id: 73,
      name: '黄南藏族自治州',
      pid: 25,
      remark: '',
      isEdit: false,
      children: []
    }]
  }, {
    id: 26,
    name: '宁夏回族自治区',
    ProSort: 30,
    remark: '自治区',
    pid: '',
    isEdit: false,
    children: [{
      id: 74,
      name: '银川市',
      pid: 26,
      remark: '',
      isEdit: false,
      children: []
    }]
  }]
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值