vue3.x + elementPlus 封装组件之transfer 穿梭框
vue3.x + elementPlus 封装组件之transfer 穿梭框,可拖拽换位
·
老规矩----前面文章的步骤创建文件导入js等
封装代码
<template>
<!-- target-order="unshift"必须设置,如果不设置的话后台穿的value值得顺序会被data重置 - -->
<el-transfer
:id="idDom"
target-order="unshift"
style="text-align: left; display: inline-block"
:model-value="transferData.value"
filterable
:filter-method="transferData.menuFilterMethod"
:left-default-checked="leftChecked"
:right-default-checked="rightChecked"
:render-content="renderFunc"
:titles="titles"
:button-texts="buttonTexts"
:format="{
noChecked: '${total}',
hasChecked: '${checked}/${total}',
}"
:data="dataListT"
@change="handleChange"
@left-check-change="leftCheckChange"
@right-check-change="rightCheckChange"
>
<template #default="{ option }">
<span
class="item"
@dragstart="drag($event, option)"
>{{ option.label || option.title }}</span>
<!-- {{ option.key }} - -->
</template>
<template #left-footer>
<el-tooltip
class="box-item"
effect="dark"
content="返回左边勾选中的数据"
placement="top"
>
<el-button class="transfer-footer btn-mixins el-button-s" size="small" @click.stop="saveLeft">确定</el-button>
</el-tooltip>
</template>
<template #right-footer>
<el-tooltip
class="box-item"
effect="dark"
content="返回右边勾选中的数据"
placement="top"
>
<el-button class="transfer-footer btn-mixins el-button-s" size="small" @click.stop="saveRight">确定</el-button>
</el-tooltip>
</template>
</el-transfer>
</template>
<script>
import Sortable from 'sortablejs'
import { reactive, ref, onMounted } from 'vue'
const transferData = reactive({
value: [], // 默认选中的个数索引
draggingKey: '', // 拖动的数据
menuFilterMethod(query, item) {
// return item.menuListdata.indexOf(query) > -1
const regStr = query.replace(/\*/g, '.*')
const reg = new RegExp(regStr)
return reg.test(item.label)
}
})
// 默认数据测试展示
const generateData = (_) => {
const data = []
for (let i = 1; i <= 15; i++) {
data.push({
key: i,
label: `备选项 ${i}`,
disabled: i % 4 === 0
})
}
return data
}
// 数据初始化和拖拽初始化
const initEffect = (props, ctx) => {
let dataListT = props.dataList.length ? props.dataList : generateData()
const init = () => {
// const transferRef = document.getElementById(props.idDom)
const transfer = document.getElementById(props.idDom)
const leftPanel = transfer.getElementsByClassName('el-transfer-panel')[0].getElementsByClassName('el-transfer-panel__body')[0]
const rightPanel = transfer.getElementsByClassName('el-transfer-panel')[1].getElementsByClassName('el-transfer-panel__body')[0]
const rightEl = rightPanel.getElementsByClassName('el-transfer-panel__list')[0]
Sortable.create(rightEl, {
animation: 100,
onEnd: (evt) => {
const { oldIndex, newIndex } = evt
const temp = transferData.value[oldIndex]
if (!temp || temp === 'undefined') {
return
} // 解决右边最后一项从右边拖左边,有undefined的问题 //这里和网上的有点不一样,网上搜到的结果排序是,当前拖拽的元素和拖拽位置的元素互换位置,但是实际上在使用el-transfer有两个问题 //1.右侧排序value的数组顺序来源于后台穿的数组顺序,实际如果不设置target-order="unshift"的话,展示会按照左侧的数据列顺序展示,导致拖拽排序时顺序乱七八糟 //2.实际拖拽排序看到的效果是当前拖拽元素拖拽到其他地方,其他地方的元素会下移,而不是调换顺序
// 去除空字符串
for (var i = 0; i < transferData.value.length; i++) {
if (
transferData.value[i] === '' ||
transferData.value[i] === null ||
typeof transferData.value[i] === 'undefined'
) {
transferData.value.splice(i, 1)
i = i - 1
}
}
const arr_temp = [].concat(transferData.value) // 创建一个新的临时数组,用以操作后不变更原数组
arr_temp.splice(newIndex, 0, arr_temp.splice(oldIndex, 1)[0]) // 在b位置插入从a位置截取的元素
transferData.value = arr_temp
ctx.emit('update:call-back', transferData.value)
}
})
const leftEl = leftPanel.getElementsByClassName('el-transfer-panel__list')[0]
Sortable.create(leftEl, {
animation: 100,
onEnd: (evt) => {
const { oldIndex, newIndex } = evt
dataListT.splice(newIndex, 0, dataListT.splice(oldIndex, 1)[0])
// 保存的新的数组用于数据渲染
const newArray = dataListT.slice(0)
dataListT = newArray
}
})
leftPanel.ondragover = (ev) => {
ev.preventDefault()
}
leftPanel.ondrop = (ev) => {
ev.preventDefault()
const index = transferData.value.indexOf(transferData.draggingKey)
if (index !== -1) {
transferData.value.splice(index, 1)
}
}
rightPanel.ondragover = (ev) => {
ev.preventDefault()
}
rightPanel.ondrop = (ev) => {
ev.preventDefault()
if (transferData.value.indexOf(transferData.draggingKey) === -1) {
transferData.value.push(transferData.draggingKey)
}
}
}
return { init, dataListT }
}
// 左边确定按钮 把左边默认展示的传递过去
const leftBtnEffect = (props, ctx) => {
const leftDataChecked = ref([])
leftDataChecked.value = props.leftChecked
// props.leftChecked.forEach(e => {
// if (!e.disabled) {
// leftDataChecked.value.push(e)
// }
// })
const leftCheckChange = (value) => {
// console.log(value)
leftDataChecked.value = value
}
// console.log(leftDataChecked.value)
// 左侧确定事件
const saveLeft = () => {
ctx.emit('changeTransferLeft', leftDataChecked)
}
return { leftDataChecked, leftCheckChange, saveLeft }
}
// 右边确定按钮 把右边默认展示的传递过去
const rightBtnEffect = (props, ctx) => {
const rightDataChecked = ref([])
rightDataChecked.value = props.rightChecked
// props.rightChecked.forEach(e => {
// if (!e.disabled) {
// rightDataChecked.value.push(e)
// }
// })
const rightCheckChange = (value) => {
// console.log(value)
rightDataChecked.value = value
}
// 右侧确定事件
const saveRight = () => {
ctx.emit('changeTransferRight', rightDataChecked)
}
return { rightDataChecked, rightCheckChange, saveRight }
}
export default {
props: {
value: {
type: Array,
default() {
return []
}
},
// 按钮文字
idDom: {
default() {
return 'transfer'
},
type: String
},
// 按钮文字
buttonTexts: {
default() {
return []
},
type: Array
},
// 数据
dataList: {
default() {
return []
},
type: Array
},
leftChecked: {
default() {
return []
},
type: Array
},
rightChecked: {
default() {
return []
},
type: Array
},
// 标题
titles: {
default() {
return []
},
type: Array
}
},
emits: ['changeTransfer', 'changeTransferLeft', 'changeTransferRight'],
setup(props, ctx) {
const { init, dataListT } = initEffect(props, ctx)
const { leftCheckChange, saveLeft } = leftBtnEffect(props, ctx)
const { rightCheckChange, saveRight } = rightBtnEffect(props, ctx)
// 数据加载完之后 再获取对应的id
onMounted(() => {
init()
})
const renderFunc = (h, option) => {
return h('span', null, option.label)
}
const handleChange = (value, direction, movedKeys) => {
ctx.emit('changeTransfer', value, direction, movedKeys)
}
const drag = (ev, option) => {
transferData.draggingKey = option.key
}
return { transferData, dataListT, handleChange, drag, leftCheckChange, saveLeft, rightCheckChange, saveRight, renderFunc }
}
}
</script>
<style lang="scss" >
.el-transfer__buttons {
.el-button:first-child {
margin-bottom: 8px;
}
}
</style>
使用
<template>
<div>
<LZTransfer
v-model="transferData.value"
:id-dom="transferData.transferId"
:button-texts="transferData.buttonTexts"
:left-checked="transferData.leftChecked"
:left-data-list="transferData.leftDataList"
:right-checked="transferData.rightChecked"
:right-data-list="transferData.rightDataList"
:titles="transferData.titles"
@changeTransfer="changeTransfer"
@changeTransferLeft="changeTransferLeft"
@changeTransferRight="changeTransferRight"
></LZTransfer>
</div>
<div>
<span>一个页面有两个穿梭框的展示和数据问题</span>
<LZTransfer
v-model="transferData2.value"
:data-list="transferData2.dataList"
:id-dom="transferData2.transferId2"
:button-texts="transferData2.buttonTexts"
:left-checked="transferData2.leftChecked"
:right-checked="transferData2.rightChecked"
:titles="transferData2.titles"
@changeTransfer="changeTransfer2"
@changeTransferLeft="changeTransferLeft2"
@changeTransferRight="changeTransferRight2"
></LZTransfer>
</div>
</template>
<script>
import { reactive } from 'vue'
const transferData = reactive({
// 默认右移动的数据
value: [2, 3],
// 箭头描述
buttonTexts: ['到左边', '到右边'],
// 左边默认选中
leftChecked: [1, 4],
// 右边默认选中
rightChecked: [2, 3],
// 每个穿梭框id
transferId: 'transferId1',
titles: ['左边标题', '右边标题'] // 自定义数据 里面必须要要label或者title 才能展示文字
})
const transferData2 = reactive({
value: [],
// 箭头描述
buttonTexts: ['到左边2', '到右边2'],
// 左边默认选中
leftChecked: [5, 4],
// 右边默认选中
rightChecked: [],
// 每个id
transferId2: 'transferId2',
titles: ['左边标题2', '右边标题2'],
// 自定义数据 里面必须要要label或者title 才能展示文字
dataList: [
{
disabled: false,
key: 1,
label: '备选项 11',
},
{
disabled: false,
key: 2,
label: '备选项 2',
},
{
disabled: false,
key: 3,
label: '备选项 3',
},
{
disabled: false,
key: 4,
label: '备选项 4',
},
{
disabled: false,
key: 5,
label: '备选项 5',
},
{
disabled: false,
key: 6,
label: '备选项 6',
},
{
disabled: false,
key: 7,
label: '备选项 7',
},
{
disabled: false,
key: 8,
label: '备选项 8',
},
{
disabled: false,
key: 9,
label: '备选项 9',
},
{
disabled: false,
key: 10,
label: '备选项 10',
},
{
disabled: false,
key: 11,
label: '备选项 11',
},
]
})
export default {
setup() {
// 当前移动的数据和方向 移动的key
const changeTransfer = (value, direction, movedKeys) => {
console.log(value, direction, movedKeys)
}
const changeTransferLeft = (list) => {
// 这里要通过.value拿到数据
console.log(list.value)
}
const changeTransferRight = (list) => {
console.log(list.value)
}
const changeTransfer2 = (value, direction, movedKeys) => {
console.log(value, direction, movedKeys)
}
const changeTransferLeft2 = (list) => {
console.log(list.value)
}
const changeTransferRight2 = (list) => {
console.log(list.value)
}
return { transferData, transferData2, changeTransfer, changeTransferLeft, changeTransferRight, changeTransfer2, changeTransferLeft2, changeTransferRight2 }
}
}
</script>
更多推荐
已为社区贡献4条内容
所有评论(0)