vue项目中使用ztree实现增删改查

3,471 阅读1分钟

zTree 是一个依靠 jQuery 实现的多功能 “树插件”。优异的性能、灵活的配置、多种功能的组合是 zTree 最大优点。专门适合项目开发,尤其是 树状菜单、树状数据的Web显示、权限管理等等。

如何在vue项目使用ztree

  1. 下载ztree ztree官网下载ztree插件,并将对应的 js 和 css 文件放到vue项目中。
  2. 引入 在vue项目中的main.js入口文件引入
import $ from 'jquery';
import '@/assets/js/ztree/zTreeStyle/zTreeStyle.css';
import './assets/js/ztree/jquery.ztree.core.js';
import './assets/js/ztree/jquery.ztree.excheck.js';
import './assets/js/ztree/jquery.ztree.exedit.js';
  1. 配置 在vue项目的 vue.config.js中进行配置。
module.exports = {
  configureWebpack: {
    plugins: [
      new webpack.ProvidePlugin({
        $: 'jquery',
        jQuery: 'jquery',
        'windows.jQuery': 'jquery'
      })
    ]
  },
}
  1. 使用 完成以上几步就可以使用ztree了。

ztree的使用案例

需求

  1. 使用阿里图标自定义增、删、改按钮。
  2. 点击节点的文字查看对应节点的信息,并在右侧显示对应的节点信息。
  3. 点击+图标,右侧显示对应的输入表单。
  4. 点击删除图标,弹出对话框确认是否删除。点击确定删除对应的节点。

具体代码

封装ztree组件

template部分

<template>
  <div class='objZtree'>
    <div class='split-body'>
      <div class='split-content'>
        <ul id='objTree' class='ztree' style='min-height: 500px'></ul>
      </div>
    </div>
  </div>
</template>

script部分

<script>
// 引入阿里图标
import './iconfont.css';

