前端vue左侧树的一整套功能实现(一):vue2+vite封装v-resize指令,实现左侧树拖拽宽度和折叠展开

news2024/9/20 10:40:42

实现v-resize指令,具体以下功能:

  1. 指令接收宽度最大最小值,接收一个id用于localStorage存储拖拽宽度,接收padding
  2. 拖拽时产生虚线拖拽,松开鼠标再进行元素宽度调整
  3. 折叠展开图标使用本地图片

封装一个vite下使用本地图片的函数方法

用于拖拽指令中设置折叠展开图标

/** vite使用动态图片的方式 */
export function requireImg(name) {
  return new URL(`/src/assets/imgs/${name}`, import.meta.url).href
}

v-resize指令具体代码

// 注意,需要去除绑定元素的overflow:auto,指令会添加一个具有overflow:auto的元素
let resize;
let stopResize;
const vResize = {
  bind(el, binding) {
    // 从绑定值中获取最小宽度和最大宽度
    const {
      minWidth = 150,
      maxWidth = 400,
      id = '',
      padding = 10,
    } = binding.value || {};

    // 拖拽元素内部插入一个包裹元素,方便控制所有子元素隐藏显示
    const wrapper = document.createElement('div');
    wrapper.style.cssText = `width: 100%; height: 100%; overflow: auto; padding:${padding}px`;
    while (el.firstChild) {
      // appendChild 方法用于将一个节点添加到另一个节点的子节点列表的末尾。
      // 如果要添加的节点已经存在于文档树中,appendChild 方法会将该节点从其当前位置移动到新的位置,而不是复制该节点。
      // 这样就可以将 el 的所有子元素通过循环全部插入至 wrapper 中
      wrapper.appendChild(el.firstChild);
    }
    el.appendChild(wrapper);

    // 创建拖拽元素
    const resizer = document.createElement('div');
    resizer.style.cssText =
      'width: 10px; height: 100%; position: absolute; right: -10px; top: 0px; cursor: ew-resize; user-select: none; display: flex; justify-content: center; align-items: center; z-index: 999;';
    el.style.position = 'relative';
    el.style.padding = '0px';
    el.appendChild(resizer);
    el.style.transition = 'width 0.3s ease';

    // 缓存宽度
    const savedWidth = localStorage.getItem('WIDTH' + id);
    if (savedWidth) {
      el.style.width = savedWidth;
      if (el.style.width === '0px') {
        wrapper.style.display = 'none';
      }
    }

    // 创建切换按钮
    const img = document.createElement('img');
    img.src =
      el.style.width === '0px'
        ? requireImg('tree/7.png')
        : requireImg('tree/6.png');
    img.style.cssText = 'cursor:pointer;height:40px;';
    resizer.appendChild(img);

    // 切换显示/隐藏逻辑
    img.addEventListener('mousedown', (e) => {
      e.stopPropagation();
      toggleContainer(el, wrapper, img);
    });

    // 拖拽虚线
    const line = document.createElement('div');
    line.style.cssText =
      'position: absolute; height: 100%; width: 2px; right: 0; top: 0; z-index: 9999; border-right: 0px dashed #409EFF; pointer-events: none;';
    el.appendChild(line);

    // 拖拽事件
    resizer.addEventListener('mousedown', () => {
      document.addEventListener('mousemove', resize);
      document.addEventListener('mouseup', stopResize);
    });

    let newWidth;

    resize = function (e) {
      line.style.borderRight = '2px dashed #409EFF';
      // 使用传入的最小宽度和最大宽度
      const width = e.pageX - el.getBoundingClientRect().left;
      if (width <= 0) {
        newWidth = 0;
      } else {
        newWidth = Math.max(minWidth, Math.min(maxWidth, width));
      }
      line.style.right = `${el.getBoundingClientRect().right - e.pageX}px`;
    };

    stopResize = function () {
      line.style.borderRight = '0px dashed #409EFF';
      document.removeEventListener('mousemove', resize);
      document.removeEventListener('mouseup', stopResize);
      if (newWidth) {
        el.style.width = `${newWidth}px`;
        setTimeout(() => {
          wrapper.style.display = 'block';
        }, 200);
      } else {
        el.style.width = `0px`;
        wrapper.style.display = 'none';
      }
      img.src =
        newWidth === 0 ? requireImg('tree/7.png') : requireImg('tree/6.png');
      localStorage.setItem('WIDTH' + id, el.style.width);
    };

    function toggleContainer(el, wrapper, img) {
      if (el.style.width === '0px') {
        el.style.width = `${minWidth}px`;
        img.src = requireImg('tree/6.png');
        setTimeout(() => {
          wrapper.style.display = 'block';
        }, 200);
      } else {
        wrapper.style.display = 'none';
        el.style.width = '0px';
        img.src = requireImg('tree/7.png');
      }
      localStorage.setItem('WIDTH' + id, el.style.width);
    }
  },
  unbind() {
    // 清除所有事件监听器,防止内存泄漏
    document.removeEventListener('mousemove', resize);
    document.removeEventListener('mouseup', stopResize);
  },
};

