vue自定義穿梭框支持遠(yuǎn)程滾動加載的實現(xiàn)方法
*分享一個使用比較久的??
技術(shù)框架公司的選型(老項目):vue2 + iview-ui方案的實現(xiàn)思路是共性的,展現(xiàn)UI樣式需要你們自定義進行更改;因為iview是全局注入,基本使用原先的類名進行二次創(chuàng)建公共組件,修改基礎(chǔ)js實現(xiàn)邏輯;
需求分析:實現(xiàn)遠(yuǎn)程滾動加載數(shù)據(jù)的穿梭框
1、創(chuàng)建自定義穿梭框,分左側(cè)和右側(cè)數(shù)據(jù)
2、依賴后端接口,左側(cè)是左側(cè)數(shù)據(jù),右側(cè)是右側(cè)數(shù)據(jù)
3、定義好出入?yún)?shù),支持回顯內(nèi)容及選中內(nèi)容的去重處理
4、綁定對應(yīng)的v-model數(shù)據(jù)響應(yīng)
5、滾動加載數(shù)據(jù),區(qū)分左右區(qū)域;添加自定義指令進行監(jiān)聽
6、滾動加載數(shù)據(jù),不丟失已選中的數(shù)據(jù),或去重已選中數(shù)據(jù)
7、支持左右側(cè)的遠(yuǎn)程搜索功能,左右互不影響,檢索數(shù)據(jù)放組件外部進行

