使用 Vue3 实现一个穿梭框效果

效果

当选中数据,并且点击相对应的方向箭头时,选中的数据会发送到对面,并且数据会保持正确的顺序进行排列。

在线预览:chenyajun.fun/#/transfer

实现

左右两边逻辑一致,这里只对左侧的进行分析

先看一下 html 结构 方便理解

html 复制代码
      <div class="module-wrapper">
        <div class="module-head">
          <span>list1</span>
          <span>{{ currentSelectLeft }}</span>
        </div>
        <div class="module-content">
          <div v-if="!listLeft.length" style="text-align: center">No data</div>
          <div class="module-item" v-for="(item, index) in listLeft" @click="handleTransferLeft(index)">
            <input style="width: 20px; height: 20px" type="checkbox" :checked="item.checked" />
            <span
              :style="{
                color: item.checked ? '#68b2ff' : '#000',
              }"
              >{{ item.label }}</span
            >
          </div>
        </div>
      </div>

数据处理

首先初始化 10 条穿梭框数据,key 属性用于排序,label 用于展示数据,最后为数据添加 checked 属性(主要用于标记是否被选中),然后将数据赋值给左边的列表 listLeft。

js 复制代码
function getListData() {
  let data = []
  for (let index = 1; index <= 10; index++) {
    data.push({
      key: index,
      label: 'option' + index,
    })
  }

  //对data进行处理 默认我们认为没有checked属性
  data.forEach((item) => {
    item.checked = false
  })
  listLeft.value = data
}

点击状态取反

上面我们初始化了数据,下面需要做的是当点击每一项 option 的时候让状态取反。

点击 option 时只需把相应的 index 传入,然后进行取反操作即可。

js 复制代码
// 点击进行状态取反
function handleTransferLeft(currentIndex) {
  listLeft.value[currentIndex].checked = !listLeft.value[currentIndex].checked
}

比例状态

我们看到了上面的已选数据和总数据的比例状态
先拿到已选数据

js 复制代码
// 左侧checked的数据
const currentCheckedLeft = computed(() => {
  return listLeft.value.filter((item) => item.checked)
})

将左侧选中数据的长度 比上 数据总长度即可

js 复制代码
// 左侧选中的比例数目
const currentSelectLeft = computed(() => {
  return currentCheckedLeft.value.length + '/' + listLeft.value.length
})

点击箭头进行穿梭

js 复制代码
// 点击右箭头
function toRight() {
  // 对选中数据进行深拷贝
  const deepCloneData = JSON.parse(JSON.stringify(currentCheckedLeft.value))
  // 把刚选择的数据状态进行清除
  deepCloneData.forEach((item) => {
    item.checked = false
  })
  // 把选中的数据添加到右边 需要把刚选择的数据状态进行清除
  listRight.value.push(...deepCloneData)
  // 对右边数据进行重新排序
  listRight.value.sort((a, b) => a.key - b.key)

  // 找到未选中数据 进行重新赋值
  const noCheckedLeftData = listLeft.value.filter((item) => !item.checked)
  listLeft.value = noCheckedLeftData
}

先对选中数据清除状态,因为如果不清除状态可能会导致穿梭过的的数据仍然还是选中。

如图所示:1,2是刚穿梭过去的数据,仍保留状态

注意需要对选中数据进行深拷贝,因为下面需要用到未选中的数据,如果不进行深拷贝,那下面再去筛选未选中的数据时就会把所有的数据选中。

js 复制代码
  // 对选中数据进行深拷贝
  const deepCloneData = JSON.parse(JSON.stringify(currentCheckedLeft.value))
  // 把刚选择的数据状态进行清除
  deepCloneData.forEach((item) => {
    item.checked = false
  })

接下来筛选出来选中数据后,将数据添加到右边的数组

js 复制代码
 // 把选中的数据添加到右边 需要把刚选择的数据状态进行清除
  listRight.value.push(...deepCloneData)

然后再对右边的数组进行排序

js 复制代码
  // 对右边数据进行重新排序
  listRight.value.sort((a, b) => a.key - b.key)

现在已经将数据穿梭到右侧,那怎么去除左侧已穿梭的数据呢?

筛选出来左边未选择的数据,重新赋值给左边数组即可

js 复制代码
  // 找到未选中数据 进行重新赋值
  const noCheckedLeftData = listLeft.value.filter((item) => !item.checked)
  listLeft.value = noCheckedLeftData

这一步也是上面为什么深拷贝的原因。

如果不进行深拷贝,如图所示:

已经穿梭了过去,但是取未筛选数据时,因为上面的状态已经取反,这里都会选择到。

总结

我们需要知道如果要实现一个穿梭框效果,我们大概都需要做哪些东西呢?

那首先是对左侧的初始化数据,我们需要对数据进行加工,添加 checked 属性,方便后面进行筛选。

其次是我们找出我们选中的数据,添加到右侧,同时把左侧选中的数据进行移除。

源码

GitHub:github.com/chenyajun-c...

所有源码已经同步提交 GitHub,如果觉得对你有帮助或者启发的话,可以给作者点下 star⭐

相关推荐
weixin_462446239 分钟前
nodejs 下使用 Prettier 美化单个 JS 文件(完整教程)
开发语言·javascript·ecmascript
岭子笑笑28 分钟前
vant 4 之loading组件源码阅读
前端
q_191328469532 分钟前
基于SpringBoot2+Vue2的行业知识答题考试系统
java·vue.js·spring boot·mysql·毕业设计·计算机毕业设计·演示文稿
hxmmm32 分钟前
自定义封装 vue多页项目新增项目脚手架
前端·javascript·node.js
ETA832 分钟前
JS执行机制揭秘:你以为的“顺序执行”,其实是V8引擎在背后搞事情!
前端·javascript
鹏北海-RemHusband33 分钟前
微前端实现方式:HTML Entry 与 JS Entry 的区别
前端·javascript·html
行走的陀螺仪1 小时前
JavaScript 装饰器完全指南(原理/分类/场景/实战/兼容)
开发语言·javascript·ecmascript·装饰器
瘦的可以下饭了1 小时前
3 链表 二叉树
前端·javascript
我那工具都齐_明早我过来上班1 小时前
WebODM生成3DTiles模型在Cesium地图上会垂直显示问题解决(y-up-to-z-up)
前端·gis
粉末的沉淀1 小时前
jeecgboot:electron桌面应用打包
前端·javascript·electron