Commit 75c32d5f6e0f18865bbbec8a2f78174b512a4a0e

Authored by 梁灏
1 parent 71c1c5b0

rebuild Tree

examples/routers/tree.vue
1 1 <template>
2   - <div>
3   - <Tree :data="baseData" show-checkbox></Tree>
4   - <div @click="c">change</div>
5   - </div>
  2 + <Tree :data="baseData" @on-select-change="handleSelectChange" show-checkbox></Tree>
6 3 </template>
7 4 <script>
8 5 export default {
9 6 data () {
10 7 return {
11   - baseData: [{
12   - expand: true,
13   - title: 'parent 1',
14   - children: [{
15   - title: 'parent 1-0',
  8 + baseData: [
  9 + {
16 10 expand: true,
17   - disabled: true,
  11 + title: 'parent 1',
18 12 children: [{
19   - title: 'leaf',
20   - disableCheckbox: true
  13 + title: 'parent 1-0',
  14 + expand: true,
  15 +// disabled: true,
  16 +// checked: true,
  17 + children: [
  18 + {
  19 + title: 'leaf',
  20 + checked: true,
  21 + selected: true
  22 + },
  23 + {
  24 + title: 'leaf',
  25 + checked: false
  26 + }
  27 + ]
21 28 }, {
22   - title: 'leaf',
  29 + title: 'parent 1-1',
  30 + expand: true,
  31 + checked: true,
  32 + children: [
  33 + {
  34 + title: '<span style="color: red">leaf</span>',
  35 + checked: false
  36 + }
  37 + ]
23 38 }]
24   - }, {
25   - title: 'parent 1-1',
26   - expand: true,
27   - checked: true,
28   - children: [{
29   - title: '<span style="color: red">leaf</span>'
30   - }]
31   - }]
32   - }]
  39 + },
  40 +// {
  41 +// expand: true,
  42 +// title: 'parent 1',
  43 +// children: [{
  44 +// title: 'parent 1-0',
  45 +// expand: true,
  46 +// children: [{
  47 +// title: 'leaf'
  48 +// }, {
  49 +// title: 'leaf',
  50 +// }]
  51 +// }, {
  52 +// title: 'parent 1-1',
  53 +// expand: true,
  54 +// checked: true,
  55 +// children: [{
  56 +// title: '<span style="color: red">leaf</span>',
  57 +// }]
  58 +// }]
  59 +// }
  60 + ]
33 61 }
34 62 },
35 63 methods: {
36   - c () {
37   - this.baseData[0].expand = false;
  64 + handleSelectChange (data) {
  65 + console.log(data);
38 66 }
39 67 }
40 68 }
... ...
src/components/tree/tree.vue
... ... @@ -31,6 +31,7 @@
31 31 import Checkbox from '../checkbox/checkbox.vue';
32 32 import { t } from '../../locale';
33 33 import Emitter from '../../mixins/emitter';
  34 + import { findComponentUpward, findComponentDownward } from '../../utils/assist';
34 35  
35 36 const prefixCls = 'ivu-tree';
36 37  
... ... @@ -174,10 +175,18 @@
174 175 }
175 176 }
176 177 // this.$dispatch('nodeSelected', this, selected);
177   - this.dispatch('Tree', 'nodeSelected', {
178   - ori: this,
179   - selected: selected
180   - });
  178 + const parentTree = findComponentUpward(this, 'Tree');
  179 + if (parentTree) {
  180 + this.dispatch('Tree', 'nodeSelected', {
  181 + ori: this,
  182 + selected: selected
  183 + });
  184 + } else {
  185 + this.$emit('nodeSelected', {
  186 + ori: this,
  187 + selected: selected
  188 + });
  189 + }
