昨晚加班写的穿梭框组件,一边写一边遇到bug,果然只有bug才会让你印象更深刻,更值得记录
封装成组件FreezeTransfer
效果如下:
主要参考了官网上可搜索的这个示例
先说遇到的bug,然后贴完整的代码
1、el-transfer数据源绑定之后不展示,filterMethod不对的原因
2、点单个复选框,所有项都被选中,数据被处理后,不需要再 使用props转换
:props=“{
key: ‘id’,
label: ‘cnName’
}”
转换
3、未选择的时候,中间按钮的左右箭头不显示
4、行没有占全
5、每次打开弹窗的时候,初始化
6、change事件的使用
7、清空某个面板的搜索关键词
1、先说第一个绑数据源,按官网给的示例,这个和treeselect的示例差不多,需要将格式转换成它要求的格式
正常从接口获取数据就行,我这里是组件,所以在父页面获取到之后,传到子组件就行,在子组件里监听数据源,处理数据之后给treansfer绑定的data
dataSource: {
handler(newVal) {
this.source = newVal.map(item => {
let obj = {
key: item.code,
code: item.code,
label: item.cnName,
disabled: false,
}
return obj
})
this.$emit('getCode', [])
},
deep: true,
immediate: true,
},
这里遇到的bug就是左侧的数据源已经有了,但就是什么都不展示,一片空白
这个坑就是filter-method引起的,因为我是可搜索的穿梭框,从官方示例拿过来的时候,先定义了这个方法,但是啥都没写,真的是不踩一下根本不知道这还会影响数据源的展示
:filter-method="filterMethod"
filterMethod(query, item) {
//模糊查询,不区分英文大小写
return item.key.toUpperCase().indexOf(query.toUpperCase()) > -1 || item.label.indexOf(query) > -1
},
2、点单个复选框,所有项都被选中,可能的原因就是id都绑了一样的,但我排查了不是这个原因,这也是个坑,就是数据源处理过了之后,不需要再写props转换了
不需要
:props="{
key: 'id',
label: 'cnName'
}"
3、未选择的时候,中间按钮的左右箭头不显示
官网未选择的时候
我这里没有中间的箭头,可能是样式受影响了
/deep/ .el-button.el-button--primary.is-disabled {
color: #fff !important;
}
4、行没有占全
/deep/ .el-transfer-panel__item.el-checkbox {
width: 100%;
}
5、每次打开弹窗的时候,初始化
因为是放在弹窗中展示的,每次打开弹窗要初始化数据
父组件上定义initTransarr数组,在确认及取消事件中置为空
:initTransarr="initTransarr"
initTransarr:[]
/** 弹框确认取消 */
dialogSure(flag) {
if (flag === 'sure') {
this.$emit('handleSure', this.custCodearr)
}
} else {
this.$emit('handleCancel')
}
this.initTransarr = []
this.$emit('update:visible', false)
},
6、change事件的使用
这里说下,left-check-change和right-check-change,分别在左侧和右侧勾选复选框的时候触发,我这里因为需求的调整,没用到,但还是保留了
change事件三个参数,当前值、数据移动的方向(‘left’ / ‘right’)、发生移动的数据 key 数组,就是中间左右箭头的事件
7、清空某个面板的搜索关键词
父组件
<FreezeTransfer
v-if="isTransfer"
ref="freezeTransfer"
:visible="visible"
:dataSource="dataSource"
:initTransarr="initTransarr"
@getCode="getCode"
></FreezeTransfer>
data() {
return {
visible:false,
custCodearr: [],
initTransarr: [],
}
},
getCode(arr) {
this.custCodearr = arr
},
/** 弹框确认取消 */
dialogSure(flag) {
if (flag === 'sure') {
this.$emit('handleSure', this.custCodearr)
}
} else {
this.$emit('handleCancel')
}
this.initTransarr = []
this.$emit('update:visible', false)
},
子组件
<template>
<div class="transfer">
<el-transfer
v-if="visible"
ref="transfer"
filterable
:filter-method="filterMethod"
:filter-placeholder="$t('placeholderName.enter')"
v-model="value"
:data="source"
:titles="['可选择', '已选择']"
@change="handleChange"
@left-check-change="leftcheckChange($event)"
@right-check-change="rightcheckChange($event)"
>
<span slot-scope="{ option }">{{ option.code }} - {{ option.label }}</span>
</el-transfer>
</div>
</template>
<script>
export default {
name: 'FreezeTransfer',
props: {
// 列表显示隐藏
visible: {
type: Boolean,
default: false,
},
// 列表数据
dataSource: {
type: Array,
default: () => {
return []
},
},
// 初始化右侧数据
initTransarr: {
type: Array,
default: () => {
return []
},
},
},
data() {
return {
source: [], // 总数据
value: [],
}
},
watch: {
initTransarr: {
handler(newVal) {
this.value = newVal
},
deep: true,
},
dataSource: {
handler(newVal) {
this.source = newVal.map(item => {
let obj = {
key: item.code,
code: item.code,
label: item.cnName,
disabled: false,
}
return obj
})
this.$emit('getCode', [])
},
deep: true,
immediate: true,
},
},
mounted() {},
methods: {
filterMethod(query, item) {
return item.key.toUpperCase().indexOf(query.toUpperCase()) > -1 || item.label.indexOf(query) > -1
},
//当前值、数据移动的方向('left' / 'right')、发生移动的数据 key 数组
handleChange(value, direction, movedKeys) {
if (direction == 'right') {
this.$nextTick(() => {
this.$refs.transfer.clearQuery('left')
})
} else if (direction == 'left') {
this.$nextTick(() => {
this.$refs.transfer.clearQuery('right')
})
}
var arr = []
value.forEach(item => {
arr.push({ code: item })
})
this.$emit('getCode', arr)
},
leftcheckChange(e) {
// console.log(e,'left------');
},
rightcheckChange(e) {
// console.log(e,'right------');
},
},
}
</script>
<style scoped lang="scss">
.transfer {
width: 100%;
/deep/ .el-transfer-panel {
width: 45%;
}
}
/deep/ .el-button.el-button--primary.is-disabled {
color: #fff !important;
}
/deep/ .el-transfer-panel__item.el-checkbox {
width: 100%;
}
/deep/ .el-transfer-panel__list {
height: 480px !important;
}
/deep/ .el-transfer-panel__body {
height: 480px !important;
}
</style>