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 | }; | ... | ... |