Vue.directive('resize', vResize);

使用指令

 <div class="page">
    <div
      class="left"
      v-resize="{
        id: 'left_tree',
        minWidth: '473',
        maxWidth: '773',
      }"
      v-loading="treeloading">
      ...
    </div>
    <div class="right">
      ...
    </div>
  </div>
.page{
   display:flex;
   .left_tree{
     width:550px;
   }
   .right{
     flex:1;
   }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【CMake】使用CMake在Visual Studio内构建多文件夹工程

一、配置准备 打开VIsual Studio&#xff0c;载入写好的 C M a k e l i s t s . t x t CMakelists.txt CMakelists.txt&#xff0c;在项目中添加以下文件&#xff1a; 创建一个文件夹 f u n c s funcs funcs&#xff0c;里面放入 f u n c . h func.h func.h、 f u n c . c p …

fmql之驱动程序编写(首次)

看了正点原子的zynq系列的Linux开发指南&#xff08;pdf和视频均有&#xff09;&#xff0c;因此从最简单的程序开始。 驱动程序开发&#xff1a;&#xff08;第四期视频&#xff09; 第3.1讲 我的第一个Linux驱动-字符设备驱动框架_哔哩哔哩_bilibili 学习驱动程序编写之前&am…

【论文串烧】多媒体推荐中的模态平衡学习 | 音视频语音识别中丢失导致的模态偏差对丢失视频帧鲁棒性的影响

文章目录 一、多媒体推荐中的模态平衡学习1.1 研究背景1.2 解决问题1.3 实施方案1.4 文章摘要1.5 文章重点1.6 文章图示图 1&#xff1a;不同模型变体在 AmazonClothing 数据集上的初步研究图 2&#xff1a;CKD模型架构的说明图 3&#xff1a;在 Amazon-Clothing 数据集上训练过…

【Linux:共享内存】

共享内存的概念&#xff1a; 操作系统通过页表将共享内存的起始虚拟地址映射到当前进程的地址空间中共享内存是由需要通信的双方进程之一来创建但该资源并不属于创建它的进程&#xff0c;而属于操作系统 共享内存可以在系统中存在多份&#xff0c;供不同个数&#xff0c;不同进…

Qt窗口——QStatusBar

文章目录 状态栏状态栏创建状态栏显示临时消息状态栏添加子控件 状态栏 QStatusBar状态栏是应用程序中输出简要信息的区域&#xff0c;例如画图板下面的区域 我们也可以给程序设置状态栏&#xff0c;表示一些状态。 状态栏创建 使用Qt Creator创建项目的时候&#xff0c;如果…

实现一种可插拔的参数校验

1、概述 仿照mybatis的二级缓存的实现方式&#xff0c;使用“策略模式配置” 的方式实现一个可动态插拔的 参数校验&#xff0c;便于后期扩展。 实现方式也很简单&#xff0c;首先定义一个校验接口&#xff0c;并提供一个校验方法&#xff1b;每种参数校验都是实现 了该校验接口…

前端vue-实现富文本组件

1.使用wangeditor富文本编辑器 工具网站&#xff1a;https://www.wangeditor.com/v4/ 下载安装命令&#xff1a;npm i wangeditor --save 成品如下图&#xff1a; 组件实现代码 <template><div><!-- 富文本编辑器 --><div id"wangeditor">…

Recbole安装指南:步骤详解与常见问题解决方案

1.两种方式&#xff1a; 从Conda安装 如果你还没有安装Conda&#xff0c;可以安装Miniconda或完整的Anaconda。 如果你在中国大陆&#xff0c;我们推荐你使用清华镜像安装Conda。 当你完成Conda的安装后&#xff0c;你可以将RecBole安装在python 3.7的Conda环境中&#xff0…

数据结构之树(下),你真的懂吗?

数据结构入门学习&#xff08;全是干货&#xff09;——树&#xff08;下&#xff09; 1 堆 (Heap) 1.1 什么是堆 堆 (Heap) 是一种特殊的完全二叉树&#xff0c;分为最大堆和最小堆。 最大堆&#xff1a;每个节点的值都大于或等于其子节点的值&#xff0c;根节点是整个堆的…

YOLOv9改进策略【注意力机制篇】| MCAttention 多尺度交叉轴注意力

一、本文介绍 本文记录的是基于MCA注意力模块的YOLOv9目标检测改进方法研究。普通的轴向注意力难以实现长距离交互&#xff0c;不利于捕获分割任务中所需的空间结构或形状&#xff0c;而MCA注意力模块通过构建了两个并行轴向注意力之间的交互&#xff0c;更有效地利用多尺度特…

2.4 卷积2

2.4.2 复正弦波与整体方案 在2.3节中&#xff0c;我们提出了关于复正弦输入的频域输出及其意义的两个问题。为了研究这些问题&#xff0c;我们让一个具有真实脉冲响应 h [ n ] h[n] h[n]&#xff08;即 h Q [ n ] 0 h_Q[n] 0 hQ​[n]0&#xff09;的LTI系统通过输入复正弦…

数据结构(Day16)

一、学习内容 1、有关顺序表的操作&#xff08;功能函数&#xff09; 1、创建顺序表 Plist create_list(){Plist L malloc(sizeof(list)); // 为顺序表分配内存空间if(NULL L){printf("申请空间失败\n");return NULL; // 如果内存分配失败&#xff0c;返回 NU…

RTMP协议在无人机巡检中的应用场景

为什么要用无人机巡检 好多开发者对无人机巡检技术方案&#xff0c;相对陌生&#xff0c;实际上&#xff0c;无人机巡检就是利用无人机对特定区域或设施进行定期或不定期的检查。这种巡检方式相比传统的人工巡检具有显著的优势&#xff0c;包括速度快、覆盖广、风险低、准确性…

Tornado 是一个 Python 异步网络库和 web 框架

Tornado 是一个 Python 异步网络库和 web 框架&#xff0c;它最初由 FriendFeed 开发&#xff0c;后来被 Facebook 收购并开源。Tornado 因其非阻塞的 I/O 操作和优秀的性能而广受欢迎&#xff0c;特别是在需要处理大量并发连接的应用中。Tornado 的底层实现主要依赖于 Python …

神经网络通俗理解学习笔记(0) numpy、matplotlib

Numpy numpynumpy 基本介绍Ndarray对象及其创建Numpy数组的基础索引numpy数组的合并与拆分&#xff08;重要&#xff09;numpy数组的矩阵运算Numpy数组的统计运算numpy中的arg运算numpy中的神奇索引和比较 Matplotlib numpy numpy 基本介绍 numpy 大多数机器学习库都用了这个…

【Linux入门】基本指令(一)

目录 一.使用环境 二.快捷键 三. 登录与用户管理 1.ssh root[ip地址] 2.whoami 3.ls /home 4.adduser [用户名] 5.passwd [用户名] 四.目录文件操作 1.ls 2.pwd 3.cd 4.touch 5.mkdir 6.rm 7.cp 五.命令手册 一.使用环境 云服务器&#xff1a;市面上有很多&am…

Python 中的 typing 模块常见用法

typing 模块是 Python 提供的一个标准库&#xff0c;主要用于为函数、变量和类定义类型提示&#xff08;Type Hints&#xff09;&#xff0c;从而提高代码的可读性和类型安全性。虽然 Python 是动态类型语言&#xff0c;但通过 typing 模块&#xff0c;开发者可以明确指定变量和…

TMStarget学习——Functional Connectivity

今天基于结构像和功能像数据试验操作TMStarget 的第二个功能模块Functional Connectivity。参考季老师的文档PPT来学习的&#xff0c;整个处理过程蛮长的&#xff0c;可能配置原因一路上报错也比较多&#xff0c;下面还是逐步记录吧&#xff0c;后面采用连更的方式直到跑通后再…

C++ 中的继承(详细讲解)

一、继承的概念以及定义 1、继承概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保 持原有类特性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。继承呈现了面向对象 程序设计的…

微波无源器件 功分器 4 一种用于天线阵列的紧凑宽带四路双极化波导功分器

摘要&#xff1a; 一种新型紧凑和高效率&#xff0c;在一个同相2x4方案(四路)显示双极化的功分器的设计和仿真被提出了&#xff0c;两个基本的正交模式TE10和TE01在四个方波导处同相输出通过使用四个3端口个四个E面和两个H面功分结构。此功分末端接了两个商用波导(WR75)端口&am…