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事件执行,否则仍然不生效。

原文地址:https://www.cnblogs.com/sxhjoker/p/12486026.html