vue自定义穿梭框支持远程滚动加载

分享-2023年资深前端进阶:前端登顶之巅-最全面的前端知识点梳理总结,前端之巅

*分享一个使用比较久的🪜

技术框架公司的选型(老项目):vue2 + iview-ui
方案的实现思路是共性的,展现UI样式需要你们自定义进行更改;因为iview是全局注入,基本使用原先的类名进行二次创建公共组件,修改基础js实现逻辑;

需求分析:实现远程滚动加载数据的穿梭框
1、创建自定义穿梭框,分左侧和右侧数据
2、依赖后端接口,左侧是左侧数据,右侧是右侧数据
3、定义好出入参数,支持回显内容及选中内容的去重处理
4、绑定对应的v-model数据响应
5、滚动加载数据,区分左右区域;添加自定义指令进行监听
6、滚动加载数据,不丢失已选中的数据,或去重已选中数据
7、支持左右侧的远程搜索功能,左右互不影响,检索数据放组件外部进行

在这里插入图片描述

1、代码信息

创建ivu-transfer.vue文件;依赖iviewUI请依据自己的样式进行拷贝;

1.1 自定义滚动监听指令
/** 远程滚动加载 */
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 = {
  // 点击左侧全选
  handleAllLeftCheck() {
    this.checkLeftAll = !this.checkLeftAll;
    if (this.checkLeftAll) {
      this.checkLeftAllGroup = this.leftDataSource.map(item => item.value);
    } else {
      this.checkLeftAllGroup = [];
    }
  },

  // 点击右侧全选
  handleAllRightCheck() {
    this.checkRightAll = !this.checkRightAll;
    if (this.checkRightAll) {
      this.checkRightAllGroup = this.rightDataSource.map(item => item.value);
    } else {
      this.checkRightAllGroup = [];
    }
  },

  // 点击向右数据
  handleClickArrowBack() {
    this.moveCheckedData("left");
  },

  // 点击向左数据
  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、内容使用api介绍

1、树形结构入参:dataSource=[{label: '测试',value: 1, description: '拼接内容' }]
2、标签引用:<IvuTransfer :leftData="dataSource" :rightData="targetKeys" @on-change="handleChange" v-loadTransfer="handleLoadMore" />
3、相关api说明文档在文章底部

<template>
 <div class="customSearch">
    <Input
      search
      clearable
      v-model="formLeftInput"
      placeholder="请输入搜索内容"
      @on-clear="handleOnLeftInput"
      @on-search="handleOnLeftInput"
    />
    <div style="width: 50px"></div>
    <Input
      search
      clearable
      v-model="formRightInput"
      placeholder="请输入搜索内容"
      @on-clear="handleOnRightInput"
      @on-search="handleOnRightInput"
    />
    </div>
    <IvuTransfer
      :leftData="dataSource"
      :rightData="targetKeys"
      @on-change="handleChange"
      v-loadTransfer="handleLoadMore"
    />
 </template>
// 远程滚动加载
  handleLoadMore(index) {
    if (index === 0 && this.dataLeftHasMore && !this.isShowLoading) {
      this.curLeftPage++;
      this.getLeftMockData();
    }
    if (index === 1 && this.dataRightHasMore && !this.rightLoading) {
      this.curRightPage++;
      this.getRightTargetKeys();
    }
  },
  
  // 触发选中移动
  handleChange(newLeftTargetData, newRightTargetKeys, direction) {
    this.dataSource = [...newLeftTargetData];
    this.targetKeys = [...newRightTargetKeys];
    if (direction === "right") {
      return this.remoteCheckPage();
    }
    if (direction === "left") {
      return this.remoteRightCheckPage();
    }
  },

getLeftData() {},
getRightData() {}
参数说明类型默认值必填项
leftData[{}]-label,value结构Array[][]
rightData[{}]-label,value结构Array[][]
on-change数据变更触发newLeft,newRight, direction

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/75380.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Unity每日一记】向量操作摄像机的移动(向量加减)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

Linux知识点 -- 进程概念(补充)

Linux知识点 – 进程概念&#xff08;补充&#xff09; 文章目录 Linux知识点 -- 进程概念&#xff08;补充&#xff09;一、进程地址空间的堆区二、虚拟地址到物理地址之间的转化三、虚拟地址到物理地址之间的映射 一、进程地址空间的堆区 在用户每次使用malloc等函数在进程的…

【设计模式——学习笔记】23种设计模式——策略模式Strategy(原理讲解+应用场景介绍+案例介绍+Java代码实现)

文章目录 案例引入传统方案实现实现分析 介绍基本介绍登场角色 案例实现案例一类图实现 案例二类图实现问答 策略模式在JDK源码中的使用总结文章说明 案例引入 有各种鸭子&#xff0c;比如野鸭、北京鸭、水鸭等。 鸭子有各种行为&#xff0c;比如走路、叫、飞行等。不同鸭子的…

[NLP]LLM 训练时GPU显存耗用量估计

以LLM中最常见的Adam fp16混合精度训练为例&#xff0c;分析其显存占用有以下四个部分&#xff1a; GPT-2含有1.5B个参数&#xff0c;如果用fp16格式&#xff0c;只需要1.5G*2Byte3GB显存, 但是模型状态实际上需要耗费1.5B*1624GB. 比如说有一个模型参数量是1M&#xff0c;在…

k8s 自身原理之 Service

好不容易&#xff0c;终于来到 k8s 自身的原理之 关于 Service 的一部分了 前面我们用 2 个简图展示了 pod 之间和 pod 与 node 之间是如何通信息的&#xff0c;且通信的数据包是不会经过 NAT 网络地址转换的 那么 Service 又是如何实现呢&#xff1f; Service 我们知道是用…

Flask-SQLAlchemy

认识Flask-SQLAlchemy Flask-SQLAlchemy 是一个为 Flask 应用增加 SQLAlchemy 支持的扩展。它致力于简化在 Flask 中 SQLAlchemy 的使用。SQLAlchemy 是目前python中最强大的 ORM框架, 功能全面, 使用简单。 ORM优缺点 优点 有语法提示, 省去自己拼写SQL&#xff0c;保证SQL…

Unity游戏源码分享-俄罗斯方块unity2017

Unity游戏源码分享-俄罗斯方块unity2017 工程地址&#xff1a; https://download.csdn.net/download/Highning0007/88204011

【Linux初阶】system V - 共享内存

文章目录 前言一、共享内存初识1.共享内存的原理2.理解共享内存3.共享的内存的概念 二、共享内存函数1.shmget函数2.shmat函数3.shmdt函数4.shmctl函数 三、共享内存的查看方法及其特征四、共享内存的代码实现五、共享内存优缺点分析1.共享内存的优点2.共享内存的缺点 六、共享…

【Nacos2.24持久化到Postgres数据库适配——详细版】

Nacos2.24持久化到Postgres数据库适配 前言步骤拉取源码添加依赖修改源码编译打包修改配置测试运行 参考 前言 公司基于springboot实现了一套单体框架&#xff0c;目前我负责搭建SpringCloud微服务框架&#xff0c;需要用到nacos&#xff0c;但是由于公司特殊性&#xff0c;na…

1022.从根到叶的二进制之和

目录 一、题目 二、代码 一、题目 二、代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nu…

玩转 VS code 之下载篇

VSCode 简介 Visual Studio Code (简称 VS Code / VSC)&#xff0c;是2015 年由微软公司推出的一款免费开源的现代化轻量级代码编辑器&#xff0c;支持几乎所有主流的开发语言的语法高亮、智能代码补全、GIT 等特性&#xff0c;支持插件扩展等等 可用于 Windows&#xff0c;ma…

等保测评标准和规范有哪些?

等保测评标准和规范的出现&#xff0c;为我国信息安全等级保护制度的建立和健全提供了重要的保障。 作为信息安全领域的重要评估标准&#xff0c;等保测评旨在通过对信息系统、网络安全设备和安全产品等的安全性能、安全功能、安全管理、安全控制和安全审计等方面的要求进行检查…

【golang】怎样判断一个变量的类型?

怎样判断一个变量的类型&#xff1f; package mainimport "fmt"var container []string{"zero", "one", "two"} func main() {container : map[int]string{0: "zero", 1: "one", 2: "two"}fmt.Printf…

AWS中Lambda集成SNS

1.创建Lambda 在Lambda中&#xff0c;创建名为AWSSNSDemo的函数 use strict console.log(loading function); var aws require(aws-sdk); var docClient new aws.DynamoDB.DocumentClient(); aws.config.regionap-southeast-1;exports.handler function(event,context,cal…

stop job is running for Advanced key-value store

今天虚拟机磁盘撑满了&#xff0c;本来还能凑合运行&#xff0c;结果重启了下&#xff0c;就报了这个 stop job is running for Advanced key-value store (1min 59s / no limit) 解决方式很简单&#xff0c; 1、虚拟机关电源&#xff0c;任务管理器&#xff0c;关闭VM&#x…

LeetCode_03Java_1572. 矩阵对角线元素的和

给你一个正方形矩阵 mat&#xff0c;请你返回矩阵对角线元素的和。 请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。 输入&#xff1a;mat [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;25 解释&#xff1a;对角线的和为&#xff1a;1 5 9 3 7 2…

我们为什么需要API管理系统?

我们为什么需要API管理系统&#xff1f; 随着web技术的发展&#xff0c;前后端分离成为越来越多互联网公司构建应用的方式。前后端分离的优势是一套Api可被多个客户端复用&#xff0c;分工和协作被细化&#xff0c;大大提高了编码效率&#xff0c;但同时也带来一些“副作用”:…

前端接口修改工具 Requestly具体操作

更新于2023年8月12日18:17:56&#xff0c;插件版本可能会变&#xff0c;界面可能会有所变化 插件下载地址&#xff1a;https://chrome.google.com/webstore/detail/requestly-open-source-htt/mdnleldcmiljblolnjhpnblkcekpdkpa 注意&#xff0c;必须用谷歌浏览器&#xff0c;…

Python-OpenCV中的图像处理-模板匹配

Python-OpenCV中的图像处理-模板匹配 模板匹配单对象的模板匹配多对象的模板匹配 模板匹配 使用模板匹配可以在一幅图像中查找目标函数&#xff1a; cv2.matchTemplate()&#xff0c; cv2.minMaxLoc()模板匹配是用来在一副大图中搜寻查找模版图像位置的方法。 OpenCV 为我们提…

强制Edge或Chrome使用独立显卡【WIN10】

现代浏览器通常将图形密集型任务卸载到 GPU&#xff0c;以改善你的网页浏览体验&#xff0c;从而释放 CPU 资源用于其他任务。 如果你的系统有多个 GPU&#xff0c;Windows 10 可以自动决定最适合 Microsoft Edge 自动使用的 GPU&#xff0c;但这并不一定意味着最强大的 GPU。 …