vue3如何使用js实现 有序数组 的复制,删除,上移,下移,置顶,置后的功能。

328 阅读8分钟

vue3如何使用js实现有序数组的复制,删除,上移,下移,置顶,置后的功能。

前言:

​ 前几天做项目的时候遇到的一个问题,在前端如何实现有序数组的复制,删除,上移,下移,最前,最后的功能。如果是一个无序的数组那么实现这些还是非常容易的,那么如果它是有序的实现这些功能就要考虑它的序列等问题。这其中也是涉及到了一些简单的算法和逻辑等问题,我觉得做完之后我受益很多,来和大家分享一下。

下面我来展示一下这个项目:

image-20230403103947287.png

1、复制

我们这边的复制是,当你点击了复制之后,会复制一个相同的题目到这个题目的下面,但是前面的序号要改变。

思路

​ 首先我们来整理一下思路:比如当我们点击了第二题的复制之后,会出现一个相同题目为自定义2的问题出现在这个第2题的下面。此时,这个复制的题目的题号应该+1为3,而原来在第一题之后的题号都要+1。所以我们的第三题的题目也变成了自定义2,原来的第三题也就是现在的第四题的题目变成了自定义3,如下图:

image-20230403104643512.png

那么应该怎么实现呢?

​ 首先我是把题目存在一个名为topicData的响应式数组里的。然后我们把我们先把想要复制的对象,存在一个空对象里面,并给它的questionOrder(题号)+1,然后我们将这个这个题目用splice的方法插入到原来选择的那个复制的题目的后面,最后我们循环遍历这个数组里的索引值,如果索引值大于我们复制并插入进数组的题目的题号(也就是这个题目在我们要复制并插入进数组的题目的后面)我们就让这个题目的题号+1。下面上完整代码:

const copy = (questionOrder: number)=>{
  const assign = Object.assign({}, topicData.value[questionOrder - 1]);
  assign.questionOrder=questionOrder+1
  topicData.value.splice(questionOrder,0,assign)
  Object.keys(topicData.value).map((value, index, array) => {
    if (index >= questionOrder+1){
      topicData.value[index].questionOrder = topicData.value[index].questionOrder +1
    }
  })
}

其实这里面是有很多坑的,特别是questionOrder和index的关系,我们一定要记得这个题目的题号始终比它的index大1。这也就是为什么我们在判断条件里面要写index>=questionOrder+1的原因。比如我们复制的是第二条题目,那我们选中的index就是1,questionOrder就是2。在我们插入复制的题目后,我们遍历我们数组中的索引,questionOrder+1就是我们插入复制的题目的题号,这时我们需要题号加1的题目的索引值就是大于等于我们题号的值。这样说大家可能有点糊涂,就拿上图那个例子来说,我们插入复制的题目的题号为3,那么原来3题也就是现在要变成第4题的index就变成了3(在复制的题目插入之前index是2)。所以这也就是为什么我们要写成index>=questionOrder+1,如果大家还是不懂,可以尽情在评论区提问。

2、删除

思路

​ 删除的功能就比复制简单多了,我们先来理清我们的思路。我们选择删除这个题目的时候,就把它从数组中移出去,那么删除之后的题目的题号都要-1,比如我们删除我们原来的第二题自定义2,那么原来的第三题自定义3就变成了第二题。如下图:

image-20230403123656029.png

实现:

​ 我们先用splice的方法,将我们选中要删除的题目删除,然后再用和复制一样的方法循环遍历我们的数组里的索引值。这时后如果这个题目的索引值大于等于questionOrder-1(也就在我们删除题目后面的题目),那么他们的题号就要-1。下面是我们的代码:

const deleteTopic = (questionOrder: number)=>{
  topicData.value.splice(questionOrder-1, 1)
  Object.keys(topicData.value).map((value, index, array) => {
    if (index >= questionOrder-1) {
      topicData.value[index].questionOrder = topicData.value[index].questionOrder -1
    }
  })
}

这里我们再来解释一下为什么是index >= questionOrder-1,我们原来选中的是第二题,也就是它的quesitionOrder是2。那么它现在被从数组中移除去了,那么原来在题号2之后的题目,也就是现在在题号1之后的题目(也就是questionOrder-1之后的题目),它们的题号要都-1。删除之后原来题目是自定义3的index是2,现在变成了1,这也就是为什么是index >= questionOrder-1。

3、上移

思路

​ 上移其实有很多思路,比如先把要上移的题目保存起来再删掉,再插入上一条题目前面。或者把选中的题目与它上一条交换并且还要改变我们的题号。我个人觉得第二种方法比较简单就选择了第二种。比如我们上移第二条题目自定义2,那么自定义2的题号就会变成1,自定义1的题号就会变成2,如下图:

image-20230403123618540.png

实现:

​ 首先我们得判断一下题目的位置,如果它的题号是1说明它已经是第一个了,无法再上移。如果不是第一个,我们再用之前的方法遍历数组的索引值,并把两个要交换的题目对象的题号保存起来,然后用ES6新特性解构赋值的方法将两个元素交换,再把之前保存好的题号按顺序赋值给这两个元素。比如上图我们上移了第二道题目,自定义1的题号变成了2,自定义2的题号变成了1,并且是按顺序排好的。下面是我们的代码:

