element 自定义处理transfer穿梭框
element
A Vue.js 2.0 UI Toolkit for Web
项目地址:https://gitcode.com/gh_mirrors/eleme/element
免费下载资源
·
根据项目需求需要实现可以单选进行选择,并且点击左侧的时候自动添加到右侧中去,代码呈上
传入的参数:isradio=true时为单选模式只能从左侧选一个,为false的时候可进行多选
主页面:(可以通过修改属性data和value存储到vuex中做到选完重新刷新浏览器选过的数据也不会重置,可以通过axios初始化数据的时候进行默认数据设置)(data为总数组即左侧区域的数组,value为右侧的数组)
<template>
<section class="main-content">
<div class="container infor_wrap">
<dir-transfer
filterable
:filter-method="filterMethod"
filter-placeholder="请输入要选择的企业名称"
v-model="value"
:data="dataList"
:titles="['未选择企业', '已选择企业']"
:isradio='true'></dir-transfer>
<el-button-group class="pageBtn">
<el-button size='small' type="primary" @click="prev" icon="el-icon-caret-left">上一步</el-button>
<el-button size='small' type="primary" @click="next" >下一步<i class="el-icon-caret-right el-icon--right"></i></el-button>
</el-button-group>
</div>
</section>
</template>
<script>
import DirTransfer from './transfermain.vue'
export default {
name:'ChooseCompany',
data() {
const generateData = _ => {
const dataList = [];
const company = ['百度', '阿里巴巴', '腾讯', '滴滴', '美团', '饿了么', '阿里巴巴', '腾讯', '滴滴', '美团', '饿了么', '阿里巴巴', '腾讯', '滴滴', '美团', '饿了么', '阿里巴巴', '腾讯', '滴滴', '美团', '饿了么', '阿里巴巴', '腾讯', '滴滴', '美团', '饿了么', '阿里巴巴', '腾讯', '滴滴', '美团', '饿了么', '阿里巴巴', '腾讯', '滴滴', '美团', '饿了么', '阿里巴巴', '腾讯', '滴滴', '美团', '饿了么', '阿里巴巴', '腾讯', '滴滴', '美团', '饿了么', '阿里巴巴', '腾讯', '滴滴', '美团', '饿了么', '阿里巴巴', '腾讯', '滴滴', '美团', '饿了么', '阿里巴巴', '腾讯', '滴滴', '美团', '饿了么'];
company.forEach((city, index) => {
dataList.push({
label: city,
key: index,
company: company[index]
});
});
return dataList;
};
return {
dataList: generateData(),
value: [1],
filterMethod(query, item) {
return item.company.indexOf(query) > -1;
}
};
},
components:{DirTransfer}
}
</script>
<style lang="scss" scoped>
.main-content{
height: calc(100% - 82px);
}
.infor_wrap{
height: calc(100% - 84px);
/deep/ .el-transfer{
height: calc(100% - 100px);
display: flex;
justify-content: center;
align-items: center;
}
/deep/ .el-transfer-panel{
width:320px;
height: 100%;
}
/deep/ .el-transfer-panel__body{
height: calc(100% - 40px);
}
/deep/ .el-transfer-panel__filter{
margin: 0 15px;
}
/deep/ .el-transfer-panel .el-transfer-panel__header{
margin-bottom: 10px;
}
/deep/ .el-transfer-panel__list.is-filterable{
margin-top: 10px;
height: calc(100% - 76px);
}
}
</style>
transfermain.vue
<template>
<div class="el-transfer">
<transfer-panel
v-bind="$props"
ref="leftPanel"
:filterable="true"
:data="sourceData"
:title="titles[0] || t('el.transfer.titles.0')"
:placeholder="filterPlaceholder || t('el.transfer.filterPlaceholder')"
:default-checked="leftDefaultChecked"
@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="allToLeft">
<span>左全选</span>此处本人更改为自己所需按钮,按钮事件名字也从addToLeft改为allToLeft
</el-button>
<el-button
type="primary"
:class="['el-transfer__button', hasButtonTexts ? 'is-with-texts' : '']"
@click.native="allToRight">
<span>右全选</span>此处本人更改为自己所需按钮,按钮事件名字也从addToRight改为allToRight
</el-button>
</div> -->
<transfer-panel
v-bind="$props"
:filterable="false"
:isRight="true"
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 './transferPanel.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'
},
isradio:{
type:Boolean,
default:false
}
},
data() {
return {
leftChecked: [],
rightChecked: [],
checkedleft:true,
checkedright:false
};
},
created(){
this.loadLeftDisabled()//初始化右侧有数据则左侧判断时候需要禁止点击
},
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 === 2;
}
},
watch: {
targetData(){//监测右侧data的变化当右侧数据为1的时候触发
if(this.targetData.length === 1){
if(this.isradio){//传入的props中isradio为true,单选给左侧数据添加disabled
this.sourceData.forEach( (item,index) => {
item['disabled']=true
})
}
}else if(this.value.length === 0){//右侧数据为0时,左侧数据中的disabled删除掉,
if(this.isradio){
this.sourceData.forEach( (item,index) => {
delete item['disabled']
})
}
}
},
value(val) {
this.dispatch('ElFormItem', 'el.form.change', val);
}
},
methods: {
loadLeftDisabled() {
if(this.value.length === 1){
if(this.isradio){
this.sourceData.forEach( (item,index) => {
item['disabled']=true
})
}
}
},
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);
this.addToRight();//在此处直接把选中项添加到右边框,实现单击操作,而不需通过按钮再次操作
},
onTargetCheckedChange(val, movedKeys) {
this.rightChecked = val;
if (movedKeys === undefined) return;
this.$emit('right-check-change', val, movedKeys);
this.addToLeft();//在此处直接把选中项添加到左边框,实现单击操作,而不需通过按钮再次操作
},
allToLeft(){
this.$refs.leftPanel.handleAllCheckedChange(true);//直接出发全选事件,父组件调用子组件方法需要通过this.$refs.组件ref值.子组件方法名
},
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);
},
allToRight(){
this.$refs.rightPanel.handleAllCheckedChange(true);//直接出发全选事件,父组件调用子组件方法需要通过this.$refs.组件ref值.子组件方法名
},
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);
},
clearQuery(which) {
if (which === 'left') {
this.$refs.leftPanel.query = '';
} else if (which === 'right') {
this.$refs.rightPanel.query = '';
}
}
}
};
</script>
transferPge
<template>
<div class="el-transfer-panel">
<p class="el-transfer-panel__header">
<el-checkbox v-show="false"
v-model="allChecked"
@change="handleAllCheckedChange"
:indeterminate="isIndeterminate">
{{ title }}
<span>{{ checkedSummary }}</span>
</el-checkbox>
{{ title }}
</p>
<div :class="['el-transfer-panel__body', hasFooter ? 'is-with-footer' : '']">
<el-input
class="el-transfer-panel__filter"
v-model="query"
size="small"
:placeholder="placeholder"
@mouseenter.native="inputHover = true"
@mouseleave.native="inputHover = false"
v-if="filterable">
<i slot="prefix"
:class="['el-input__icon', 'el-icon-' + inputIcon]"
@click="clearQuery"
></i>
</el-input>
<el-checkbox-group
v-model="checked"
v-show="!hasNoMatch && data.length > 0"
:class="{ 'is-filterable': filterable }"
class="el-transfer-panel__list">
<el-checkbox
class="el-transfer-panel__item"
:label="item[keyProp]"
:disabled="item[disabledProp]"
:key="item[keyProp]"
v-for="item in filteredData">
<option-content :option="item"></option-content>
<span v-if="isRight" class="el-icon-remove-outline" style="float:right;margin:5px 10px 0 5px;width:20px;line-height:20px;text-align:center;height:20px;border-radius:50%;"></span>
</el-checkbox><!--此处加了个判断是否为右边框给其加上相应的关闭按钮,isRight通过属性值进行传入-->
</el-checkbox-group>
<p
class="el-transfer-panel__empty"
v-show="hasNoMatch">{{ t('el.transfer.noMatch') }}</p>
<p
class="el-transfer-panel__empty"
v-show="data.length === 0 && !hasNoMatch">{{ t('el.transfer.noData') }}</p>
</div>
<p class="el-transfer-panel__footer" v-if="hasFooter">
<slot></slot>
</p>
</div>
</template>
<script>
import ElCheckboxGroup from 'element-ui/packages/checkbox-group';
import ElCheckbox from 'element-ui/packages/checkbox';
import ElInput from 'element-ui/packages/input';
import Locale from 'element-ui/src/mixins/locale';
export default {
mixins: [Locale],
name: 'ElTransferPanel',
componentName: 'ElTransferPanel',
components: {
ElCheckboxGroup,
ElCheckbox,
ElInput,
OptionContent: {
props: {
option: Object
},
render(h) {
const getParent = vm => {
if (vm.$options.componentName === 'ElTransferPanel') {
return vm;
} else if (vm.$parent) {
return getParent(vm.$parent);
} else {
return vm;
}
};
const panel = getParent(this);
const transfer = panel.$parent || panel;
return panel.renderContent
? panel.renderContent(h, this.option)
: transfer.$scopedSlots.default
? transfer.$scopedSlots.default({ option: this.option })
: <span>{ this.option[panel.labelProp] || this.option[panel.keyProp] }</span>;
}
}
},
props: {
data: {
type: Array,
default() {
return [];
}
},
renderContent: Function,
placeholder: String,
title: String,
filterable: Boolean,
isRight:Boolean,
format: Object,
filterMethod: Function,
defaultChecked: Array,
props: Object
},
data() {
return {
checked: [],
allChecked: false,
query: '',
inputHover: false,
checkChangeByUser: true
};
},
watch: {
checked(val, oldVal) {
this.updateAllChecked();
if (this.checkChangeByUser) {
const movedKeys = val.concat(oldVal)
.filter(v => val.indexOf(v) === -1 || oldVal.indexOf(v) === -1);
this.$emit('checked-change', val, movedKeys);
} else {
this.$emit('checked-change', val);
this.checkChangeByUser = true;
}
},
data() {
const checked = [];
const filteredDataKeys = this.filteredData.map(item => item[this.keyProp]);
this.checked.forEach(item => {
if (filteredDataKeys.indexOf(item) > -1) {
checked.push(item);
}
});
this.checkChangeByUser = false;
this.checked = checked;
},
checkableData() {
this.updateAllChecked();
},
defaultChecked: {
immediate: true,
handler(val, oldVal) {
if (oldVal && val.length === oldVal.length &&
val.every(item => oldVal.indexOf(item) > -1)) return;
const checked = [];
const checkableDataKeys = this.checkableData.map(item => item[this.keyProp]);
val.forEach(item => {
if (checkableDataKeys.indexOf(item) > -1) {
checked.push(item);
}
});
this.checkChangeByUser = false;
this.checked = checked;
}
}
},
computed: {
filteredData() {
return this.data.filter(item => {
if (typeof this.filterMethod === 'function') {
return this.filterMethod(this.query, item);
} else {
const label = item[this.labelProp] || item[this.keyProp].toString();
return label.toLowerCase().indexOf(this.query.toLowerCase()) > -1;
}
});
},
checkableData() {
return this.filteredData.filter(item => !item[this.disabledProp]);
},
checkedSummary() {
const checkedLength = this.checked.length;
const dataLength = this.data.length;
const { noChecked, hasChecked } = this.format;
if (noChecked && hasChecked) {
return checkedLength > 0
? hasChecked.replace(/\${checked}/g, checkedLength).replace(/\${total}/g, dataLength)
: noChecked.replace(/\${total}/g, dataLength);
} else {
return `${ checkedLength }/${ dataLength }`;
}
},
isIndeterminate() {
const checkedLength = this.checked.length;
return checkedLength > 0 && checkedLength < this.checkableData.length;
},
hasNoMatch() {
return this.query.length > 0 && this.filteredData.length === 0;
},
inputIcon() {
return this.query.length > 0 && this.inputHover
? 'circle-close'
: 'search';
},
labelProp() {
return this.props.label || 'label';
},
keyProp() {
return this.props.key || 'key';
},
disabledProp() {
return this.props.disabled || 'disabled';
},
hasFooter() {
return !!this.$slots.default;
}
},
methods: {
updateAllChecked() {
const checkableDataKeys = this.checkableData.map(item => item[this.keyProp]);
this.allChecked = checkableDataKeys.length > 0 &&
checkableDataKeys.every(item => this.checked.indexOf(item) > -1);
},
handleAllCheckedChange(value) {
console.log("value",value);
this.checked = value
? this.checkableData.map(item => item[this.keyProp])
: [];
},
clearQuery() {
if (this.inputIcon === 'circle-close') {
this.query = '';
}
}
}
};
</script>
参考文章:https://blog.csdn.net/programarqin/article/details/81042546
GitHub 加速计划 / eleme / element
54.06 K
14.63 K
下载
A Vue.js 2.0 UI Toolkit for Web
最近提交(Master分支:3 个月前 )
c345bb45
7 个月前
a07f3a59
* Update transition.md
* Update table.md
* Update transition.md
* Update table.md
* Update transition.md
* Update table.md
* Update table.md
* Update transition.md
* Update popover.md 7 个月前
更多推荐
已为社区贡献3条内容
所有评论(0)