element-ui 修改源码实践 --tranfer

2023-05-30,,

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(红色部分是我修改过的代码)

 <template>
<div class="el-transfer">
<transfer-panel
v-bind="$props"
ref="leftPanel"
:data="sourceData"
:title="titles[0] || t('el.transfer.titles.0')"
:default-checked="leftDefaultChecked"
:placeholder="filterPlaceholder || t('el.transfer.filterPlaceholder')"
@checked-change="onSourceCheckedChange">
<slot name="left-footer"></slot>
</transfer-panel>
<div class="el-transfer__buttons">
<el-button
type="primary"
:class="['el-transfer__button', hasButtonTexts ? 'is-with-texts' : '']"
@click.native="addToLeft"
:disabled="rightChecked.length === 0">
<i class="el-icon-arrow-left"></i>
<span v-if="buttonTexts[0] !== undefined">{{ buttonTexts[0] }}</span>
</el-button>
<el-button
type="primary"
:class="['el-transfer__button', hasButtonTexts ? 'is-with-texts' : '']"
@click.native="addToRight"
:disabled="leftChecked.length === 0">
<span v-if="buttonTexts[1] !== undefined">{{ buttonTexts[1] }}</span>
<i class="el-icon-arrow-right"></i>
</el-button>
<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>
</div>
<transfer-panel
v-bind="$props"
ref="rightPanel"
:data="targetData"
:title="titles[1] || t('el.transfer.titles.1')"
:default-checked="rightDefaultChecked"
:placeholder="filterPlaceholder || t('el.transfer.filterPlaceholder')"
@checked-change="onTargetCheckedChange">
<slot name="right-footer"></slot>
</transfer-panel>
</div>
</template> <script>
import ElButton from 'element-ui/packages/button';
import Emitter from 'element-ui/src/mixins/emitter';
import Locale from 'element-ui/src/mixins/locale';
import TransferPanel from './transfer-panel.vue';
import Migrating from 'element-ui/src/mixins/migrating'; export default {
name: 'ElTransfer', mixins: [Emitter, Locale, Migrating], components: {
TransferPanel,
ElButton
}, props: {
data: {
type: Array,
default() {
return [];
}
},
titles: {
type: Array,
default() {
return [];
}
},
buttonTexts: {
type: Array,
default() {
return [];
}
},
filterPlaceholder: {
type: String,
default: ''
},
filterMethod: Function,
leftDefaultChecked: {
type: Array,
default() {
return [];
}
},
rightDefaultChecked: {
type: Array,
default() {
return [];
}
},
renderContent: Function,
value: {
type: Array,
default() {
return [];
}
},
format: {
type: Object,
default() {
return {};
}
},
filterable: Boolean,
props: {
type: Object,
default() {
return {
label: 'label',
key: 'key',
disabled: 'disabled'
};
}
},
targetOrder: {
type: String,
default: 'original'
},
moveable: Boolean
}, data() {
return {
leftChecked: [],
rightChecked: []
};
}, computed: {
dataObj() {
const key = this.props.key;
return this.data.reduce((o, cur) => (o[cur[key]] = cur) && o, {});
}, sourceData() {
return this.data.filter(item => this.value.indexOf(item[this.props.key]) === -1);
}, targetData() {
return this.targetOrder === 'original'
? this.data.filter(item => this.value.indexOf(item[this.props.key]) > -1)
: this.value.map(key => this.dataObj[key]);
}, hasButtonTexts() {
return this.buttonTexts.length === 4;
}
}, watch: {
value(val) {
this.dispatch('ElFormItem', 'el.form.change', val);
}
}, methods: {
getMigratingConfig() {
return {
props: {
'footer-format': 'footer-format is renamed to format.'
}
};
}, onSourceCheckedChange(val, movedKeys) {
this.leftChecked = val;
if (movedKeys === undefined) return;
this.$emit('left-check-change', val, movedKeys);
}, onTargetCheckedChange(val, movedKeys) {
this.rightChecked = val;
if (movedKeys === undefined) return;
this.$emit('right-check-change', val, movedKeys);
}, addToLeft() {
let currentValue = this.value.slice();
this.rightChecked.forEach(item => {
const index = currentValue.indexOf(item);
if (index > -1) {
currentValue.splice(index, 1);
}
});
this.$emit('input', currentValue);
this.$emit('change', currentValue, 'left', this.rightChecked);
}, addToRight() {
let currentValue = this.value.slice();
const itemsToBeMoved = [];
const key = this.props.key;
this.data.forEach(item => {
const itemKey = item[key];
if (
this.leftChecked.indexOf(itemKey) > -1 &&
this.value.indexOf(itemKey) === -1
) {
itemsToBeMoved.push(itemKey);
}
});
currentValue = this.targetOrder === 'unshift'
? itemsToBeMoved.concat(currentValue)
: currentValue.concat(itemsToBeMoved);
this.$emit('input', currentValue);
this.$emit('change', currentValue, 'right', this.leftChecked);
},
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 }, clearQuery(which) {
if (which === 'left') {
this.$refs.leftPanel.query = '';
} else if (which === 'right') {
this.$refs.rightPanel.query = '';
}
}, 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 }
};
</script>