const moveUp = (questionOrder:number)=>{
  if (questionOrder === 1){
    message.error('已经在最顶上了');
    return;
  }
  Object.keys(topicData.value).map((value, index, array) => {
    if (index == questionOrder-1){
      let a = topicData.value[index].questionOrder;
      let b = topicData.value[index-1].questionOrder;
      [topicData.value[index],topicData.value[index-1]]=[topicData.value[index-1],topicData.value[index]];
      topicData.value[index].questionOrder = a;
      topicData.value[index-1].questionOrder = b;
    }
  })
}

这里面为什么是index == questionOrder-1想必经过前面的复制和删除的讲解大家已经很清楚了。这里我们选中的是我们想要上移的那个题目的index,就是它自己的index。选中之后index-1就是要交换的题目。

4、下移

思路

​ 其实上移和下移都差不多,只是一开始要判断题目是不是在最底下,不是在最底下就和下面一题交换位置,并且改一下题号就行了。

const moveDown = (questionOrder:number)=>{
  if (questionOrder == topicData.value.length){
    message.error('已经在最底下了')
  }

  Object.keys(topicData.value).map((value, index, array) => {
    if (index == questionOrder-1){
      let a = topicData.value[index].questionOrder;
      let b = topicData.value[index+1].questionOrder;
      [topicData.value[index+1],topicData.value[index]]=[topicData.value[index],topicData.value[index+1]]
      topicData.value[index].questionOrder = a;
      topicData.value[index+1].questionOrder = b;
    }
  })
}

5、置顶

思路

​ 我这里给大家提供的思路是用unshift方法把要置顶的题目放到最前面,然后将题号改为1,并且删除这个题目原来所在的位置。当然在这个原本题目之前的题目的题号都要+1。比如我们要将第三题置顶,那么置顶后它的题号就是1,原来第一题和第二题的的题号就要变成2和3。当然我们也要判断它是不是已经是第一个题目,无法置顶。如下图:

image-20230403130712360.png

实现:

​ 我们还是要先遍历一下数组的索引,选中我们当前要置顶的题目,用unshift和splice方法,将要置顶的题目放到数组首位,并且将该题目的题号改为1,同时在该题之前的题目的题号都要+1。例如上图我们将题目为自定义三的题目置顶,于是它的题号变为1,同时其它题目的题号要+1。如果它的questionOrder已经是1,那么就已经置顶了。代码如下:

const front = (questionOrder: number)=>{
  if (questionOrder === 1){
    message.error('已经在最前面了');
  }
  Object.keys(topicData.value).map((value, index, array) => {
    if (index == questionOrder-1){
      topicData.value.unshift(topicData.value.splice(index,1)[0])
      topicData.value[0].questionOrder = 1;
    }
    if (index <= questionOrder-2) {
      topicData.value[index].questionOrder = topicData.value[index].questionOrder + 1
    }
  })
}

这里有个坑

我们还是先来说一下为什么index <= questionOrder-2,例如上图的例子,我们置顶的是第三个题目,它的题号是3,那么第二个题目的index是1,所以应该写成index <= questionOrder-2。不知道你们会不会好奇为什么在index == questionOrder-1的里面就把置顶的题目的题号定成1了,这样不会在第二个if语句的时候题号再加1吗?不应该把topicData.value[0].questionOrder = 1;语句放在外面吗?其实并不是这样的,因为我们在用map循环遍历的时候它是按顺序执行的,它会从index=0开始执行,也就是先执行index <= questionOrder-2里面的语句,先让选中题目之前的题号+1再将选中的题目unshift到数组最前面,并将它的题号改为1。

6、置底

思路

​ 置底我们还是要先选中我们要置底的题目,选中之后我们可以把它push到数组的最后,然后再把原来位置的题目删除掉,在它原来位置之后的题目所有题号都要+1。当然如果已经在最底部的话,那就提示一下。如下图我们将第一个题目置底:

image-20230403163943259.png

实现:

​ 同样我们的实现方法与置顶差不多,先用push方法将要置底的题目放在数组最后面,然后用splice删除原来位置的题目,再将原本该题目位置之后的题目题号-1。如果它的题号等于数组的长度就说明它已经在最底下了。完整代码如下:

const bottom = (questionOrder: number) => {
  if (questionOrder == topicData.value.length) {
    message.error('已经在最底部了');
  }
  Object.keys(topicData.value).map((value, index, array) => {
    if (index == questionOrder - 1) {
      topicData.value.push(topicData.value[index])
      topicData.value.splice(index, 1)
    }
    if (index >= questionOrder-1) {
      topicData.value[index].questionOrder = topicData.value[index].questionOrder - 1
    }
  })
  topicData.value[topicData.value.length - 1].questionOrder = topicData.value.length;
}

这里为什么又把题号放在最外面呢?

同样我们还是要注意代码遍历时执行的顺序,这里会先执行index == questionOrder - 1,所以先将我们要置底的题目push到最后,再删掉原本题目,然后执行题目题号-1的操作,最后我们才给我们要置底的题目的题号赋值为数组的长度。如果放在index == questionOrder - 1的判断条件里面先给他题号定死,但是后面一条判断语句里面的语句又会给它的题号-1。大家一定要多加考虑。

总结

​ 做完这个有序数组的排列我是收益颇丰,希望大家也仔细研究研究相信大家也会得到很多启发。同时如果大家有更好的方法或者我的代码有漏洞的地方也欢迎大家提议与指正。