export default {
  data() {
    return {
      setting: {
        view: {
          showIcon: false,
          addHoverDom: this.addHoverDom,
          removeHoverDom: this.removeHoverDom
        },
        edit: {
          enable: true,
          showRemoveBtn: false,
          showRenameBtn: false
        },
        callback: {
          // beforeRemove: this.beforeRemove
          beforeAsync: this.beforeAsync,
          onAsyncSuccess: this.zTreeOnAsyncSuccess,
          onClick: this.zTreeOnClick
        },
        data: {
          key: {
            name: 'DisplayName'
          }
        },
        async: {
          enable: true,
          url: function(treeId, treeNode) {
            // console.log('异步请求', treeId, treeNode); // 得到当前节点的信息
            return './index.vue';
          },
          type: 'GET'
        }
      },
      initalNode: {
        DisplayName: '一级分类',
        BrowseName: 'ModelLib',
        iconSkin: 'iconObjectType',
        nodeClass: 'Object Type',
        uri: '/system/5013',
        isParent: true,
        nocheck: true
      },
      // 当前节点的treeId
      currentTreeId: ''
    };
  },
  methods: {
    // 初始化 ztree
    loadObjTree() {
      $.fn.zTree.init($('#objTree'), this.setting, this.initalNode);
    },
    
    // 点击一级分类前的展开标志触发异步请求,模拟异步请求添加子节点
    beforeAsync(treeId, treeNode) {
      console.log('异步请求发送之前触发', treeId, treeNode);
    },
    zTreeOnAsyncSuccess(event, treeId, treeNode, msg) {
        console.log('异步请求成功回调函数执行', event, treeId, treeNode, msg);
        let zTree = $.fn.zTree.getZTreeObj(treeId);
        // let selectedNodes = zTree.getSelectedNodes();
        let item = {
          DisplayName: '基础类模型',
          bowserPath: '/aa/bb'
        };
        item.nodes = [
          {
            forward: true,
            id: 11111,
            includeSubtype: false
          }
        ];
        zTree.addNodes(treeNode, item);
    },
    
    zTreeOnClick(event, treeId, treeNode) { // 点击某一个节点时触发的函数
      console.log('点击节点文字查看', event, treeId, treeNode);
      let zTree = $.fn.zTree.getZTreeObj(treeId);
      let selectedNodes = zTree.getSelectedNodes(true); // 得到点击的节点(选中的节点)
      this.$emit('changeCheckBoxVisible', selectedNodes);  // 调用父组件定义的方法,并传递该节点的信息
    },
    
    // 鼠标移入节点时触发,
    addHoverDom(treeId, treeNode) {
      this.currentTreeId = treeId;  // 将当前节点保存到实例中,以便该组件使用
      var aObj = $('#' + treeNode.tId + '_span');
       if ($('#diyBtnGroup').length>0) return;
        // 查看是否存在自定义的按钮组,因为 addHoverDom 会触发多次
        // 使用阿里图标自定义增删改按钮
        var editStr = `<span id='diyBtnGroup'>
                        <span id='diyBtn_space_${treeNode.id}' οnfοcus='this.blur();'> </span>
                        <i class="iconfont icon-tianjia" style="color: #1296db;" id='diyBtn_${treeNode.id}_add' οnfοcus='this.blur();'></i>
                        <i class="iconfont icon-bianji" style="color: #1296db;" id='diyBtn_${treeNode.id}_modify' οnfοcus='this.blur();'></i>
                        <i class="iconfont icon-cangpeitubiao_shanchu" style="color: #1296db;" id='diyBtn_${treeNode.id}_delete' οnfοcus='this.blur();'></i>
                    </span>`;
        aObj.append(editStr); // 在每个节点后添加自定义按钮组
        // 获取到对应按钮的DOM元素
        var btnDelete = $('#diyBtn_'+treeNode.id + '_delete');
        var btnAdd = $('#diyBtn_'+treeNode.id + '_add');
        var btnModify = $('#diyBtn_'+treeNode.id + '_modify');
        
        // 为每个按钮绑定不同的点击事件
        if (btnDelete) {
        btnDelete.bind('click', (e) => {
          e.stopPropagation();
          // 触发父组件的方法,使删除对话框显示
          this.$emit('changeDelModelFlag');
        });
        };
        if (btnAdd) {
          btnAdd.bind('click', (e) => {
          e.stopPropagation();
          this.$emit('changeAddFormFlag');  // 点击删除按钮,调用父组件定义的方法,弹出删除确认框
        });
        }
        if (btnModify) {
        btnModify.bind('click', function(e) {
          e.stopPropagation();
          // 更新节点的操作,具体逻辑与添加节点的逻辑类似,此处只是模拟更新操作
          var treeObj = $.fn.zTree.getZTreeObj(treeId);
          var nodes = treeObj.getSelectedNodes();
          nodes[0].name = '更新了节点';
          treeObj.updateNode(nodes[0]);
        });
}
    },
    
    // 删除之前调用的逻辑,ztree提供的删除节点的回调函数
    // beforeRemove(e) {
    //   console.log(e);
    //   alert('确定要删除吗');
    // },
    
    // 子组件定义删除节点的方法,通过在父组件的删除对话框中点击确定按钮,调用该方法删除对应的节点
    delNode() {
      var treeObj = $.fn.zTree.getZTreeObj(this.currentTreeId);
      var nodes = treeObj.getSelectedNodes();
      treeObj.removeNode(nodes[0]);
    },
    
    // 自组件自定义添加节点的方法,在父组件中添加表单的确认按钮点击后,调用该方法添加节点
    addNode(addInfo) {
      var treeObj = $.fn.zTree.getZTreeObj(this.currentTreeId);
      // console.log(treeId); // id='objTree'
      // console.log('treeObj', treeObj);  // 通过 treeId 获取被操作的ztree对象
      var nodes = treeObj.getSelectedNodes(); // 获取所有被选中的节点,返回一个数组
      // var parentNode = nodes[0].getParentNode(); // 获取某一个节点的父节点,若没有父节点返回null
      // console.log('父节点', parentNode);
      var newNode = { // 自定义新节点用于模拟添加节点操作,真实的节点内容,可以通过在父组件中调用该方法时,通过参数传递过来addInfo
        DisplayName: '模型库2号',
        BrowseName: 'ModelLib',
        iconSkin: 'iconObjectType'
      };
      // 第一个参数为添加节点的位置,在当前选中节点下添加新节点
      var add = treeObj.addNodes(nodes[0], newNode); 
      console.log('新增节点后的返回值', add); // 以数组的方式返回新增的节点
    },
    
    // 鼠标离开当前节点的逻辑,鼠标离开时,解除事件的绑定 
    removeHoverDom: (treeId, treeNode) => {
        // 为了方便删除整个 button 组,上面我用 #diyBtnGroup 这个包了起来,这里直接删除外层即可,不用挨个找了。
        $('#diyBtnGroup').unbind().remove();
    }
  },
  
  mounted() {
    // 当个组件挂载完毕时,调用初始化ztree的方法,初始化ztree
    this.loadObjTree();
  }
};
</script>

注解

为什么添加阻止冒泡?

