• bootstrap-treeview中勾选父节点全选子节点,以及勾选一个子节点自动勾选父节点


      做了一个树形菜单,想实现如下两个操作:1.勾选父节点全选子节点  2.勾选子节点自动勾选父节点。本以为实现起来应该很简单,但实际做的时候遇到了还是碰到很多问题,现在来记录一下。

      直接上代码:

    let clickFlag = 0; // clickFlag用来记录节点是被手动点击而使state变为cheked的,而不是因为级联选择导致节点被checked
    // 初始化树形菜单
    function initTreeView(model) {
       $('#treeview-checkable').treeview({
          data: getMenus(model),    // 加载的数据源
          showIcon: false,
          showCheckbox: true,       // 展示复选框
          levels: 2,
          onNodeChecked: function(event, node) {    //选中时触发
             checkNode(node);
          },
          onNodeUnchecked: function (event, node) {  //取消选中时触发
             unCheckNode(node);
          },
          onNodeClicked: function (event, node) { // click事件早于check事件
             if (node.nodes != undefined && !node.state.checked) {
                if (node.parentId == undefined) { // 顶层节点
                   clickFlag = 1;
                } else { // 中间节点
                   clickFlag = 2;
                }
             } else {
                clickFlag = 0;
             }
          },
       });
    };
    
    
    // 选择父菜单节点后,选中所有子菜单;当父菜单下所有子菜单被选中之后,自动勾选上父菜单节点
    function checkNode(data) {
       if(data.nodes != undefined && clickFlag != 0) {
          for(var i = 0; i < data.nodes.length; i++) {
             $('#treeview-checkable').treeview("checkNode", [data.nodes[i].nodeId, {slient: true}]);
          }
          if (clickFlag == 2) { // 点击中间节点,选中了节点下所有子节点后,改变标识,防止污染后续操作
             clickFlag = 0;
          }
       }
       if (data.parentId != undefined) {
          var parentNode = $('#treeview-checkable').treeview('getParent', data.nodeId);
          let checkCount = 0;
          for (x in parentNode.nodes) {
             if (parentNode.nodes[x].state.checked) {
                checkCount++;
             }
          }
          if(checkCount > 0) {
             // 选中当前节点的父节点
             $('#treeview-checkable').treeview("checkNode", [parentNode.nodeId, {slient: true}]);
          }
       }
    
    
    }
    // 取消选择父菜单节点后,自动取消菜单下全部人员
    function unCheckNode(data) {
       if(data.nodes != undefined) {
          var flag = false;
          for(var i = 0; i < data.nodes.length; i++) {
             if (data.nodes[i].state.checked) {
                flag = true;
                break;
             }
          }
          if(flag) {
             for(var i = 0; i < data.nodes.length; i++) {
                $('#treeview-checkable').treeview("uncheckNode", [data.nodes[i].nodeId, {slient: true}]);
             }
          }
       }
       if (data.parentId != undefined) {
          var parentNode = $('#treeview-checkable').treeview('getParent', data.nodeId);
          var checkCount = 0;
          for (x in parentNode.nodes) {
             if (parentNode.nodes[x].state.checked) {
                checkCount++;
             }
          }
          if(checkCount == 0) {
             $('#treeview-checkable').treeview("uncheckNode", [parentNode.nodeId, {slient: true}]);
          }
       }
    }
      其中clickFlag很重要,如果没有这个属性,会出现以下情况:点击了子节点后自动勾选了父节点,因为定义了父节点被选中后就全选子节点,所以这时父节点下所有子节点都会被选中。因此,我就想到需要用一个flag来标注节点是被人手动点击的,而不是因为级联操作被选中的,这样才能避免出现上面说的问题。
        节点的选中状态判断是通过onNodeChecked和onNodeUnchecked来判断的,还需要一个点击事件来记录节点是否被点击,bootstrap-treeview默认并没有提供这个事件,需要我们另外添加,添加方式如下:
    ;(function ($, window, document, undefined) {
         /*global jQuery, console*/
         'use strict';
         var pluginName = 'treeview';
         var _default = {};
         _default.settings = {
              injectStyle: true,
              levels: 2,
              expandIcon: 'glyphicon glyphicon-plus',
              collapseIcon: 'glyphicon glyphicon-minus',
              emptyIcon: 'glyphicon',
              nodeIcon: '',
              selectedIcon: '',
              checkedIcon: 'glyphicon glyphicon-check',
              uncheckedIcon: 'glyphicon glyphicon-unchecked',
              color: undefined, // '#000000',
              backColor: undefined, // '#FFFFFF',
              borderColor: undefined, // '#dddddd',
              onhoverColor: '#F5F5F5',
              selectedColor: '#FFFFFF',
              selectedBackColor: '#428bca',
              searchResultColor: '#D9534F',
              searchResultBackColor: undefined, //'#FFFFFF',
              enableLinks: false,
              highlightSelected: true,
              highlightSearchResults: true,
              showBorder: true,
              showIcon: true,
              showCheckbox: false,
              showTags: false,
              multiSelect: false,
              // Event handlers          onNodeChecked: undefined,
              onNodeCollapsed: undefined,
              onNodeDisabled: undefined,
              onNodeEnabled: undefined,
              onNodeExpanded: undefined,
              onNodeSelected: undefined,
              onNodeUnchecked: undefined,
              onNodeUnselected: undefined,
              onSearchComplete: undefined,
              onSearchCleared: undefined,
              
              /**
             * 给 bootstrap treeview 添加 点击事件 定义
             */
              onNodeClicked: undefined
         };
         Tree.prototype.unsubscribeEvents = function () {
              this.$element.off('click');
              this.$element.off('nodeChecked');
              this.$element.off('nodeCollapsed');
              this.$element.off('nodeDisabled');
              this.$element.off('nodeEnabled');
              this.$element.off('nodeExpanded');
              this.$element.off('nodeSelected');
              this.$element.off('nodeUnchecked');
              this.$element.off('nodeUnselected');
              this.$element.off('searchComplete');
              this.$element.off('searchCleared');
              
              /**
             * 给 bootstrap treeview 添加 点击事件 元素
             */
              this.$element.off('nodeClicked');
         };
        Tree.prototype.subscribeEvents = function () {
              this.unsubscribeEvents();
              this.$element.on('click', $.proxy(this.clickHandler, this));
              if (typeof (this.options.onNodeChecked) === 'function') {
                  this.$element.on('nodeChecked', this.options.onNodeChecked);
              }
              if (typeof (this.options.onNodeCollapsed) === 'function') {
                  this.$element.on('nodeCollapsed', this.options.onNodeCollapsed);
              }
              if (typeof (this.options.onNodeDisabled) === 'function') {
                  this.$element.on('nodeDisabled', this.options.onNodeDisabled);
              }
              if (typeof (this.options.onNodeEnabled) === 'function') {
                  this.$element.on('nodeEnabled', this.options.onNodeEnabled);
              }
              if (typeof (this.options.onNodeExpanded) === 'function') {
                  this.$element.on('nodeExpanded', this.options.onNodeExpanded);
              }
              if (typeof (this.options.onNodeSelected) === 'function') {
                  this.$element.on('nodeSelected', this.options.onNodeSelected);
              }
              if (typeof (this.options.onNodeUnchecked) === 'function') {
                  this.$element.on('nodeUnchecked', this.options.onNodeUnchecked);
              }
              if (typeof (this.options.onNodeUnselected) === 'function') {
                  this.$element.on('nodeUnselected', this.options.onNodeUnselected);
              }
              if (typeof (this.options.onSearchComplete) === 'function') {
                  this.$element.on('searchComplete', this.options.onSearchComplete);
              }
              if (typeof (this.options.onSearchCleared) === 'function') {
                  this.$element.on('searchCleared', this.options.onSearchCleared);
              }
              
              /**
               * 给 bootstrap treeview 添加 点击事件 赋值
               */
              if (typeof (this.options.onNodeClicked) === 'function') {
                  this.$element.on('nodeClicked', this.options.onNodeClicked);
              }
         };
         Tree.prototype.clickHandler = function (event) {
              if (!this.options.enableLinks) event.preventDefault();
              var target = $(event.target);
              var node = this.findNode(target);
              if (!node || node.state.disabled) return;
              
              /**
               * @update by sxh: 先执行点击事件
               */
              this.onClicked(node, _default.options);          
    
              var classList = target.attr('class') ? target.attr('class').split(' ') : [];
              if ((classList.indexOf('expand-icon') !== -1)) {
                  this.toggleExpandedState(node, _default.options);
                  this.render();
              }
              else if ((classList.indexOf('check-icon') !== -1)) {
                  
                  this.toggleCheckedState(node, _default.options);
                  this.render();
              }
              else {
                  
                  if (node.selectable) {
                       this.toggleSelectedState(node, _default.options);
                  } else {
                       this.toggleExpandedState(node, _default.options);
                  }
                  this.render();
              }
              
              /**
               * clickHandler -- 最后执行点击事件
               */
            // this.onClicked(node, _default.options);
         };
         /**
         * 给 bootstrap treeview 添加 点击事件
         * 依赖于clickHandler 方法。最后执行
         */
         Tree.prototype.onClicked = function (node, options) {
              if (!node) return;
            if (!options.silent) {
                this.$element.trigger('nodeClicked', $.extend(true, {}, node));
            }
         };

    另外一点需要注意的是,添加的click事件一定要先于checked事件执行,否则仍然不生效。

  • 相关阅读:
    leetcode 287 寻找重复数
    739 每日温度 && 单调栈算法的思路
    leetcode 34 在排序数组中查找元素的第一个和最后一个位置
    leetcode 239 滑动窗口最大值
    leetcode 114 二叉树展开为链表
    leetcode 79 单词搜索
    leetcode 88 合并两个有序数组
    函数指针 & 指针函数
    leetcode 240 搜索二维矩阵
    谱聚类
  • 原文地址:https://www.cnblogs.com/sxhjoker/p/12486026.html
Copyright © 2020-2023  润新知