packages\theme-chalk\src\transfer.scss

 @import "mixins/mixins";
@import "mixins/utils";
@import "common/var";
@import "input";
@import "button";
@import "checkbox";
@import "checkbox-group"; @include b(transfer) {
font-size: $--font-size-base; @include e(buttons) {
display: inline-block;
vertical-align: middle;
padding: 0 30px;
} @include e(button) {
display: block;
margin: 0 auto;
padding: 10px;
border-radius: 50%;
color: $--color-white;
background-color: $--color-primary;
font-size: 0; @include when(with-texts) {
border-radius: $--border-radius-base;
} @include when(disabled) {
border: $--border-base;
background-color: $--background-color-base;
color: $--color-text-placeholder; &:hover {
border: $--border-base;
background-color: $--background-color-base;
color: $--color-text-placeholder;
}
} &:first-child {
margin-bottom: 10px;
} &: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 } i, span {
font-size: 14px;
} & [class*="el-icon-"] + span {
margin-left: 0;
}
}
} @include b(transfer-panel) {
border: 1px solid $--transfer-border-color;
border-radius: $--transfer-border-radius;
overflow: hidden;
background: $--color-white;
display: inline-block;
vertical-align: middle;
width: $--transfer-panel-width;
max-height: 100%;
box-sizing: border-box;
position: relative; @include e(body) {
height: $--transfer-panel-body-height; @include when(with-footer) {
padding-bottom: $--transfer-panel-footer-height;
}
} @include e(list) {
margin: 0;
padding: 6px 0;
list-style: none;
height: $--transfer-panel-body-height;
overflow: auto;
box-sizing: border-box; @include when(filterable) {
height: #{$--transfer-panel-body-height - $--transfer-filter-height - 20px};
padding-top: 0;
}
} @include e(item) {
height: $--transfer-item-height;
line-height: $--transfer-item-height;
padding-left: 15px;
display: block; & + .el-transfer-panel__item {
margin-left: 0;
} &.el-checkbox {
color: $--color-text-regular;
} &:hover {
color: $--color-primary;
} &.el-checkbox .el-checkbox__label {
width: 100%;
@include utils-ellipsis;
display: block;
box-sizing: border-box;
padding-left: 24px;
line-height: $--transfer-item-height;
} .el-checkbox__input {
position: absolute;
top: 8px;
}
} @include e(filter) {
text-align: center;
margin: 15px;
box-sizing: border-box;
display: block;
width: auto; .el-input__inner {
height: $--transfer-filter-height;
width: 100%;
font-size: 12px;
display: inline-block;
box-sizing: border-box;
border-radius: #{$--transfer-filter-height / 2};
padding-right: 10px;
padding-left: 30px;
} .el-input__icon {
margin-left: 5px;
} .el-icon-circle-close {
cursor: pointer;
}
} .el-transfer-panel__header {
height: $--transfer-panel-header-height;
line-height: $--transfer-panel-header-height;
background: $--transfer-panel-header-background;
margin: 0;
padding-left: 15px;
border-bottom: 1px solid $--transfer-border-color;
box-sizing: border-box;
color: $--color-black; .el-checkbox {
display: block;
line-height: 40px; .el-checkbox__label {
font-size: 16px;
color: $--color-text-primary;
font-weight: normal; span {
position: absolute;
right: 15px;
color: $--color-text-secondary;
font-size: 12px;
font-weight: normal;
}
}
}
} .el-transfer-panel__footer {
height: $--transfer-panel-footer-height;
background: $--color-white;
margin: 0;
padding: 0;
border-top: 1px solid $--transfer-border-color;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
z-index: $--index-normal;
@include utils-vertical-center; .el-checkbox {
padding-left: 20px;
color: $--color-text-regular;
}
} .el-transfer-panel__empty {
margin: 0;
height: $--transfer-item-height;
line-height: $--transfer-item-height;
padding: 6px 15px 0;
color: $--color-text-secondary;
text-align: center;
} .el-checkbox__label {
padding-left: 8px;
} .el-checkbox__inner {
height: 14px;
width: 14px;
border-radius: 3px;
&::after {
height: 6px;
width: 3px;
left: 4px;
}
}
}

查看效果可以在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

如有错误,请指正

element-ui 修改源码实践 --tranfer的相关教程结束。

《element-ui 修改源码实践 --tranfer.doc》

下载本文的Word格式文档,以方便收藏与打印。