181 190 }
182 191 },
183 192 setCheck (disabled, index) {
... ... @@ -270,6 +279,7 @@
270 279 });
271 280 });
272 281 this.$on('cancelSelected', ori => {
  282 + console.log(191)
273 283 // this.$broadcast('cancelSelected', ori);
274 284 this.broadcast('Tree', 'cancelSelected', ori);
275 285 if (this !== ori) {
... ...
src/components/tree2/index.js 0 → 100644
  1 +import Tree from './tree.vue';
  2 +export default Tree;
0 3 \ No newline at end of file
... ...
src/components/tree2/node.vue 0 → 100644
  1 +<template>
  2 + <transition name="slide-up">
  3 + <ul :class="classes" v-show="visible">
  4 + <li>
  5 + <span :class="arrowClasses" @click="handleExpand">
  6 + <Icon type="arrow-right-b"></Icon>
  7 + </span>
  8 + <Checkbox
  9 + v-if="showCheckbox"
  10 + :value="data.checked"
  11 + :indeterminate="indeterminate"
  12 + :disabled="data.disabled || data.disableCheckbox"
  13 + @click.native.prevent="handleCheck"></Checkbox>
  14 + <span :class="titleClasses" v-html="data.title" @click="handleSelect"></span>
  15 + <Tree-node
  16 + v-for="item in data.children"
  17 + :key="item"
  18 + :data="item"
  19 + :visible="data.expand"
  20 + :multiple="multiple"
  21 + :show-checkbox="showCheckbox">
  22 + </Tree-node>
  23 + </li>
  24 + </ul>
  25 + </transition>
  26 +</template>
  27 +<script>
  28 + import Checkbox from '../checkbox/checkbox.vue';
  29 + import Emitter from '../../mixins/emitter';
  30 + import { findComponentsDownward } from '../../utils/assist';
  31 +
  32 + const prefixCls = 'ivu-tree';
  33 +
  34 + export default {
  35 + name: 'TreeNode',
  36 + mixins: [ Emitter ],
  37 + components: { Checkbox },
  38 + props: {
  39 + data: {
  40 + type: Object,
  41 + default () {
  42 + return {};
  43 + }
  44 + },
  45 + multiple: {
  46 + type: Boolean,
  47 + default: false
  48 + },
  49 + showCheckbox: {
  50 + type: Boolean,
  51 + default: false
  52 + },
  53 + visible: {
  54 + type: Boolean,
  55 + default: false
  56 + }
  57 + },
  58 + data () {
  59 + return {
  60 + prefixCls: prefixCls,
  61 + indeterminate: false,
  62 + checked: false
  63 + };
  64 + },
  65 + computed: {
  66 + classes () {
  67 + return [
  68 + `${prefixCls}-children`
  69 + ]
  70 + },
  71 + selectedCls () {
  72 + return [
  73 + {
  74 + [`${prefixCls}-node-selected`]: this.data.selected
  75 + }
  76 + ];
  77 + },
  78 + arrowClasses () {
  79 + return [
  80 + `${prefixCls}-arrow`,
  81 + {
  82 + [`${prefixCls}-arrow-disabled`]: this.data.disabled,
  83 + [`${prefixCls}-arrow-open`]: this.data.expand,
  84 + [`${prefixCls}-arrow-hidden`]: !(this.data.children && this.data.children.length)
  85 + }
  86 + ];
  87 + },
  88 + titleClasses () {
  89 + return [
  90 + `${prefixCls}-title`,
  91 + {
  92 + [`${prefixCls}-title-selected`]: this.data.selected
  93 + }
  94 + ];
  95 + }
  96 + },
  97 + methods: {
  98 + handleExpand () {
  99 + if (this.data.disabled) return;
  100 + this.$set(this.data, 'expand', !this.data.expand);
  101 + },
  102 + handleSelect () {
  103 + if (this.data.disabled) return;
  104 + if (this.data.selected) {
  105 + this.data.selected = false;
  106 + } else if (this.multiple) {
  107 + this.$set(this.data, 'selected', !this.data.selected);
  108 + } else {
  109 + this.dispatch('Tree', 'selected', this.data);
  110 + }
  111 + this.dispatch('Tree', 'on-selected');
  112 + },
  113 + handleCheck () {
  114 + if (this.disabled) return;
  115 + this.data.checked = !this.data.checked;
  116 + this.dispatch('Tree', 'checked');
  117 + },
  118 + setIndeterminate () {
  119 + this.indeterminate = this.data.checked ? false : findComponentsDownward(this, 'TreeNode').some(node => node.data.checked);
  120 + }
  121 + },
  122 + created () {
  123 + // created node.vue first, mounted tree.vue second
  124 + if (!this.data.checked) this.$set(this.data, 'checked', false);
  125 + },
  126 + mounted () {
  127 + this.$on('indeterminate', () => {
  128 + this.setIndeterminate();
  129 + })
  130 + }
  131 + };
  132 +</script>
0 133 \ No newline at end of file
... ...
src/components/tree2/tree.vue 0 → 100644
  1 +<template>
  2 + <div :class="prefixCls">
  3 + <Tree-node
  4 + v-for="item in currentData"
  5 + :key="item"
  6 + :data="item"
  7 + visible
  8 + :multiple="multiple"
  9 + :show-checkbox="showCheckbox">
  10 + </Tree-node>
  11 + </div>
  12 +</template>
  13 +<script>
  14 + import TreeNode from './node.vue';
  15 + import { findComponentsDownward } from '../../utils/assist';
  16 + import Emitter from '../../mixins/emitter';
  17 + import { t } from '../../locale';
  18 +
  19 + const prefixCls = 'ivu-tree';
  20 +
  21 + export default {
  22 + name: 'Tree',
  23 + mixins: [ Emitter ],
  24 + components: { TreeNode },
  25 + props: {
  26 + data: {
  27 + type: Array,
  28 + default () {
  29 + return [];
  30 + }
  31 + },
  32 + multiple: {
  33 + type: Boolean,
  34 + default: false
  35 + },
  36 + showCheckbox: {
  37 + type: Boolean,
  38 + default: false
  39 + },
  40 + emptyText: {
  41 + type: String,
  42 + default () {
  43 + return t('i.tree.emptyText');
  44 + }
  45 + }
  46 + },
  47 + data () {
  48 + return {
  49 + prefixCls: prefixCls,
  50 + currentData: this.data
  51 + };
  52 + },
  53 + watch: {
  54 + data (val) {
  55 +
  56 + }
  57 + },
  58 + methods: {
  59 + getSelectedNodes () {
  60 + const nodes = findComponentsDownward(this, 'TreeNode');
  61 + return nodes.filter(node => node.data.selected).map(node => node.data);
  62 + },
  63 + updateData () {
  64 + // init checked status
  65 + function reverseChecked(data) {
  66 + if (data.children) {
  67 + let checkedLength = 0;
  68 + data.children.forEach(node => {
  69 + if (node.children) node = reverseChecked(node);
  70 + if (node.checked) checkedLength++;
  71 + });
  72 +// data.checked = checkedLength >= data.children.length;
  73 + if (checkedLength >= data.children.length) data.checked = true;
  74 + return data;
  75 + } else {
  76 + return data;
  77 + }
  78 + }
  79 +
  80 + function forwardChecked(data) {
  81 + if (data.children) {
  82 + data.children.forEach(node => {
  83 + if (data.checked) node.checked = true;
  84 + if (node.children) node = forwardChecked(node);
  85 + });
  86 + return data;
  87 + } else {
  88 + return data;
  89 + }
  90 + }
  91 + this.currentData = this.data.map(node => reverseChecked(node)).map(node => forwardChecked(node));
  92 + this.broadcast('TreeNode', 'indeterminate');
  93 + }
  94 + },
  95 + mounted () {
  96 + this.updateData();
  97 +
  98 + this.$on('selected', ori => {
  99 + const nodes = findComponentsDownward(this, 'TreeNode');
  100 + nodes.forEach(node => {
  101 + this.$set(node.data, 'selected', false);
  102 + });
  103 + this.$set(ori, 'selected', true);
  104 + });
  105 + this.$on('on-selected', () => {
  106 + this.$emit('on-select-change', this.getSelectedNodes());
  107 + });
  108 + this.$on('checked', () => {
  109 + this.updateData();
  110 + });
  111 + }
  112 + };
  113 +</script>
0 114 \ No newline at end of file
... ...
src/index.js
... ... @@ -40,7 +40,7 @@ import Timeline from &#39;./components/timeline&#39;;
40 40 import TimePicker from './components/time-picker';
41 41 import Tooltip from './components/tooltip';
42 42 import Transfer from './components/transfer';
43   -import Tree from './components/tree';
  43 +import Tree from './components/tree2';
44 44 import Upload from './components/upload';
45 45 import { Row, Col } from './components/grid';
46 46 import { Select, Option, OptionGroup } from './components/select';
... ...
src/styles/components/tree.less
1 1 @tree-prefix-cls: ~"@{css-prefix}tree";
2 2  
3 3 .@{tree-prefix-cls} {
4   - margin: 0;
5   - padding: 5px;
6   - font-size: @font-size-small;
7   - li {
8   - padding: 0;
9   - margin: 8px 0;
  4 + ul{
10 5 list-style: none;
11   - white-space: nowrap;
12   - outline: 0;
13   - a[draggable],
14   - a[draggable="true"] {
15   - user-select: none;
16   - /* Required to make elements draggable in old WebKit */
17   - -khtml-user-drag: element;
18   - -webkit-user-drag: element;
  6 + margin: 0;
  7 + padding: 5px;
  8 + font-size: @font-size-small;
  9 + li{
  10 + list-style: none;
  11 + margin: 8px 0;
  12 + padding: 0;
  13 + white-space: nowrap;
  14 + outline: none;
19 15 }
20   - &.drag-over {
21   - > a[draggable] {
22   - background-color: @primary-color;
23   - color: white;
24   - opacity: 0.8;
25   - }
26   - }
27   - &.drag-over-gap-top {
28   - > a[draggable] {
29   - border-top: 2px @primary-color solid;
30   - }
31   - }
32   - &.drag-over-gap-bottom {
33   - > a[draggable] {
34   - border-bottom: 2px @primary-color solid;
35   - }
36   - }
37   - &.filter-node {
38   - > a {
39   - color: @error-color!important;
40   - font-weight: bold!important;
41   - }
42   - }
43   - ul {
  16 + }
  17 + li{
  18 + ul{
44 19 margin: 0;
45 20 padding: 0 0 0 18px;
46 21 }
47   - a {
48   - display: inline-block;
49   - margin: 0;
50   - padding: 0 4px;
51   - border-radius: @btn-border-radius-small;
52   - cursor: pointer;
53   - text-decoration: none;
54   - vertical-align: top;
55   - color: @text-color;
56   - transition: all @transition-time @ease-in-out;
57   - &:hover {
58   - background-color: tint(@primary-color, 90%);
59   - }
60   - &.@{tree-prefix-cls}-node-selected {
61   - background-color: tint(@primary-color, 80%);
62   - }
  22 + }
  23 + &-title {
  24 + display: inline-block;
  25 + margin: 0;
  26 + padding: 0 4px;
  27 + border-radius: @btn-border-radius-small;
  28 + cursor: pointer;
  29 + vertical-align: top;
  30 + color: @text-color;
  31 + transition: all @transition-time @ease-in-out;
  32 + &:hover {
  33 + background-color: tint(@primary-color, 90%);
63 34 }
64   - .@{checkbox-prefix-cls}-wrapper{
65   - margin-right: 4px;
  35 + &-selected, &-selected:hover{
  36 + background-color: tint(@primary-color, 80%);
66 37 }
67   - span {
68   - &.@{tree-prefix-cls}-switcher,
69   - &.@{tree-prefix-cls}-iconEle {
70   - display: inline-block;
71   - text-align: center;
72   - width: 16px;
73   - height: 16px;
74   - line-height: 16px;
75   - margin: 0;
76   - vertical-align: middle;
77   - border: 0 none;
78   - cursor: pointer;
79   - outline: none;
80   - }
81   - //&.@{tree-prefix-cls}-icon_loading {
82   - // &:after {
83   - // display: inline-block;
84   - // //.iconfont-font("\e6a1");
85   - // animation: loadingCircle 1s infinite linear;
86   - // color: @primary-color;
87   - // }
88   - //}
89   - &.@{tree-prefix-cls}-switcher {
90   - i{
91   - transition: all @transition-time @ease-in-out;
92   - }
93   - &.@{tree-prefix-cls}-switcher-noop {
94   - //display: none;
95   - cursor: auto;
96   - i{
97   - display: none;
98   - }
99   - }
100   - &.@{tree-prefix-cls}-roots_open,
101   - &.@{tree-prefix-cls}-center_open,
102   - &.@{tree-prefix-cls}-bottom_open,
103   - &.@{tree-prefix-cls}-noline_open {
104   - i {
105   - transform: rotate(90deg);
106   - }
107   - }
108   - &.@{tree-prefix-cls}-roots_close,
109   - &.@{tree-prefix-cls}-center_close,
110   - &.@{tree-prefix-cls}-bottom_close,
111   - &.@{tree-prefix-cls}-noline_close {
112   -
113   - }
  38 + }
  39 + &-arrow{
  40 + cursor: pointer;
  41 + i{
  42 + transition: all @transition-time @ease-in-out;
  43 + }
  44 + &-open{
  45 + i {
  46 + transform: rotate(90deg);
114 47 }
115 48 }
116   - }
117   - &-child-tree {
118   - display: none;
119   - &-open {
120   - display: block;
  49 + &-hidden{
  50 + cursor: auto;
  51 + i{
  52 + display: none;
  53 + }
121 54 }
122   - }
123   - &-treenode-disabled {
124   - >span,
125   - >a,
126   - >a span {
127   - color: @input-disabled-bg;
128   - cursor: not-allowed;
  55 + &-disabled{
  56 + cursor: @cursor-disabled;
129 57 }
130 58 }
131   - &-icon__open {
132   - margin-right: 2px;
133   - vertical-align: top;
134   - }
135   - &-icon__close {
136   - margin-right: 2px;
137   - vertical-align: top;
138   - }
139 59 }
140 60 \ No newline at end of file
... ...
src/styles/components/tree2.less 0 → 100644
  1 +@tree-prefix-cls: ~"@{css-prefix}tree";
  2 +
  3 +.@{tree-prefix-cls} {
  4 + margin: 0;
  5 + padding: 5px;
  6 + font-size: @font-size-small;
  7 + li {
  8 + padding: 0;
  9 + margin: 8px 0;
  10 + list-style: none;
  11 + white-space: nowrap;
  12 + outline: 0;
  13 + a[draggable],
  14 + a[draggable="true"] {
  15 + user-select: none;
  16 + /* Required to make elements draggable in old WebKit */
  17 + -khtml-user-drag: element;
  18 + -webkit-user-drag: element;
  19 + }
  20 + &.drag-over {
  21 + > a[draggable] {
  22 + background-color: @primary-color;
  23 + color: white;
  24 + opacity: 0.8;
  25 + }
  26 + }
  27 + &.drag-over-gap-top {
  28 + > a[draggable] {
  29 + border-top: 2px @primary-color solid;
  30 + }
  31 + }
  32 + &.drag-over-gap-bottom {
  33 + > a[draggable] {
  34 + border-bottom: 2px @primary-color solid;
  35 + }
  36 + }
  37 + &.filter-node {
  38 + > a {
  39 + color: @error-color!important;
  40 + font-weight: bold!important;
  41 + }
  42 + }
  43 + ul {
  44 + margin: 0;
  45 + padding: 0 0 0 18px;
  46 + }
  47 + a {
  48 + display: inline-block;
  49 + margin: 0;
  50 + padding: 0 4px;
  51 + border-radius: @btn-border-radius-small;
  52 + cursor: pointer;
  53 + text-decoration: none;
  54 + vertical-align: top;
  55 + color: @text-color;
  56 + transition: all @transition-time @ease-in-out;
  57 + &:hover {
  58 + background-color: tint(@primary-color, 90%);
  59 + }
  60 + &.@{tree-prefix-cls}-node-selected {
  61 + background-color: tint(@primary-color, 80%);
  62 + }
  63 + }
  64 + .@{checkbox-prefix-cls}-wrapper{
  65 + margin-right: 4px;
  66 + }
  67 + span {
  68 + &.@{tree-prefix-cls}-switcher,
  69 + &.@{tree-prefix-cls}-iconEle {
  70 + display: inline-block;
  71 + text-align: center;
  72 + width: 16px;
  73 + height: 16px;
  74 + line-height: 16px;
  75 + margin: 0;
  76 + vertical-align: middle;
  77 + border: 0 none;
  78 + cursor: pointer;
  79 + outline: none;
  80 + }
  81 + //&.@{tree-prefix-cls}-icon_loading {
  82 + // &:after {
  83 + // display: inline-block;
  84 + // //.iconfont-font("\e6a1");
  85 + // animation: loadingCircle 1s infinite linear;
  86 + // color: @primary-color;
  87 + // }
  88 + //}
  89 + &.@{tree-prefix-cls}-switcher {
  90 + i{
  91 + transition: all @transition-time @ease-in-out;
  92 + }
  93 + &.@{tree-prefix-cls}-switcher-noop {
  94 + //display: none;
  95 + cursor: auto;
  96 + i{
  97 + display: none;
  98 + }
  99 + }
  100 + &.@{tree-prefix-cls}-roots_open,
  101 + &.@{tree-prefix-cls}-center_open,
  102 + &.@{tree-prefix-cls}-bottom_open,
  103 + &.@{tree-prefix-cls}-noline_open {
  104 + i {
  105 + transform: rotate(90deg);
  106 + }
  107 + }
  108 + &.@{tree-prefix-cls}-roots_close,
  109 + &.@{tree-prefix-cls}-center_close,
  110 + &.@{tree-prefix-cls}-bottom_close,
  111 + &.@{tree-prefix-cls}-noline_close {
  112 +
  113 + }
  114 + }
  115 + }
  116 + }
  117 + &-child-tree {
  118 + display: none;
  119 + &-open {
  120 + display: block;
  121 + }
  122 + }
  123 + &-treenode-disabled {
  124 + >span,
  125 + >a,
  126 + >a span {
  127 + color: @input-disabled-bg;
  128 + cursor: not-allowed;
  129 + }
  130 + }
  131 + &-icon__open {
  132 + margin-right: 2px;
  133 + vertical-align: top;
  134 + }
  135 + &-icon__close {
  136 + margin-right: 2px;
  137 + vertical-align: top;
  138 + }
  139 +}
0 140 \ No newline at end of file
... ...