Update:2023-10-26
代码如下(.vue
文件):
<!--
* @FileDescription: 数组批量上移、下移
* @Date: 2023-10-16
* @LastEditTime: 2023-10-16
-->
<script setup lang="ts">
import { reactive } from 'vue';
import { useMessage } from 'src/common/hooks';
const { warn } = useMessage();
const state = reactive({
list: [
{
title: '1',
checked: false,
},
{
title: '2',
checked: false,
}, {
title: '3',
checked: false,
}, {
title: '4',
checked: false,
}, {
title: '5',
checked: false,
},
{
title: '6',
checked: false,
},
{
title: '7',
checked: false,
},
],
})
function bulkUp() {
const selected = state.list.filter(i => i.checked);
// console.log('selected=', selected);
if (selected.length === 0) return warn('请选择数据');
state.list = bulkUpContinue(selected, state.list, 'title');
// console.log('上移list', state.list);
}
/**
* @description 批量上移
* @param {any[]} selected 勾选的数据列表
* @param {any[]} target 当前数组列表
* @param {string} uniqueKey 唯一的key
* @return {any[]} 返回的新数组列表
*/
function bulkUpContinue(selected: any[], target: any[], uniqueKey: string) {
if (selected.length > 0) {
const item = selected[0];
const afterMoveList = upOne(item, target, uniqueKey);
if (selected.length > 1) {
const afterMoveSelected = selected.slice(1);
return bulkUpContinue(afterMoveSelected, afterMoveList, uniqueKey);
} else {
return afterMoveList;
}
} else {
return target;
}
}
/**
* @description 单个上移
* @param {any} checked 勾选的一条数据
* @param {any[]} target 当前数组列表
* @param {string} uniqueKey 唯一的key
* @return {any[]} 返回的新数组列表
*/
function upOne(checked: any, target: any[], uniqueKey: string) {
if (target.length === 0) {
return [];
} else {
const key = checked[uniqueKey];
// 勾选数据的下标
const index = target.findIndex(i => i[uniqueKey] === key);
// 勾选数据的前一个下标
const lastIndex = index === 0 ? target.length - 1 : index - 1;
const newList = [] as any[];
if (index === 0) {
let i = 0;
for (const item of target) {
if (i > 0) {
newList.push(item);
}
i = i + 1;
};
newList.push(target[0]);
} else {
let i = 0;
for (const item of target) {
if (i === lastIndex) {
newList.push(target[index]);
} else if (i === index) {
newList.push(target[lastIndex]);
} else {
newList.push(item);
}
i = i + 1;
}
}
return newList;
}
}
// function oneUp() {
// const selected = state.list.filter(i => i.checked);
// if (selected.length === 1) {
// const list = upOne(selected[0], state.list);
// state.list = list;
// console.log('list', list);
// } else {
// return;
// }
// }
// function oneDown() {
// const selected = state.list.filter(i => i.checked);
// if (selected.length === 1) {
// const list = downOne(selected[0], state.list, 'title');
// state.list = list;
// console.log('list', list);
// } else {
// return;
// }
// }
function batchDown() {
const selected = state.list.filter(i => i.checked);
// console.log('selected=', selected);
if (selected.length === 0) return warn('请选择数据');
state.list = batchDownContinue(selected, state.list, 'title');
// console.log('下移list', state.list);
}
/**
* @description 批量下移
* @param {any[]} selected 勾选的数据列表
* @param {any[]} target 当前数组列表
* @param {string} uniqueKey 唯一的key
* @return {any[]} 返回的新数组列表
*/
function batchDownContinue(selected: any[], target: any[], uniqueKey: string) {
if (selected.length > 0) {
const item = selected[selected.length - 1]; // 从最后一个开始
const afterMoveList = downOne(item, target, uniqueKey);
if (selected.length > 1) {
const afterMoveSelected = selected.slice(0, selected.length - 1);
return batchDownContinue(afterMoveSelected, afterMoveList, uniqueKey);
} else {
return afterMoveList;
}
} else {
return target;
}
}
/**
* @description 单个下移
* @param {any} checked 勾选的一条数据
* @param {any[]} target 当前数组列表
* @param {string} uniqueKey 唯一的key
* @return {any[]} 返回的新数组列表
*/
function downOne(checked: any, target: any[], uniqueKey: string) {
if (target.length === 0) {
return [];
} else {
const key = checked[uniqueKey];
// 勾选数据的下标
const index = target.findIndex(i => i[uniqueKey] === key);
// 勾选数据的后一个下标
const nextIndex = index === target.length - 1 ? 0 : index + 1;
const newList = [] as any[];
if (index === target.length - 1) {
newList.push(target[target.length - 1]);
let i = 0;
for (const item of target) {
if (i < target.length - 1) {
newList.push(item);
}
i = i + 1;
};
} else {
let i = 0;
for (const item of target) {
if (i === index) {
newList.push(target[nextIndex]);
} else if (i === nextIndex) {
newList.push(target[index]);
} else {
newList.push(item);
}
i = i + 1;
}
}
return newList;
}
}
</script>
<template>
<div>
<div>
<q-btn color="primary" label="批量上移" @click="bulkUp" />
<q-btn color="primary" label="批量下移" @click="batchDown" />
<!-- <q-btn color="primary" label="单个上移" @click="oneUp" /> -->
<!-- <q-btn color="primary" label="单个下移" @click="oneDown" /> -->
</div>
<div class="column">
<q-checkbox v-model="i.checked" :label="i.title" v-for="(i) in state.list" :key="i.title" />
</div>
</div>
</template>
<style lang="scss" scoped></style>
在线查看:https://codepen.io/hu-c-y/pen/vYQbLyz
数组
const state = {
list: [
{
name: '0',
checked: false,
},
{
name: '1',
checked: false,
},
{
name: '2',
checked: false,
},
{
name: '3',
checked: false,
},
{
name: '4',
checked: false,
},
{
name: '5',
checked: false,
},
{
name: '6',
checked: false,
},
{
name: '7',
checked: false,
},
] as any[],
};
注意:在原数组对象上新加了两个属性
delete
和index
。
上移
// 上移
function moveUp() {
const length = state.list.length;
let max: any = null;
let maxIndex = null;
for (let i = 0; i < length; i++) {
const item: any = state.list[i];
if (item.checked) {
item.index = theIndex(i - 1, length);
if (!isEmpty(max)) {
const newMax = max + 1;
state.list[maxIndex].index = newMax;
max = newMax;
if (state.list[0].checked && i === length - 1) {
state.list[maxIndex].index = 0;
}
} else {
state.list[item.index].index = i;
max = i;
maxIndex = item.index;
}
} else {
if (i < length - 1) {
item.index = i;
max = i;
maxIndex = i;
}
}
}
state.list.sort((a, b) => a.index - b.index);
}
下移
// 下移
function moveDown() {
let max: any = null;
let maxIndex = null;
const length = state.list.length;
for (let i = length - 1; i > -1; i--) {
const item: any = state.list[i];
if (item.checked) {
item.index = theIndex(i + 1, length);
if (!isEmpty(max)) {
const newMax = max - 1;
state.list[maxIndex].index = newMax;
max = newMax;
if (state.list[length - 1].checked && i === 0) {
state.list[maxIndex].index = length - 1;
}
} else {
state.list[item.index].index = i;
max = i;
maxIndex = item.index;
}
} else {
if (i > 0) {
item.index = i;
max = i;
maxIndex = i;
}
}
}
state.list.sort((a, b) => a.index - b.index);
}
置顶
// 置顶
function toTop() {
const list: any[] = state.list;
const selectedList = [] as any[];
for (let i = 0; i < list.length; i++) {
if (list[i].checked) {
selectedList.push(list[i]);
list[i].delete = true;
} else {
list[i].delete = false;
}
}
let _list = state.list.filter((item: any) => !item.delete);
_list.unshift(...selectedList);
state.list = _list;
}
置顶
// 置底
function toBottom() {
const list: any[] = state.list;
const selectedList = [] as any[];
for (let i = 0; i < list.length; i++) {
if (list[i].checked) {
selectedList.push(list[i]);
list[i].delete = true;
} else {
list[i].delete = false;
}
}
let _list = state.list.filter((item: any) => !item.delete);
_list.push(...selectedList);
state.list = _list;
}
utils
function theIndex(index: number, length: number) {
if (index < 0) {
return length - 1;
} else if (index > length - 1) {
return 0;
} else {
return index;
}
}
function isEmpty(data: any) {
if (data === '' || data === null || data === undefined) {
return true;
}
// [] {} 0 false/true
else {
const typeofs = Object.prototype.toString.call(data);
// 数组
if (typeofs === '[object Array]') {
if (data.length > 0) {
return false;
} else {
return true;
}
}
// 对象
else if (typeofs === '[object Object]') {
if (Object.keys(data).length > 0) {
return false;
} else {
return true;
}
} else {
// 不为空
return false;
}
}
}