Commit 5b19b5f55f0b1022c3bf5e7b7060534b2d9e3676
1 parent
191068ac
support Transfer
support Transfer
Showing
8 changed files
with
198 additions
and
55 deletions
Show diff stats
examples/app.vue
... | ... | @@ -46,6 +46,7 @@ li + li { border-left: solid 1px #bbb; padding-left: 10px; margin-left: 10px; } |
46 | 46 | <li><router-link to="/select">Select</router-link></li> |
47 | 47 | <li><router-link to="/backtop">Backtop</router-link></li> |
48 | 48 | <li><router-link to="/page">Page</router-link></li> |
49 | + <li><router-link to="/transfer">Transfer</router-link></li> | |
49 | 50 | </ul> |
50 | 51 | </nav> |
51 | 52 | <router-view></router-view> | ... | ... |
examples/main.js
examples/routers/transfer.vue
1 | +<!--<template>--> | |
2 | + <!--<div>--> | |
3 | + <!--<Transfer--> | |
4 | + <!--:data="data1"--> | |
5 | + <!--filterable--> | |
6 | + <!--:target-keys="targetKeys1"--> | |
7 | + <!--:render-format="render1"--> | |
8 | + <!--@on-change="handleChange1"></Transfer>--> | |
9 | + <!--</div>--> | |
10 | +<!--</template>--> | |
11 | +<!--<script>--> | |
12 | + <!--export default {--> | |
13 | + <!--data () {--> | |
14 | + <!--return {--> | |
15 | + <!--data1: this.getMockData(),--> | |
16 | + <!--targetKeys1: this.getTargetKeys()--> | |
17 | + <!--}--> | |
18 | + <!--},--> | |
19 | + <!--methods: {--> | |
20 | + <!--getMockData () {--> | |
21 | + <!--let mockData = [];--> | |
22 | + <!--for (let i = 1; i <= 20; i++) {--> | |
23 | + <!--mockData.push({--> | |
24 | + <!--key: i.toString(),--> | |
25 | + <!--label: '内容' + i,--> | |
26 | + <!--description: '内容' + i + '的描述信息',--> | |
27 | + <!--disabled: Math.random() * 3 < 1--> | |
28 | + <!--});--> | |
29 | + <!--}--> | |
30 | + <!--return mockData;--> | |
31 | + <!--},--> | |
32 | + <!--getTargetKeys () {--> | |
33 | + <!--return this.getMockData()--> | |
34 | + <!--.filter(() => Math.random() * 2 > 1)--> | |
35 | + <!--.map(item => item.key);--> | |
36 | + <!--},--> | |
37 | + <!--render1 (item) {--> | |
38 | + <!--return item.label;--> | |
39 | + <!--},--> | |
40 | + <!--handleChange1 (newTargetKeys, direction, moveKeys) {--> | |
41 | + <!--console.log(newTargetKeys);--> | |
42 | + <!--console.log(direction);--> | |
43 | + <!--console.log(moveKeys);--> | |
44 | + <!--this.targetKeys1 = newTargetKeys;--> | |
45 | + <!--}--> | |
46 | + <!--}--> | |
47 | + <!--}--> | |
48 | +<!--</script>--> | |
49 | + | |
50 | + | |
1 | 51 | <template> |
2 | 52 | <Transfer |
3 | - :data="data2" | |
4 | - :target-keys="targetKeys2" | |
53 | + :data="data3" | |
54 | + :target-keys="targetKeys3" | |
55 | + :list-style="listStyle" | |
56 | + :render-format="render3" | |
57 | + :operations="['向左移动','向右移动']" | |
5 | 58 | filterable |
6 | - :render-format="rf" | |
7 | - :filter-method="filterMethod" | |
8 | - @on-change="handleChange2"></Transfer> | |
59 | + @on-change="handleChange3"> | |
60 | + <div :style="{float: 'right', margin: '5px'}"> | |
61 | + <Button type="ghost" size="small" @click.native="reloadMockData">刷新</Button> | |
62 | + </div> | |
63 | + </Transfer> | |
9 | 64 | </template> |
10 | 65 | <script> |
11 | 66 | export default { |
12 | 67 | data () { |
13 | 68 | return { |
14 | - data2: this.getMockData(), | |
15 | - targetKeys2: this.getTargetKeys() | |
69 | + data3: this.getMockData(), | |
70 | + targetKeys3: this.getTargetKeys(), | |
71 | + listStyle: { | |
72 | + width: '250px', | |
73 | + height: '300px' | |
74 | + } | |
16 | 75 | } |
17 | 76 | }, |
18 | 77 | methods: { |
... | ... | @@ -30,18 +89,62 @@ |
30 | 89 | }, |
31 | 90 | getTargetKeys () { |
32 | 91 | return this.getMockData() |
33 | - .filter(() => Math.random() * 2 > 1) | |
34 | - .map(item => item.key); | |
92 | + .filter(() => Math.random() * 2 > 1) | |
93 | + .map(item => item.key); | |
35 | 94 | }, |
36 | - handleChange2 (newTargetKeys) { | |
37 | - this.targetKeys2 = newTargetKeys; | |
95 | + handleChange3 (newTargetKeys) { | |
96 | + this.targetKeys3 = newTargetKeys; | |
38 | 97 | }, |
39 | - filterMethod (data, query) { | |
40 | - return data.label.indexOf(query) > -1; | |
98 | + render3 (item) { | |
99 | + return item.label + ' - ' + item.description; | |
41 | 100 | }, |
42 | - rf (data) { | |
43 | - return '<i class="ivu-icon ivu-icon-alert"></i>' + data.label; | |
101 | + reloadMockData () { | |
102 | + this.data3 = this.getMockData(); | |
103 | + this.targetKeys3 = this.getTargetKeys(); | |
44 | 104 | } |
45 | 105 | } |
46 | 106 | } |
47 | 107 | </script> |
108 | + | |
109 | +<!--<template>--> | |
110 | + <!--<Transfer--> | |
111 | + <!--:data="data4"--> | |
112 | + <!--:target-keys="targetKeys4"--> | |
113 | + <!--:render-format="render4"--> | |
114 | + <!--@on-change="handleChange4"></Transfer>--> | |
115 | +<!--</template>--> | |
116 | +<!--<script>--> | |
117 | + <!--export default {--> | |
118 | + <!--data () {--> | |
119 | + <!--return {--> | |
120 | + <!--data4: this.getMockData(),--> | |
121 | + <!--targetKeys4: this.getTargetKeys()--> | |
122 | + <!--}--> | |
123 | + <!--},--> | |
124 | + <!--methods: {--> | |
125 | + <!--getMockData () {--> | |
126 | + <!--let mockData = [];--> | |
127 | + <!--for (let i = 1; i <= 20; i++) {--> | |
128 | + <!--mockData.push({--> | |
129 | + <!--key: i.toString(),--> | |
130 | + <!--label: '内容' + i,--> | |
131 | + <!--description: '内容' + i + '的描述信息',--> | |
132 | + <!--disabled: Math.random() * 3 < 1--> | |
133 | + <!--});--> | |
134 | + <!--}--> | |
135 | + <!--return mockData;--> | |
136 | + <!--},--> | |
137 | + <!--getTargetKeys () {--> | |
138 | + <!--return this.getMockData()--> | |
139 | + <!--.filter(() => Math.random() * 2 > 1)--> | |
140 | + <!--.map(item => item.key);--> | |
141 | + <!--},--> | |
142 | + <!--handleChange4 (newTargetKeys) {--> | |
143 | + <!--this.targetKeys4 = newTargetKeys;--> | |
144 | + <!--},--> | |
145 | + <!--render4 (item) {--> | |
146 | + <!--return item.label + ' - ' + item.description;--> | |
147 | + <!--}--> | |
148 | + <!--}--> | |
149 | + <!--}--> | |
150 | +<!--</script>--> | ... | ... |
src/components/transfer/list.vue
1 | 1 | <template> |
2 | 2 | <div :class="classes" :style="style"> |
3 | 3 | <div :class="prefixCls + '-header'"> |
4 | - <Checkbox :checked.sync="checkedAll" :disabled="checkedAllDisabled" @on-change="toggleSelectAll"></Checkbox> | |
4 | + <Checkbox :value="checkedAll" :disabled="checkedAllDisabled" @on-change="toggleSelectAll"></Checkbox> | |
5 | 5 | <span>{{ title }}</span> |
6 | 6 | <span :class="prefixCls + '-header-count'">{{ count }}</span> |
7 | 7 | </div> |
... | ... | @@ -9,21 +9,23 @@ |
9 | 9 | <div :class="prefixCls + '-body-search-wrapper'" v-if="filterable"> |
10 | 10 | <Search |
11 | 11 | :prefix-cls="prefixCls + '-search'" |
12 | - :query.sync="query" | |
12 | + :query="query" | |
13 | + @on-query-clear="handleQueryClear" | |
14 | + @on-query-change="handleQueryChange" | |
13 | 15 | :placeholder="filterPlaceholder"></Search> |
14 | 16 | </div> |
15 | 17 | <ul :class="prefixCls + '-content'"> |
16 | 18 | <li |
17 | - v-for="item in showItems | filterBy filterData" | |
19 | + v-for="item in filterData" | |
18 | 20 | :class="itemClasses(item)" |
19 | 21 | @click.prevent="select(item)"> |
20 | - <Checkbox :checked="isCheck(item)" :disabled="item.disabled"></Checkbox> | |
21 | - <span>{{{ showLabel(item) }}}</span> | |
22 | + <Checkbox :value="isCheck(item)" :disabled="item.disabled"></Checkbox> | |
23 | + <span v-html="showLabel(item)"></span> | |
22 | 24 | </li> |
23 | 25 | <li :class="prefixCls + '-content-not-found'">{{ notFoundText }}</li> |
24 | 26 | </ul> |
25 | 27 | </div> |
26 | - <div :class="prefixCls + '-footer'" v-if="showFooter" v-el:footer><slot></slot></div> | |
28 | + <div :class="prefixCls + '-footer'" v-if="showFooter"><slot></slot></div> | |
27 | 29 | </div> |
28 | 30 | </template> |
29 | 31 | <script> |
... | ... | @@ -31,6 +33,7 @@ |
31 | 33 | import Checkbox from '../checkbox/checkbox.vue'; |
32 | 34 | |
33 | 35 | export default { |
36 | + name: 'TransferList', | |
34 | 37 | components: { Search, Checkbox }, |
35 | 38 | props: { |
36 | 39 | prefixCls: String, |
... | ... | @@ -52,6 +55,11 @@ |
52 | 55 | showFooter: true |
53 | 56 | }; |
54 | 57 | }, |
58 | + watch: { | |
59 | + data () { | |
60 | + this.updateFilteredData(); | |
61 | + } | |
62 | + }, | |
55 | 63 | computed: { |
56 | 64 | classes () { |
57 | 65 | return [ |
... | ... | @@ -79,6 +87,9 @@ |
79 | 87 | }, |
80 | 88 | checkedAllDisabled () { |
81 | 89 | return this.data.filter(data => !data.disabled).length <= 0; |
90 | + }, | |
91 | + filterData () { | |
92 | + return this.showItems.filter(item => this.filterMethod(item, this.query)); | |
82 | 93 | } |
83 | 94 | }, |
84 | 95 | methods: { |
... | ... | @@ -105,25 +116,23 @@ |
105 | 116 | this.showItems = this.data; |
106 | 117 | }, |
107 | 118 | toggleSelectAll (status) { |
108 | - this.checkedKeys = status ? | |
119 | + const keys = status ? | |
109 | 120 | this.data.filter(data => !data.disabled || this.checkedKeys.indexOf(data.key) > -1).map(data => data.key) : |
110 | 121 | this.data.filter(data => data.disabled && this.checkedKeys.indexOf(data.key) > -1).map(data => data.key); |
122 | + this.$emit('on-checked-keys-change', keys); | |
123 | + }, | |
124 | + handleQueryClear () { | |
125 | + this.query = ''; | |
111 | 126 | }, |
112 | - filterData (value) { | |
113 | - return this.filterMethod(value, this.query); | |
127 | + handleQueryChange (val) { | |
128 | + this.query = val; | |
114 | 129 | } |
115 | 130 | }, |
116 | 131 | created () { |
117 | 132 | this.updateFilteredData(); |
118 | - | |
119 | - }, | |
120 | - compiled () { | |
121 | - this.showFooter = this.$els.footer.innerHTML !== ''; | |
122 | 133 | }, |
123 | - watch: { | |
124 | - data () { | |
125 | - this.updateFilteredData(); | |
126 | - } | |
134 | + mounted () { | |
135 | + this.showFooter = this.$slots.default !== undefined; | |
127 | 136 | } |
128 | 137 | }; |
129 | 138 | </script> | ... | ... |
src/components/transfer/operation.vue
1 | 1 | <template> |
2 | 2 | <div :class="prefixCls + '-operation'"> |
3 | - <i-button type="primary" size="small" :disabled="!rightActive" @click="moveToLeft"> | |
3 | + <i-button type="primary" size="small" :disabled="!rightActive" @click.native="moveToLeft"> | |
4 | 4 | <Icon type="ios-arrow-left"></Icon> {{ operations[0] }} |
5 | 5 | </i-button> |
6 | - <i-button type="primary" size="small" :disabled="!leftActive" @click="moveToRight"> | |
6 | + <i-button type="primary" size="small" :disabled="!leftActive" @click.native="moveToRight"> | |
7 | 7 | {{ operations[1] }} <Icon type="ios-arrow-right"></Icon> |
8 | 8 | </i-button> |
9 | 9 | </div> |
... | ... | @@ -13,6 +13,7 @@ |
13 | 13 | import Icon from '../icon/icon.vue'; |
14 | 14 | |
15 | 15 | export default { |
16 | + name: 'Operation', | |
16 | 17 | components: { iButton, Icon }, |
17 | 18 | props: { |
18 | 19 | prefixCls: String, | ... | ... |
src/components/transfer/search.vue
1 | 1 | <template> |
2 | 2 | <div :class="prefixCls"> |
3 | 3 | <i-input |
4 | - :value.sync="query" | |
4 | + v-model="currentQuery" | |
5 | 5 | size="small" |
6 | 6 | :icon="icon" |
7 | 7 | :placeholder="placeholder" |
... | ... | @@ -12,12 +12,26 @@ |
12 | 12 | import iInput from '../input/input.vue'; |
13 | 13 | |
14 | 14 | export default { |
15 | + name: 'Search', | |
15 | 16 | components: { iInput }, |
16 | 17 | props: { |
17 | 18 | prefixCls: String, |
18 | 19 | placeholder: String, |
19 | 20 | query: String |
20 | 21 | }, |
22 | + data () { | |
23 | + return { | |
24 | + currentQuery: this.query | |
25 | + }; | |
26 | + }, | |
27 | + watch: { | |
28 | + query (val) { | |
29 | + this.currentQuery = val; | |
30 | + }, | |
31 | + currentQuery (val) { | |
32 | + this.$emit('on-query-change', val); | |
33 | + } | |
34 | + }, | |
21 | 35 | computed: { |
22 | 36 | icon () { |
23 | 37 | return this.query === '' ? 'ios-search' : 'ios-close'; |
... | ... | @@ -25,17 +39,19 @@ |
25 | 39 | }, |
26 | 40 | methods: { |
27 | 41 | handleClick () { |
28 | - if (this.query === '') return; | |
29 | - this.query = ''; | |
30 | - } | |
31 | - }, | |
32 | - events: { | |
33 | - 'on-form-blur' () { | |
34 | - return false; | |
35 | - }, | |
36 | - 'on-form-change' () { | |
37 | - return false; | |
42 | + if (this.currentQuery === '') return; | |
43 | + this.currentQuery = ''; | |
44 | + this.$emit('on-query-clear'); | |
38 | 45 | } |
39 | 46 | } |
47 | + // todo 事件 | |
48 | +// events: { | |
49 | +// 'on-form-blur' () { | |
50 | +// return false; | |
51 | +// }, | |
52 | +// 'on-form-change' () { | |
53 | +// return false; | |
54 | +// } | |
55 | +// } | |
40 | 56 | }; |
41 | 57 | </script> | ... | ... |
src/components/transfer/transfer.vue
1 | 1 | <template> |
2 | 2 | <div :class="classes"> |
3 | 3 | <List |
4 | - v-ref:left | |
4 | + ref="left" | |
5 | 5 | :prefix-cls="prefixCls + '-list'" |
6 | 6 | :data="leftData" |
7 | 7 | :render-format="renderFormat" |
8 | - :checked-keys.sync="leftCheckedKeys" | |
9 | - :valid-keys-count.sync="leftValidKeysCount" | |
8 | + :checked-keys="leftCheckedKeys" | |
9 | + @on-checked-keys-change="handleLeftCheckedKeysChange" | |
10 | + :valid-keys-count="leftValidKeysCount" | |
10 | 11 | :style="listStyle" |
11 | 12 | :title="titles[0]" |
12 | 13 | :filterable="filterable" |
... | ... | @@ -19,19 +20,20 @@ |
19 | 20 | :operations="operations" |
20 | 21 | :left-active="leftValidKeysCount > 0" |
21 | 22 | :right-active="rightValidKeysCount > 0"></Operation><List |
22 | - v-ref:right | |
23 | + ref="right" | |
23 | 24 | :prefix-cls="prefixCls + '-list'" |
24 | 25 | :data="rightData" |
25 | 26 | :render-format="renderFormat" |
26 | - :checked-keys.sync="rightCheckedKeys" | |
27 | - :valid-keys-count.sync="rightValidKeysCount" | |
27 | + :checked-keys="rightCheckedKeys" | |
28 | + @on-checked-keys-change="handleRightCheckedKeysChange" | |
29 | + :valid-keys-count="rightValidKeysCount" | |
28 | 30 | :style="listStyle" |
29 | 31 | :title="titles[1]" |
30 | 32 | :filterable="filterable" |
31 | 33 | :filter-placeholder="filterPlaceholder" |
32 | 34 | :filter-method="filterMethod" |
33 | 35 | :not-found-text="notFoundText"> |
34 | - <slot></slot> | |
36 | + <slot name="right"></slot> | |
35 | 37 | </List> |
36 | 38 | </div> |
37 | 39 | </template> |
... | ... | @@ -177,7 +179,14 @@ |
177 | 179 | |
178 | 180 | this.$refs[opposite].toggleSelectAll(false); |
179 | 181 | this.$emit('on-change', newTargetKeys, direction, moveKeys); |
180 | - this.$dispatch('on-form-change', newTargetKeys, direction, moveKeys); | |
182 | + // todo 事件 | |
183 | +// this.$dispatch('on-form-change', newTargetKeys, direction, moveKeys); | |
184 | + }, | |
185 | + handleLeftCheckedKeysChange (keys) { | |
186 | + this.leftCheckedKeys = keys; | |
187 | + }, | |
188 | + handleRightCheckedKeysChange (keys) { | |
189 | + this.rightCheckedKeys = keys; | |
181 | 190 | } |
182 | 191 | }, |
183 | 192 | watch: { | ... | ... |
src/index.js
... | ... | @@ -39,7 +39,7 @@ import Tag from './components/tag'; |
39 | 39 | import Timeline from './components/timeline'; |
40 | 40 | // import TimePicker from './components/time-picker'; |
41 | 41 | import Tooltip from './components/tooltip'; |
42 | -// import Transfer from './components/transfer'; | |
42 | +import Transfer from './components/transfer'; | |
43 | 43 | import Tree from './components/tree'; |
44 | 44 | import Upload from './components/upload'; |
45 | 45 | import { Row, Col } from './components/grid'; |
... | ... | @@ -107,7 +107,7 @@ const iview = { |
107 | 107 | TimelineItem: Timeline.Item, |
108 | 108 | // TimePicker, |
109 | 109 | Tooltip, |
110 | - // Transfer, | |
110 | + Transfer, | |
111 | 111 | Tree, |
112 | 112 | Upload |
113 | 113 | }; | ... | ... |