JS数组批量移动——批量上移、批量下移、置顶、置底

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[],
};

注意:在原数组对象上新加了两个属性deleteindex

上移

// 上移
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;
    }
  }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值