自定义增删改按钮,并绑定事件后形成的代码结构为: 按照需求是:当点击基础类模型后右侧是显示查看节点内容的表格,点击+显示,添加表单的内容,由于存在事件冒泡机制,所以当点击+后,却显示的是查看节点内容的表格,所以要在增删改的事件中阻止事件冒泡。

父组件

template部分

<template>
  <div class="meta-data-classic">
    <Input v-model="cateName" search placeholder="Enter something..." style="width: 300px" />
    <div class="mainContainer">
      <div class="leftContianer">
      <!-- 调用ztree组件,同时把改变增删改显示的方法传递给ztree组件 -->
        <Ztree
        @changeDelModelFlag="changeDelModelFlag"
        @changeAddFormFlag="changeAddFormFlag"
        @changeCheckBoxVisible="changeCheckBoxVisible"
        ref="ZtreeRef"
        />
      </div>
      
      <div class="rightContainer">
      
        <!-- 添加分类的表单 -->
        <Form ref="formCustom" :model="addForm" :label-width="80" v-if="addFormVisible">
            <FormItem label="分类" prop="passwd">
                <Input type="password" v-model="addForm.category"></Input>
            </FormItem>
            <FormItem label="创建人" prop="passwdCheck">
                <Input type="password" v-model="addForm.founder"></Input>
            </FormItem>
            <FormItem label="所属部门" prop="age">
                <Input type="text" v-model="addForm.department" number></Input>
            </FormItem>
            <FormItem label="备注" prop="age">
                <Input type="text" v-model="addForm.remark" number></Input>
            </FormItem>
            <FormItem>
                <Button type="primary" @click="addSubmit('formCustom')">确定</Button>
                <Button @click="handleCancel('formCustom')" style="margin-left: 8px">取消</Button>
            </FormItem>
        </Form>
        
        <!-- 查看展示节点数据 -->
       <div class="checkInfo" v-if="checkBoxVisible">
         <Table :columns="checkColumns" :data="checkData" width="500"></Table>
         <Button type="primary" @click="checkBoxVisible = false">确定</Button>
         <Button type="primary" @click="checkBoxVisible = false">取消</Button>
       </div>
      </div>
    </div>
    
    <!-- 删除对应节点的确认对话框 -->
    <Modal
        v-model="delModelVisible"
        title="删除节点"
        @on-ok="onOk"
      >
        <p>你确定要删除该节点吗</p>
    </Modal>
  </div>
</template>

script部分

<script>
import Ztree from './bindPoints';
export default {
  name: 'meta-data-classic',
  components: {
    Ztree
  },
  data() {
    return {
      delModelVisible: false,
      addFormVisible: false,
      checkBoxVisible: false,
      cateName: '',
      addForm: {
        category: '',
        founder: '',
        department: '',
        remark: ''
      },
      checkColumns: [
          {
              title: '名称',
              key: 'title'
          },
          {
              title: '信息',
              key: 'info'
          }
      ],
      checkData: [
          {
              title: '分类',
              info: 'category'
          },
          {
              title: '创建人',
              info: 'founder'
          },
          {
              title: '所属部门',
              info: 'department'
          },
          {
              title: '备注',
              info: 'remark'
          }
      ]
    };
  },
  methods: {
    changeDelModelFlag() {
      this.delModelVisible = true;  // 显示删除对话框
    },
    onOk() {
      // 点击删除对话框的确认按钮,调用子组件的方法删除对应的节点
      this.$refs.ZtreeRef.delNode(); 
      this.checkBoxVisible = false;
      this.addFormVisible = false;
    },
    changeAddFormFlag() {
      this.checkBoxVisible = false;
      this.addFormVisible = true;
    },
    handleCancel() {
      this.addFormVisible = false;
    },
    changeCheckBoxVisible(nodeInfo) {
      console.log('对应节点的具体信息', nodeInfo);
      this.checkBoxVisible = true;
      this.addFormVisible = false;
    },
    addSubmit() {
      // 点击添加表单的确定按钮,调用子组件的添加节点的方法,添加节点,同时将addForm传递过去
      this.$refs.ZtreeRef.addNode(this.addForm);
    }
  }
};
</script>

style部分

<style scoped>
  .meta-data-classic .mainContainer{
    display: flex;
  }
  .meta-data-classic .mainContainer .leftContianer {
    flex: 3;
  }
  .meta-data-classic .mainContainer .rightContainer {
    flex: 4;
  }
  .meta-data-classic .mainContainer .rightContainer Form {
    width: 60%;
  }
  .rightContainer .checkInfo Button{
    margin-top: 10px;
  }
  .rightContainer .checkInfo Button:nth-of-type(1) {
    margin-left: 370px;
    margin-right: 20px;
  }
</style>