Bläddra i källkod

Tree: add check-descendants attribute

Dreamacro 8 år sedan
förälder
incheckning
41c19249ab
3 ändrade filer med 143 tillägg och 47 borttagningar
  1. 44 47
      packages/tree/src/model/node.js
  2. 5 0
      packages/tree/src/tree.vue
  3. 94 0
      test/unit/specs/tree.spec.js

+ 44 - 47
packages/tree/src/model/node.js

@@ -22,6 +22,8 @@ export const getChildState = node => {
 };
 
 const reInitChecked = function(node) {
+  if (node.childNodes.length === 0) return;
+
   const {all, none, half} = getChildState(node.childNodes);
   if (all) {
     node.checked = true;
@@ -42,22 +44,6 @@ const reInitChecked = function(node) {
   }
 };
 
-const initLazyLoadChild = node => {
-  const childNodes = node.childNodes;
-  if (node.checked) {
-    for (let i = 0, j = childNodes.length; i < j; i++) {
-      const child = childNodes[i];
-      if (!child.disabled) {
-        child.checked = true;
-      }
-    }
-  }
-
-  const parent = node.parent;
-  if (!parent || parent.level === 0) return;
-  reInitChecked(parent);
-};
-
 const getPropertyFromData = function(node, prop) {
   const props = node.store.props;
   const data = node.data || {};
@@ -261,7 +247,11 @@ export default class Node {
     if (this.shouldLoadData()) {
       this.loadData((data) => {
         if (data instanceof Array) {
-          initLazyLoadChild(this);
+          if (this.checked) {
+            this.setChecked(true, true);
+          } else {
+            reInitChecked(this);
+          }
           done();
         }
       });
@@ -300,45 +290,52 @@ export default class Node {
   setChecked(value, deep, recursion, passValue) {
     this.indeterminate = value === 'half';
     this.checked = value === true;
-    let { all, allWithoutDisable } = getChildState(this.childNodes);
 
-    if (this.childNodes.length && (!all && allWithoutDisable)) {
-      this.checked = false;
-      value = false;
-    }
+    if (this.store.checkStrictly) return;
 
-    const handleDescendants = (lazy) => {
-      if (deep && !lazy) {
-        const childNodes = this.childNodes;
-        for (let i = 0, j = childNodes.length; i < j; i++) {
-          const child = childNodes[i];
-          passValue = passValue || value !== false;
-          const isCheck = child.disabled ? child.checked : passValue;
-          child.setChecked(isCheck, deep, true, passValue);
-        }
-        const { half, all } = getChildState(childNodes);
-        if (!all) {
-          this.checked = all;
-          this.indeterminate = half;
-        }
+    if (!(this.shouldLoadData() && !this.store.checkDescendants)) {
+      let { all, allWithoutDisable } = getChildState(this.childNodes);
+
+      if (!this.isLeaf && (!all && allWithoutDisable)) {
+        this.checked = false;
+        value = false;
       }
-    };
 
-    if (!this.store.checkStrictly && this.shouldLoadData()) {
-      // Only work on lazy load data.
-      this.loadData(() => {
-        handleDescendants(true);
-      }, {
-        checked: value !== false
-      });
-    } else {
-      handleDescendants();
+      const handleDescendants = () => {
+        if (deep) {
+          const childNodes = this.childNodes;
+          for (let i = 0, j = childNodes.length; i < j; i++) {
+            const child = childNodes[i];
+            passValue = passValue || value !== false;
+            const isCheck = child.disabled ? child.checked : passValue;
+            child.setChecked(isCheck, deep, true, passValue);
+          }
+          const { half, all } = getChildState(childNodes);
+          if (!all) {
+            this.checked = all;
+            this.indeterminate = half;
+          }
+        }
+      };
+
+      if (this.shouldLoadData()) {
+        // Only work on lazy load data.
+        this.loadData(() => {
+          handleDescendants();
+          reInitChecked(this);
+        }, {
+          checked: value !== false
+        });
+        return;
+      } else {
+        handleDescendants();
+      }
     }
 
     const parent = this.parent;
     if (!parent || parent.level === 0) return;
 
-    if (!this.store.checkStrictly && !recursion) {
+    if (!recursion) {
       reInitChecked(parent);
     }
   }

+ 5 - 0
packages/tree/src/tree.vue

@@ -53,6 +53,10 @@
         type: Boolean,
         default: true
       },
+      checkDescendants: {
+        type: Boolean,
+        default: false
+      },
       autoExpandParent: {
         type: Boolean,
         default: true
@@ -180,6 +184,7 @@
         load: this.load,
         currentNodeKey: this.currentNodeKey,
         checkStrictly: this.checkStrictly,
+        checkDescendants: this.checkDescendants,
         defaultCheckedKeys: this.defaultCheckedKeys,
         defaultExpandedKeys: this.defaultExpandedKeys,
         autoExpandParent: this.autoExpandParent,

+ 94 - 0
test/unit/specs/tree.spec.js

@@ -522,6 +522,100 @@ describe('Tree', () => {
     }, 100);
   });
 
+  it('lazy defaultChecked', done => {
+    vm = getTreeVm(':props="defaultProps" node-key="id" lazy :load="loadNode" show-checkbox', {
+      methods: {
+        loadNode(node, resolve) {
+          if (node.level === 0) {
+            return resolve([{ label: 'region1', id: this.count++ }, { label: 'region2', id: this.count++ }]);
+          }
+          if (node.level > 4) return resolve([]);
+          setTimeout(() => {
+            resolve([{
+              label: 'zone' + this.count,
+              id: this.count++
+            }, {
+              label: 'zone' + this.count,
+              id: this.count++
+            }]);
+          }, 50);
+        }
+      }
+    });
+    const tree = vm.$children[0];
+    const firstNode = document.querySelector('.el-tree-node__content');
+    const initStatus = firstNode.querySelector('.is-indeterminate');
+    expect(initStatus).to.equal(null);
+    tree.store.setCheckedKeys([3]);
+    firstNode.querySelector('.el-tree-node__expand-icon').click();
+    setTimeout(() => {
+      const clickStatus = firstNode.querySelector('.is-indeterminate');
+      expect(clickStatus).to.not.equal(null);
+      const child = document.querySelectorAll('.el-tree-node__content')[1];
+      expect(child.querySelector('input').checked).to.equal(true);
+      done();
+    }, 300);
+  });
+
+  it('lazy expandOnChecked', done => {
+    vm = getTreeVm(':props="defaultProps" node-key="id" lazy :load="loadNode" show-checkbox check-descendants', {
+      methods: {
+        loadNode(node, resolve) {
+          if (node.level === 0) {
+            return resolve([{ label: 'region1', id: this.count++ }, { label: 'region2', id: this.count++ }]);
+          }
+          if (node.level > 4) return resolve([]);
+          setTimeout(() => {
+            resolve([{
+              label: 'zone' + this.count,
+              id: this.count++
+            }, {
+              label: 'zone' + this.count,
+              id: this.count++
+            }]);
+          }, 50);
+        }
+      }
+    });
+    const tree = vm.$children[0];
+    tree.store.setCheckedKeys([1]);
+    setTimeout(() => {
+      const id5 = document.querySelectorAll('.el-tree-node__content')[3];
+      expect(id5.querySelector('input').checked).to.equal(true);
+      done();
+    }, 300);
+  });
+
+  it('lazy without expandOnChecked', done => {
+    vm = getTreeVm(':props="defaultProps" node-key="id" lazy :load="loadNode" show-checkbox', {
+      methods: {
+        loadNode(node, resolve) {
+          if (node.level === 0) {
+            return resolve([{ label: 'region1', id: this.count++ }, { label: 'region2', id: this.count++ }]);
+          }
+          if (node.level > 4) return resolve([]);
+          setTimeout(() => {
+            resolve([{
+              label: 'zone' + this.count,
+              id: this.count++
+            }, {
+              label: 'zone' + this.count,
+              id: this.count++
+            }]);
+          }, 50);
+        }
+      }
+    });
+    const tree = vm.$children[0];
+    tree.store.setCheckedKeys([1]);
+    setTimeout(() => {
+      const nodes = document.querySelectorAll('.el-tree-node__content');
+      expect(nodes[0].querySelector('input').checked).to.equal(true);
+      expect(nodes.length).to.equal(2);
+      done();
+    }, 300);
+  });
+
   it('accordion', done => {
     vm = getTreeVm(':props="defaultProps" accordion');
     const firstNode = vm.$el.querySelector('.el-tree-node__content');