Commit 34ee7b4a14b4eb6db62def19528fe2c9c0758c13
1 parent
bb71140e
support Tree & add dispatch and broadcast methods
support Tree,many component add name $option;add dispatch and broadcast methods, mixins it
Showing
28 changed files
with
190 additions
and
69 deletions
Show diff stats
CHANGE.md
... | ... | @@ -21,4 +21,6 @@ class 改为了 className |
21 | 21 | ### Collapse |
22 | 22 | 废弃 activeKey,使用 v-model,key 是保留的,更名为 name |
23 | 23 | ### Carousel |
24 | -废弃 activeIndex,使用 v-model,v-for="n in slides.length",Vue2的数字循环,是从1开始的 | |
25 | 24 | \ No newline at end of file |
25 | +废弃 activeIndex,使用 v-model,v-for="n in slides.length",Vue2的数字循环,是从1开始的 | |
26 | +### Tree | |
27 | +废弃 data,改为 value,使用 v-model,key 更名为 name | |
26 | 28 | \ No newline at end of file | ... | ... |
README.md
src/components/alert/alert.vue
src/components/badge/badge.vue
src/components/button/button-group.vue
src/components/cascader/cascader.vue
src/components/checkbox/checkbox-group.vue
src/components/circle/circle.vue
src/components/collapse/collapse.vue
src/components/collapse/panel.vue
src/components/grid/col.vue
src/components/grid/row.vue
src/components/input-number/input-number.vue
src/components/radio/radio-group.vue
src/components/steps/step.vue
src/components/steps/steps.vue
src/components/switch/switch.vue
src/components/tag/tag.vue
src/components/timeline/timeline-item.vue
src/components/timeline/timeline.vue
src/components/tree/tree.vue
1 | 1 | <template> |
2 | 2 | <ul :class="classes"> |
3 | - <li v-for="item in data" :class="itemCls(item)"> | |
4 | - <span :class="arrowCls(item)" @click="setExpand(item.disabled, $index)"> | |
3 | + <li v-for="(item, index) in data" :class="itemCls(item)"> | |
4 | + <span :class="arrowCls(item)" @click="setExpand(item.disabled, index)"> | |
5 | 5 | <Icon type="arrow-right-b"></Icon> |
6 | 6 | </span> |
7 | 7 | <Checkbox |
8 | 8 | v-if="showCheckbox" |
9 | - :checked="item.checked && item.childrenCheckedStatus == 2" | |
9 | + :value="item.checked && item.childrenCheckedStatus == 2" | |
10 | 10 | :disabled="item.disabled || item.disableCheckbox" |
11 | 11 | :indeterminate="item.checked && item.childrenCheckedStatus == 1" |
12 | - @click.prevent="setCheck(item.disabled||item.disableCheckbox,$index)"></Checkbox> | |
13 | - <a :class="titleCls(item)" @click="setSelect(item.disabled, $index)"> | |
12 | + @click.prevent="setCheck(item.disabled||item.disableCheckbox, index)"></Checkbox> | |
13 | + <a :class="titleCls(item)" @click="setSelect(item.disabled, index)"> | |
14 | 14 | <span :class="[prefixCls + '-title']" v-html="item.title"></span> |
15 | 15 | </a> |
16 | - <tree | |
17 | - v-if="!item.isLeaf" | |
18 | - v-show="item.expand" | |
19 | - :class="expandCls(item)" | |
20 | - :data.sync="item.children" | |
21 | - :key="this.key+'.'+$index" | |
22 | - :multiple="multiple" | |
23 | - :show-checkbox="showCheckbox" | |
24 | - transition="slide-up"></tree> | |
16 | + <transition name="slide-up"> | |
17 | + <Tree | |
18 | + v-if="!item.isLeaf" | |
19 | + v-show="item.expand" | |
20 | + :class="expandCls(item)" | |
21 | + :value="item.children" | |
22 | + :name="item.name+'.'+index" | |
23 | + :multiple="multiple" | |
24 | + :show-checkbox="showCheckbox"></Tree> | |
25 | + </transition> | |
25 | 26 | </li> |
26 | 27 | </ul> |
27 | 28 | </template> |
... | ... | @@ -29,20 +30,22 @@ |
29 | 30 | import Icon from '../icon/icon.vue'; |
30 | 31 | import Checkbox from '../checkbox/checkbox.vue'; |
31 | 32 | import { t } from '../../locale'; |
33 | + import emitter from '../../mixins/emitter'; | |
32 | 34 | |
33 | 35 | const prefixCls = 'ivu-tree'; |
34 | 36 | |
35 | 37 | export default { |
36 | - name: 'tree', | |
38 | + name: 'Tree', | |
37 | 39 | components: { Icon, Checkbox }, |
40 | + mixins: [ emitter ], | |
38 | 41 | props: { |
39 | - data: { | |
42 | + value: { | |
40 | 43 | type: Array, |
41 | 44 | default () { |
42 | 45 | return []; |
43 | 46 | } |
44 | 47 | }, |
45 | - key: { | |
48 | + name: { | |
46 | 49 | type: String, |
47 | 50 | default: '0' |
48 | 51 | }, |
... | ... | @@ -63,12 +66,13 @@ |
63 | 66 | }, |
64 | 67 | data () { |
65 | 68 | return { |
66 | - prefixCls: prefixCls | |
69 | + prefixCls: prefixCls, | |
70 | + data: this.value | |
67 | 71 | }; |
68 | 72 | }, |
69 | 73 | computed: { |
70 | 74 | classes () { |
71 | - if (this.key === '0') { | |
75 | + if (this.name === '0') { | |
72 | 76 | return this.prefixCls; |
73 | 77 | } else { |
74 | 78 | return `${this.prefixCls}-child-tree`; |
... | ... | @@ -76,8 +80,11 @@ |
76 | 80 | } |
77 | 81 | }, |
78 | 82 | watch: { |
79 | - data(){ | |
80 | - if (this.key === '0') { | |
83 | + value (val) { | |
84 | + this.data = val; | |
85 | + }, | |
86 | + data () { | |
87 | + if (this.name === '0') { | |
81 | 88 | this.setKey(); |
82 | 89 | this.preHandle(); |
83 | 90 | } |
... | ... | @@ -118,55 +125,82 @@ |
118 | 125 | }, |
119 | 126 | setKey () { |
120 | 127 | for (let i = 0; i < this.data.length; i++) { |
121 | - this.data[i].key = `${this.key}.${i}`; | |
128 | + this.data[i].name = `${this.name}.${i}`; | |
122 | 129 | } |
123 | 130 | }, |
124 | 131 | preHandle () { |
125 | - for (let [i,item] of this.data.entries()) { | |
132 | + for (let [i, item] of this.data.entries()) { | |
126 | 133 | if (!item.children || !item.children.length) { |
127 | - this.$set(`data[${i}].isLeaf`, true); | |
128 | - this.$set(`data[${i}].childrenCheckedStatus`, 2); | |
134 | +// this.$set(`data[${i}].isLeaf`, true); | |
135 | +// this.$set(`data[${i}].childrenCheckedStatus`, 2); | |
136 | + this.$set(this.data[i], 'isLeaf', true); | |
137 | + this.$set(this.data[i], 'childrenCheckedStatus', 2); | |
129 | 138 | continue; |
130 | 139 | } |
131 | 140 | if (item.checked && !item.childrenCheckedStatus) { |
132 | - this.$set(`data[${i}].childrenCheckedStatus`, 2); | |
133 | - this.$broadcast('parentChecked', true, `${this.key}.${i}`); | |
141 | +// this.$set(`data[${i}].childrenCheckedStatus`, 2); | |
142 | + this.$set(this.data[i], 'childrenCheckedStatus', 2); | |
143 | +// this.$broadcast('parentChecked', true, `${this.name}.${i}`); | |
144 | + this.broadcast('Tree', 'parentChecked', { | |
145 | + status: true, | |
146 | + name: `${this.name}.${i}` | |
147 | + }); | |
134 | 148 | } else { |
135 | 149 | let status = this.getChildrenCheckedStatus(item.children); |
136 | - this.$set(`data[${i}].childrenCheckedStatus`, status); | |
137 | - if (status !== 0) this.$set(`data[${i}].checked`, true); | |
150 | +// this.$set(`data[${i}].childrenCheckedStatus`, status); | |
151 | + this.$set(this.data[i], 'childrenCheckedStatus', status); | |
152 | +// if (status !== 0) this.$set(`data[${i}].checked`, true); | |
153 | + if (status !== 0) this.$set(this.data[i], 'checked', true); | |
138 | 154 | } |
139 | 155 | } |
140 | 156 | }, |
141 | 157 | setExpand (disabled, index) { |
142 | 158 | if (!disabled) { |
143 | - this.$set(`data[${index}].expand`, !this.data[index].expand); | |
159 | +// this.$set(`data[${index}].expand`, !this.data[index].expand); | |
160 | + this.$set(this.data[index], 'expand', !this.data[index].expand); | |
144 | 161 | } |
145 | 162 | }, |
146 | 163 | setSelect (disabled, index) { |
147 | 164 | if (!disabled) { |
148 | 165 | const selected = !this.data[index].selected; |
149 | 166 | if (this.multiple || !selected) { |
150 | - this.$set(`data[${index}].selected`, selected); | |
167 | +// this.$set(`data[${index}].selected`, selected); | |
168 | + this.$set(this.data[index], 'selected', selected); | |
151 | 169 | } else { |
152 | 170 | for (let i = 0; i < this.data.length; i++) { |
153 | 171 | if (i == index) { |
154 | - this.$set(`data[${i}].selected`, true); | |
172 | +// this.$set(`data[${i}].selected`, true); | |
173 | + this.$set(this.data[i], 'selected', true); | |
155 | 174 | } else { |
156 | - this.$set(`data[${i}].selected`, false); | |
175 | +// this.$set(`data[${i}].selected`, false); | |
176 | + this.$set(this.data[i], 'selected', false); | |
157 | 177 | } |
158 | 178 | } |
159 | 179 | } |
160 | - this.$dispatch('nodeSelected', this, selected); | |
180 | +// this.$dispatch('nodeSelected', this, selected); | |
181 | + this.dispatch('Tree', 'nodeSelected', { | |
182 | + ori: this, | |
183 | + selected: selected | |
184 | + }) | |
161 | 185 | } |
162 | 186 | }, |
163 | 187 | setCheck (disabled, index) { |
164 | 188 | if (disabled) return; |
165 | 189 | const checked = !this.data[index].checked; |
166 | - this.$set(`data[${index}].checked`, checked); | |
167 | - this.$set(`data[${index}].childrenCheckedStatus`, checked ? 2 : 0); | |
168 | - this.$dispatch('childChecked', this, this.key); | |
169 | - this.$broadcast('parentChecked', checked, `${this.key}.${index}`); | |
190 | +// this.$set(`data[${index}].checked`, checked); | |
191 | + this.$set(this.data[index], 'checked', checked); | |
192 | +// this.$set(`data[${index}].childrenCheckedStatus`, checked ? 2 : 0); | |
193 | + this.$set(this.data[index], 'childrenCheckedStatus', checked ? 2 : 0); | |
194 | +// this.$dispatch('childChecked', this, this.name); | |
195 | + this.dispatch('Tree', 'childChecked', { | |
196 | + ori: this, | |
197 | + name: this.name | |
198 | + }); | |
199 | +// this.$broadcast('parentChecked', checked, `${this.name}.${index}`); | |
200 | + this.broadcast('Tree', 'parentChecked', { | |
201 | + status: checked, | |
202 | + name: `${this.name}.${index}` | |
203 | + }); | |
170 | 204 | }, |
171 | 205 | getNodes (data, opt) { |
172 | 206 | data = data || this.data; |
... | ... | @@ -215,55 +249,83 @@ |
215 | 249 | } |
216 | 250 | } |
217 | 251 | }, |
218 | - ready(){ | |
252 | + mounted () { | |
219 | 253 | this.setKey(); |
220 | 254 | this.preHandle(); |
221 | 255 | |
222 | - this.$on('nodeSelected', (ori, selected) => { | |
223 | - if (this.key !== '0') return true; | |
256 | +// this.$on('nodeSelected', (ori, selected) => { | |
257 | + this.$on('nodeSelected', (params) => { | |
258 | + const ori = params.ori; | |
259 | + const selected = params.selected; | |
260 | + | |
261 | + if (this.name !== '0') return true; | |
224 | 262 | if (!this.multiple && selected) { |
225 | 263 | if (this !== ori) { |
226 | 264 | for (let i = 0; i < this.data.length; i++) { |
227 | - this.$set(`data[${i}].selected`, false); | |
265 | +// this.$set(`data[${i}].selected`, false); | |
266 | + this.$set(this.data[i], 'selected', false); | |
228 | 267 | } |
229 | 268 | } |
230 | - this.$broadcast('cancelSelected', ori); | |
269 | +// this.$broadcast('cancelSelected', ori); | |
270 | + this.broadcast('Tree', 'cancelSelected', ori); | |
231 | 271 | } |
232 | 272 | this.$nextTick(() => { |
233 | 273 | this.$emit('on-select-change', this.getSelectedNodes()); |
234 | 274 | }); |
235 | 275 | }); |
236 | 276 | this.$on('cancelSelected', ori => { |
237 | - this.$broadcast('cancelSelected', ori); | |
277 | +// this.$broadcast('cancelSelected', ori); | |
278 | + this.broadcast('Tree', 'cancelSelected', ori); | |
238 | 279 | if (this !== ori) { |
239 | 280 | for (let i = 0; i < this.data.length; i++) { |
240 | - this.$set(`data[${i}].selected`, false); | |
281 | +// this.$set(`data[${i}].selected`, false); | |
282 | + this.$set(this.data[i], 'selected', false); | |
241 | 283 | } |
242 | 284 | } |
243 | 285 | }); |
244 | - this.$on('parentChecked', (status, key) => { | |
245 | - if (this.key == key || this.key.startsWith(key + '.')) { | |
286 | +// this.$on('parentChecked', (status, name) => { | |
287 | + this.$on('parentChecked', (params) => { | |
288 | + const status = params.status; | |
289 | + const name = params.name; | |
290 | + | |
291 | + if (this.name == name || this.name.startsWith(name + '.')) { | |
246 | 292 | for (let i = 0; i < this.data.length; i++) { |
247 | - this.$set(`data[${i}].checked`, status); | |
248 | - this.$set(`data[${i}].childrenCheckedStatus`, status ? 2 : 0); | |
293 | +// this.$set(`data[${i}].checked`, status); | |
294 | + this.$set(this.data[i], 'checked', status); | |
295 | +// this.$set(`data[${i}].childrenCheckedStatus`, status ? 2 : 0); | |
296 | + this.$set(this.data[i], 'childrenCheckedStatus', status ? 2 : 0); | |
249 | 297 | } |
250 | - this.$broadcast('parentChecked', status, key); | |
298 | +// this.$broadcast('parentChecked', status, name); | |
299 | + this.broadcast('Tree', 'parentChecked', { | |
300 | + status: status, | |
301 | + name: name | |
302 | + }); | |
251 | 303 | } |
252 | 304 | }); |
253 | - this.$on('childChecked', (ori, key) => { | |
254 | - if (this.key === '0') { | |
305 | +// this.$on('childChecked', (ori, name) => { | |
306 | + this.$on('childChecked', (params) => { | |
307 | + const ori = params.ori; | |
308 | + const name = params.name; | |
309 | + | |
310 | + if (this.name === '0') { | |
255 | 311 | this.$nextTick(() => { |
256 | 312 | this.$emit('on-check-change', this.getCheckedNodes()); |
257 | 313 | }); |
258 | 314 | } |
259 | 315 | if (this === ori) return; |
260 | 316 | for (let [i,item] of this.data.entries()) { |
261 | - if (this.key + '.' + i == key) { | |
317 | + if (this.name + '.' + i == name) { | |
262 | 318 | let temp = this.getChildrenCheckedStatus(item.children); |
263 | 319 | if (temp != item.childrenCheckedStatus) { |
264 | - this.$set(`data[${i}].checked`, !!temp); | |
265 | - this.$set(`data[${i}].childrenCheckedStatus`, temp); | |
266 | - if (this.key !== '0') this.$dispatch('childChecked', this, this.key); | |
320 | +// this.$set(`data[${i}].checked`, !!temp); | |
321 | + this.$set(this.data[i], 'checked', !!temp); | |
322 | +// this.$set(`data[${i}].childrenCheckedStatus`, temp); | |
323 | + this.$set(this.data[i], 'childrenCheckedStatus', temp); | |
324 | +// if (this.name !== '0') this.$dispatch('childChecked', this, this.name); | |
325 | + if (this.name !== '0') this.dispatch('Tree', 'childChecked', { | |
326 | + ori: this, | |
327 | + name: this.name | |
328 | + }); | |
267 | 329 | } |
268 | 330 | } |
269 | 331 | } | ... | ... |
src/components/upload/upload-list.vue
src/components/upload/upload.vue
src/index.js
... | ... | @@ -40,7 +40,7 @@ import Timeline from './components/timeline'; |
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/tree'; | |
44 | 44 | import Upload from './components/upload'; |
45 | 45 | import { Row, Col } from './components/grid'; |
46 | 46 | // import { Select, Option, OptionGroup } from './components/select'; |
... | ... | @@ -108,7 +108,7 @@ const iview = { |
108 | 108 | // TimePicker, |
109 | 109 | // Tooltip, |
110 | 110 | // Transfer, |
111 | - // Tree, | |
111 | + Tree, | |
112 | 112 | Upload |
113 | 113 | }; |
114 | 114 | ... | ... |
1 | +function broadcast(componentName, eventName, params) { | |
2 | + this.$children.forEach(child => { | |
3 | + const name = child.$options.name; | |
4 | + | |
5 | + if (name === componentName) { | |
6 | + child.$emit.apply(child, [eventName].concat(params)); | |
7 | + } else { | |
8 | + broadcast.apply(child, [componentName, eventName].concat([params])); | |
9 | + } | |
10 | + }); | |
11 | +} | |
12 | +export default { | |
13 | + methods: { | |
14 | + dispatch(componentName, eventName, params) { | |
15 | + let parent = this.$parent || this.$root; | |
16 | + let name = parent.$options.name; | |
17 | + | |
18 | + while (parent && (!name || name !== componentName)) { | |
19 | + parent = parent.$parent; | |
20 | + | |
21 | + if (parent) { | |
22 | + name = parent.$options.name; | |
23 | + } | |
24 | + } | |
25 | + if (parent) { | |
26 | + parent.$emit.apply(parent, [eventName].concat(params)); | |
27 | + } | |
28 | + }, | |
29 | + broadcast(componentName, eventName, params) { | |
30 | + broadcast.call(this, componentName, eventName, params); | |
31 | + } | |
32 | + } | |
33 | +}; | |
0 | 34 | \ No newline at end of file | ... | ... |
test/app.vue
... | ... | @@ -30,6 +30,7 @@ li + li { border-left: solid 1px #bbb; padding-left: 10px; margin-left: 10px; } |
30 | 30 | <li><router-link to="/upload">Upload</router-link></li> |
31 | 31 | <li><router-link to="/collapse">Collapse</router-link></li> |
32 | 32 | <li><router-link to="/carousel">Carousel</router-link></li> |
33 | + <li><router-link to="/tree">Tree</router-link></li> | |
33 | 34 | </ul> |
34 | 35 | </nav> |
35 | 36 | <router-view></router-view> | ... | ... |
test/main.js
test/routers/tree.vue
1 | 1 | <template> |
2 | - <Tree | |
3 | - :data.sync="treeData" | |
4 | - :show-checkbox="true" | |
5 | - :multiple="true" | |
6 | - @on-select-change="selectFn" | |
7 | - @on-check-change="checkFn"></Tree> | |
2 | + <div> | |
3 | + <Tree | |
4 | + v-model="treeData" | |
5 | + :show-checkbox="true" | |
6 | + :multiple="true" | |
7 | + @on-select-change="selectFn" | |
8 | + @on-check-change="checkFn"></Tree> | |
9 | + </div> | |
8 | 10 | </template> |
9 | 11 | <script> |
10 | 12 | export default { | ... | ... |