1.element-ui 地址:https://github.com/ElemeFE/element
2.修改elelment-ui版本:2.2.2(请选择和项目相对应的版本)
3.修改内容:穿梭框组件(transfer),实现上下移动排序
4.效果:
步骤
从github上把项目克隆到本地
全局安装yarn :npm install -g yarn
安装依赖并启动项目:npm run dev (已经使用 yarn 进行依赖版本的锁定,所以请不要使用 npm install
安装依赖。)
目录介绍
我们修改源码主要也是修改这两个位置
打开packages\transfer\src\main.vue(红色部分是我修改过的代码)
1 <template> 2 <div class="el-transfer"> 3 <transfer-panel 4 v-bind="$props" 5 ref="leftPanel" 6 :data="sourceData" 7 :title="titles[0] || t('el.transfer.titles.0')" 8 :default-checked="leftDefaultChecked" 9 :placeholder="filterPlaceholder || t('el.transfer.filterPlaceholder')" 10 @checked-change="onSourceCheckedChange"> 11 <slot name="left-footer"></slot> 12 </transfer-panel> 13 <div class="el-transfer__buttons"> 14 <el-button 15 type="primary" 16 :class="['el-transfer__button', hasButtonTexts ? 'is-with-texts' : '']" 17 @click.native="addToLeft" 18 :disabled="rightChecked.length === 0"> 19 <i class="el-icon-arrow-left"></i> 20 <span v-if="buttonTexts[0] !== undefined">{{ buttonTexts[0] }}</span> 21 </el-button> 22 <el-button 23 type="primary" 24 :class="['el-transfer__button', hasButtonTexts ? 'is-with-texts' : '']" 25 @click.native="addToRight" 26 :disabled="leftChecked.length === 0"> 27 <span v-if="buttonTexts[1] !== undefined">{{ buttonTexts[1] }}</span> 28 <i class="el-icon-arrow-right"></i> 29 </el-button> 30 <el-button 31 v-if="moveable" 32 type="primary" 33 :class="['el-transfer__button', hasButtonTexts ? 'is-with-texts' : '']" 34 @click.native="toUp" 35 :disabled="rightChecked.length === 0 || rightChecked.length > 1"> 36 <span v-if="buttonTexts[2] !== undefined">{{ buttonTexts[2] }}</span> 37 <i class="el-icon-arrow-up"></i> 38 </el-button> 39 <el-button 40 v-if="moveable" 41 type="primary" 42 :class="['el-transfer__button', hasButtonTexts ? 'is-with-texts' : '']" 43 @click.native="toDown" 44 :disabled="rightChecked.length === 0 || rightChecked.length > 1"> 45 <span v-if="buttonTexts[3] !== undefined">{{ buttonTexts[3] }}</span> 46 <i class="el-icon-arrow-down"></i> 47 </el-button> 48 </div> 49 <transfer-panel 50 v-bind="$props" 51 ref="rightPanel" 52 :data="targetData" 53 :title="titles[1] || t('el.transfer.titles.1')" 54 :default-checked="rightDefaultChecked" 55 :placeholder="filterPlaceholder || t('el.transfer.filterPlaceholder')" 56 @checked-change="onTargetCheckedChange"> 57 <slot name="right-footer"></slot> 58 </transfer-panel> 59 </div> 60 </template> 61 62 <script> 63 import ElButton from 'element-ui/packages/button'; 64 import Emitter from 'element-ui/src/mixins/emitter'; 65 import Locale from 'element-ui/src/mixins/locale'; 66 import TransferPanel from './transfer-panel.vue'; 67 import Migrating from 'element-ui/src/mixins/migrating'; 68 69 export default { 70 name: 'ElTransfer', 71 72 mixins: [Emitter, Locale, Migrating], 73 74 components: { 75 TransferPanel, 76 ElButton 77 }, 78 79 props: { 80 data: { 81 type: Array, 82 default() { 83 return []; 84 } 85 }, 86 titles: { 87 type: Array, 88 default() { 89 return []; 90 } 91 }, 92 buttonTexts: { 93 type: Array, 94 default() { 95 return []; 96 } 97 }, 98 filterPlaceholder: { 99 type: String, 100 default: '' 101 }, 102 filterMethod: Function, 103 leftDefaultChecked: { 104 type: Array, 105 default() { 106 return []; 107 } 108 }, 109 rightDefaultChecked: { 110 type: Array, 111 default() { 112 return []; 113 } 114 }, 115 renderContent: Function, 116 value: { 117 type: Array, 118 default() { 119 return []; 120 } 121 }, 122 format: { 123 type: Object, 124 default() { 125 return {}; 126 } 127 }, 128 filterable: Boolean, 129 props: { 130 type: Object, 131 default() { 132 return { 133 label: 'label', 134 key: 'key', 135 disabled: 'disabled' 136 }; 137 } 138 }, 139 targetOrder: { 140 type: String, 141 default: 'original' 142 }, 143 moveable: Boolean 144 }, 145 146 data() { 147 return { 148 leftChecked: [], 149 rightChecked: [] 150 }; 151 }, 152 153 computed: { 154 dataObj() { 155 const key = this.props.key; 156 return this.data.reduce((o, cur) => (o[cur[key]] = cur) && o, {}); 157 }, 158 159 sourceData() { 160 return this.data.filter(item => this.value.indexOf(item[this.props.key]) === -1); 161 }, 162 163 targetData() { 164 return this.targetOrder === 'original' 165 ? this.data.filter(item => this.value.indexOf(item[this.props.key]) > -1) 166 : this.value.map(key => this.dataObj[key]); 167 }, 168 169 hasButtonTexts() { 170 return this.buttonTexts.length === 4; 171 } 172 }, 173 174 watch: { 175 value(val) { 176 this.dispatch('ElFormItem', 'el.form.change', val); 177 } 178 }, 179 180 methods: { 181 getMigratingConfig() { 182 return { 183 props: { 184 'footer-format': 'footer-format is renamed to format.' 185 } 186 }; 187 }, 188 189 onSourceCheckedChange(val, movedKeys) { 190 this.leftChecked = val; 191 if (movedKeys === undefined) return; 192 this.$emit('left-check-change', val, movedKeys); 193 }, 194 195 onTargetCheckedChange(val, movedKeys) { 196 this.rightChecked = val; 197 if (movedKeys === undefined) return; 198 this.$emit('right-check-change', val, movedKeys); 199 }, 200 201 addToLeft() { 202 let currentValue = this.value.slice(); 203 this.rightChecked.forEach(item => { 204 const index = currentValue.indexOf(item); 205 if (index > -1) { 206 currentValue.splice(index, 1); 207 } 208 }); 209 this.$emit('input', currentValue); 210 this.$emit('change', currentValue, 'left', this.rightChecked); 211 }, 212 213 addToRight() { 214 let currentValue = this.value.slice(); 215 const itemsToBeMoved = []; 216 const key = this.props.key; 217 this.data.forEach(item => { 218 const itemKey = item[key]; 219 if ( 220 this.leftChecked.indexOf(itemKey) > -1 && 221 this.value.indexOf(itemKey) === -1 222 ) { 223 itemsToBeMoved.push(itemKey); 224 } 225 }); 226 currentValue = this.targetOrder === 'unshift' 227 ? itemsToBeMoved.concat(currentValue) 228 : currentValue.concat(itemsToBeMoved); 229 this.$emit('input', currentValue); 230 this.$emit('change', currentValue, 'right', this.leftChecked); 231 }, 232 toUp() { 233 let currentValue = this.value.slice(); 234 let index = currentValue.indexOf(this.rightChecked[0]); 235 currentValue = this.upRecord(currentValue, index); 236 this.$emit('input', currentValue); 237 this.$emit('change', currentValue, 'right'); 238 }, 239 toDown() { 240 let currentValue = this.value.slice(); 241 let index = currentValue.indexOf(this.rightChecked[0]); 242 currentValue = this.downRecord(currentValue, index); 243 this.$emit('input', currentValue); 244 this.$emit('change', currentValue, 'right'); 245 }, 246 247 clearQuery(which) { 248 if (which === 'left') { 249 this.$refs.leftPanel.query = ''; 250 } else if (which === 'right') { 251 this.$refs.rightPanel.query = ''; 252 } 253 }, 254 255 swapItems(arr, index1, index2) { 256 arr[index1] = arr.splice(index2, 1, arr[index1])[0]; 257 return arr; 258 }, 259 260 upRecord(arr, $index) { 261 if ($index === 0) { 262 return arr; 263 } 264 return this.swapItems(arr, $index, $index - 1); 265 }, 266 267 downRecord(arr, $index) { 268 if ($index === arr.length - 1) { 269 return arr; 270 } 271 return this.swapItems(arr, $index, $index + 1); 272 } 273 } 274 }; 275 </script>
packages\theme-chalk\src\transfer.scss
1 @import "mixins/mixins"; 2 @import "mixins/utils"; 3 @import "common/var"; 4 @import "input"; 5 @import "button"; 6 @import "checkbox"; 7 @import "checkbox-group"; 8 9 @include b(transfer) { 10 font-size: $--font-size-base; 11 12 @include e(buttons) { 13 display: inline-block; 14 vertical-align: middle; 15 padding: 0 30px; 16 } 17 18 @include e(button) { 19 display: block; 20 margin: 0 auto; 21 padding: 10px; 22 border-radius: 50%; 23 color: $--color-white; 24 background-color: $--color-primary; 25 font-size: 0; 26 27 @include when(with-texts) { 28 border-radius: $--border-radius-base; 29 } 30 31 @include when(disabled) { 32 border: $--border-base; 33 background-color: $--background-color-base; 34 color: $--color-text-placeholder; 35 36 &:hover { 37 border: $--border-base; 38 background-color: $--background-color-base; 39 color: $--color-text-placeholder; 40 } 41 } 42 43 &:first-child { 44 margin-bottom: 10px; 45 } 46 47 &:nth-child(2) { 48 margin: 0; 49 margin-bottom: 10px; 50 } 51 52 &:nth-child(3) { 53 margin: 0; 54 margin-bottom: 10px; 55 } 56 57 &:nth-child(4) { 58 margin: 0; 59 } 60 61 i, span { 62 font-size: 14px; 63 } 64 65 & [class*="el-icon-"] + span { 66 margin-left: 0; 67 } 68 } 69 } 70 71 @include b(transfer-panel) { 72 border: 1px solid $--transfer-border-color; 73 border-radius: $--transfer-border-radius; 74 overflow: hidden; 75 background: $--color-white; 76 display: inline-block; 77 vertical-align: middle; 78 width: $--transfer-panel-width; 79 max-height: 100%; 80 box-sizing: border-box; 81 position: relative; 82 83 @include e(body) { 84 height: $--transfer-panel-body-height; 85 86 @include when(with-footer) { 87 padding-bottom: $--transfer-panel-footer-height; 88 } 89 } 90 91 @include e(list) { 92 margin: 0; 93 padding: 6px 0; 94 list-style: none; 95 height: $--transfer-panel-body-height; 96 overflow: auto; 97 box-sizing: border-box; 98 99 @include when(filterable) { 100 height: #{$--transfer-panel-body-height - $--transfer-filter-height - 20px}; 101 padding-top: 0; 102 } 103 } 104 105 @include e(item) { 106 height: $--transfer-item-height; 107 line-height: $--transfer-item-height; 108 padding-left: 15px; 109 display: block; 110 111 & + .el-transfer-panel__item { 112 margin-left: 0; 113 } 114 115 &.el-checkbox { 116 color: $--color-text-regular; 117 } 118 119 &:hover { 120 color: $--color-primary; 121 } 122 123 &.el-checkbox .el-checkbox__label { 124 width: 100%; 125 @include utils-ellipsis; 126 display: block; 127 box-sizing: border-box; 128 padding-left: 24px; 129 line-height: $--transfer-item-height; 130 } 131 132 .el-checkbox__input { 133 position: absolute; 134 top: 8px; 135 } 136 } 137 138 @include e(filter) { 139 text-align: center; 140 margin: 15px; 141 box-sizing: border-box; 142 display: block; 143 width: auto; 144 145 .el-input__inner { 146 height: $--transfer-filter-height; 147 width: 100%; 148 font-size: 12px; 149 display: inline-block; 150 box-sizing: border-box; 151 border-radius: #{$--transfer-filter-height / 2}; 152 padding-right: 10px; 153 padding-left: 30px; 154 } 155 156 .el-input__icon { 157 margin-left: 5px; 158 } 159 160 .el-icon-circle-close { 161 cursor: pointer; 162 } 163 } 164 165 .el-transfer-panel__header { 166 height: $--transfer-panel-header-height; 167 line-height: $--transfer-panel-header-height; 168 background: $--transfer-panel-header-background; 169 margin: 0; 170 padding-left: 15px; 171 border-bottom: 1px solid $--transfer-border-color; 172 box-sizing: border-box; 173 color: $--color-black; 174 175 .el-checkbox { 176 display: block; 177 line-height: 40px; 178 179 .el-checkbox__label { 180 font-size: 16px; 181 color: $--color-text-primary; 182 font-weight: normal; 183 184 span { 185 position: absolute; 186 right: 15px; 187 color: $--color-text-secondary; 188 font-size: 12px; 189 font-weight: normal; 190 } 191 } 192 } 193 } 194 195 .el-transfer-panel__footer { 196 height: $--transfer-panel-footer-height; 197 background: $--color-white; 198 margin: 0; 199 padding: 0; 200 border-top: 1px solid $--transfer-border-color; 201 position: absolute; 202 bottom: 0; 203 left: 0; 204 width: 100%; 205 z-index: $--index-normal; 206 @include utils-vertical-center; 207 208 .el-checkbox { 209 padding-left: 20px; 210 color: $--color-text-regular; 211 } 212 } 213 214 .el-transfer-panel__empty { 215 margin: 0; 216 height: $--transfer-item-height; 217 line-height: $--transfer-item-height; 218 padding: 6px 15px 0; 219 color: $--color-text-secondary; 220 text-align: center; 221 } 222 223 .el-checkbox__label { 224 padding-left: 8px; 225 } 226 227 .el-checkbox__inner { 228 height: 14px; 229 width: 14px; 230 border-radius: 3px; 231 &::after { 232 height: 6px; 233 width: 3px; 234 left: 4px; 235 } 236 } 237 }
查看效果可以在examples\docs\zh-CN\transfer.md中修改后查看
修改第80行
<template>
<el-transfer v-model="value1" :data="data" target-order="push" :moveable=true></el-transfer>
</template>
项目打包: npm run dist (请注意代码书写规范,否则可能打包失败)
将打包生成的lib文件替换项目中的lib文件,这样我们就可以用了
因为element-ui官方暂时不提供这样的功能,所以只能自己修改,我已经把代码上传到github,地址:https://github.com/BuNuo/element
如有错误,请指正