1、代碼信息
創(chuàng)建ivu-transfer.vue文件;依賴iviewUI請依據(jù)自己的樣式進行拷貝;
1.1 自定義滾動監(jiān)聽指令
/** 遠(yuǎn)程滾動加載 */
import Vue from 'vue'
Vue.directive("loadTransfer", {
bind(el, binding) {
const select_dom = el.querySelectorAll('.ivu-transfer-list .ivu-transfer-list-content');
select_dom.forEach((item, index) => {
item.addEventListener('scroll', function () {
const height = this.scrollHeight - this.scrollTop - 1 <= this.clientHeight;
if (height) {
binding.value(index)
}
})
})
}
})1.2 自定義穿梭框代碼
<template>
<div class="ivu-transfer">
<div
class="ivu-transfer-list"
:style="{
width: listStyle.width,
height: listStyle.height
}"
>
<div class="ivu-transfer-list-header">
<Checkbox
:value="checkLeftAll"
@on-change="handleAllLeftCheck"
></Checkbox>
<span class="ivu-transfer-list-header-title">源列表</span>
<span class="ivu-transfer-list-header-count">
{{ leftDataSource.length }}
</span>
</div>
<div class="ivu-transfer-list-body">
<div class="ivu-transfer-list-content">
<CheckboxGroup v-model="checkLeftAllGroup">
<Checkbox
:key="index"
:label="item.value"
class="ivu-transfer-list-content-item"
v-for="(item, index) in leftDataSource"
>{{
item.label +
`${item.description ? ` - ${item.description}` : ""}`
}}</Checkbox
>
</CheckboxGroup>
<div
v-if="!leftDataSource.length"
class="ivu-transfer-list-content-not-found"
>
列表為空
</div>
</div>
</div>
</div>
<div class="ivu-transfer-operation">
<Button
size="small"
type="primary"
icon="ios-arrow-back"
@click="handleClickArrowBack"
:disabled="!checkRightAllGroup.length"
></Button>
<Button
size="small"
type="primary"
icon="ios-arrow-forward"
@click="handleClickArrowForward"
:disabled="!checkLeftAllGroup.length"
></Button>
</div>
<div
class="ivu-transfer-list"
:style="{
width: listStyle.width,
height: listStyle.height
}"
>
<div class="ivu-transfer-list-header">
<Checkbox
:value="checkRightAll"
@on-change="handleAllRightCheck"
></Checkbox>
<span class="ivu-transfer-list-header-title">目的列表</span>
<span class="ivu-transfer-list-header-count">
{{ rightDataSource.length }}
</span>
</div>
<div class="ivu-transfer-list-body">
<div class="ivu-transfer-list-content">
<CheckboxGroup v-model="checkRightAllGroup">
<Checkbox
:key="index"
:label="item.value"
class="ivu-transfer-list-content-item"
v-for="(item, index) in rightDataSource"
>{{
item.label +
`${item.description ? ` - ${item.description}` : ""}`
}}
</Checkbox>
</CheckboxGroup>
<div
v-if="!rightDataSource.length"
class="ivu-transfer-list-content-not-found"
>
列表為空
</div>
</div>
</div>
</div>
</div>
</template>
<script>
const methods = {
// 點擊左側(cè)全選
handleAllLeftCheck() {
this.checkLeftAll = !this.checkLeftAll;
if (this.checkLeftAll) {
this.checkLeftAllGroup = this.leftDataSource.map(item => item.value);
} else {
this.checkLeftAllGroup = [];
}
},
// 點擊右側(cè)全選
handleAllRightCheck() {
this.checkRightAll = !this.checkRightAll;
if (this.checkRightAll) {
this.checkRightAllGroup = this.rightDataSource.map(item => item.value);
} else {
this.checkRightAllGroup = [];
}
},
// 點擊向右數(shù)據(jù)
handleClickArrowBack() {
this.moveCheckedData("left");
},
// 點擊向左數(shù)據(jù)
handleClickArrowForward() {
this.moveCheckedData("right");
},
moveCheckedData(direction) {
const newLeftDataSource = [];
const newRightDataSource = [];
const dataSource =
direction === "left" ? this.rightDataSource : this.leftDataSource;
dataSource.forEach(item => {
const index =
direction === "left"
? this.checkRightAllGroup.indexOf(item.value)
: this.checkLeftAllGroup.indexOf(item.value);
if (index !== -1) {
direction === "left"
? newLeftDataSource.push(item)
: newRightDataSource.push(item);
} else {
direction === "left"
? newRightDataSource.push(item)
: newLeftDataSource.push(item);
}
});
this.leftDataSource =
direction === "left"
? [...this.leftDataSource, ...newLeftDataSource]
: newLeftDataSource;
this.rightDataSource =
direction === "left"
? newRightDataSource
: [...this.rightDataSource, ...newRightDataSource];
this.checkLeftAll = false;
this.checkRightAll = false;
this.checkLeftAllGroup = [];
this.checkRightAllGroup = [];
this.$emit("on-change", this.leftDataSource, this.rightDataSource, direction);
},
filterDataMethods() {
const rightValues = new Set(this.rightDataSource.map(opt => opt.value));
this.leftDataSource = this.leftDataSource.filter(
item => !rightValues.has(item.value)
);
this.$nextTick(() => {
const leftValues = new Set(this.leftDataSource.map(opt => opt.value));
this.rightDataSource = this.rightDataSource.filter(
opt => !leftValues.has(opt.value)
);
});
}
};
export default {
props: {
listStyle: {
type: Object,
default: () => ({
width: "250px",
height: "380px"
})
},
leftData: {
type: Array,
require: true,
default: () => []
},
rightData: {
type: Array,
require: true,
default: () => []
}
},
data() {
return {
checkLeftAll: false,
checkRightAll: false,
checkRightAllGroup: [],
checkLeftAllGroup: [],
leftDataSource: [],
rightDataSource: []
};
},
watch: {
leftData(newVal) {
this.leftDataSource = newVal;
this.filterDataMethods();
},
rightData(newVal) {
this.rightDataSource = newVal || [];
this.filterDataMethods();
}
},
mounted() {
this.$nextTick(() => {
this.$emit("on-change", this.leftDataSource, this.rightDataSource);
})
},
methods
};
</script>
<style lang="less" scoped>
.ivu-transfer-list-content-item {
width: 100%;
margin-left: -0.3em;
}
.ivu-transfer-list-content-not-found {
display: block;
}
</style>2、內(nèi)容使用api介紹
1、樹形結(jié)構(gòu)入?yún)ⅲ篸ataSource=[{label: '測試',value: 1, description: '拼接內(nèi)容' }],
2、標(biāo)簽引用:<IvuTransfer :leftData="dataSource" :rightData="targetKeys" @on-change="handleChange" v-loadTransfer="handleLoadMore" />
3、相關(guān)api說明文檔在文章底部
<template>
<div class="customSearch">
<Input
search
clearable
v-model="formLeftInput"
placeholder="請輸入搜索內(nèi)容"
@on-clear="handleOnLeftInput"
@on-search="handleOnLeftInput"
/>
<div style="width: 50px"></div>
<Input
search
clearable
v-model="formRightInput"
placeholder="請輸入搜索內(nèi)容"
@on-clear="handleOnRightInput"
@on-search="handleOnRightInput"
/>
</div>
<IvuTransfer
:leftData="dataSource"
:rightData="targetKeys"
@on-change="handleChange"
v-loadTransfer="handleLoadMore"
/>
</template>
// 遠(yuǎn)程滾動加載
handleLoadMore(index) {
if (index === 0 && this.dataLeftHasMore && !this.isShowLoading) {
this.curLeftPage++;
this.getLeftMockData();
}
if (index === 1 && this.dataRightHasMore && !this.rightLoading) {
this.curRightPage++;
this.getRightTargetKeys();
}
},
// 觸發(fā)選中移動
handleChange(newLeftTargetData, newRightTargetKeys, direction) {
this.dataSource = [...newLeftTargetData];
this.targetKeys = [...newRightTargetKeys];
if (direction === "right") {
return this.remoteCheckPage();
}
if (direction === "left") {
return this.remoteRightCheckPage();
}
},
getLeftData() {},
getRightData() {}| 參數(shù) | 說明 | 類型 | 默認(rèn)值 | 必填項 |
|---|---|---|---|---|
| leftData | [{}]-label,value結(jié)構(gòu) | Array[] | [] | 是 |
| rightData | [{}]-label,value結(jié)構(gòu) | Array[] | [] | 是 |
| on-change | 數(shù)據(jù)變更觸發(fā) | newLeft,newRight, direction | 無 | 否 |
到此這篇關(guān)于vue自定義穿梭框支持遠(yuǎn)程滾動加載的文章就介紹到這了,更多相關(guān)vue遠(yuǎn)程滾動加載內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue.Draggable使用文檔超詳細(xì)總結(jié)
Vue拖拽組件(Draggable)是一個允許與View-Model同步進行拖放排序的Vue組件,下面這篇文章主要給大家介紹了關(guān)于Vue.Draggable使用文檔的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08

