突破编程_前端_JS编程实例(分割窗体组件)

1 开发目标

分隔窗体组件旨在提供灵活的窗体分隔功能,支持横向分割与纵向分隔两种类型,并具备拖拽调整窗体比例的功能,同时提供最小比例设置,以防止窗体被过度缩小:

在这里插入图片描述

2 详细需求

2.1 分隔窗体类型

(1)横向分割:

  • 用户可以在窗体顶部或底部添加一个横向分割条,将窗体分割成上下两部分。
  • 分割条的位置可以通过拖拽调整,以改变上下两部分窗体的高度比例。

(2)纵向分隔:

  • 用户可以在窗体左侧或右侧添加一个纵向分割条,将窗体分割成左右两部分。
  • 分割条的位置同样可以通过拖拽调整,以改变左右两部分窗体的宽度比例。

2.2 鼠标样式切换

(1)鼠标靠近状态:

  • 当鼠标指针移动到分割条附近的一定范围内时,分割条应自动变为拖拽样式。
  • 拖拽样式可以通过视觉上的变化来体现,例如改变分割条的颜色、形状或添加拖拽图标等。

(2)鼠标远离状态:

  • 当鼠标指针离开分割条附近的范围时,分割条应自动恢复到默认样式。
  • 默认样式应简洁明了,以便在不需要拖拽调整时保持窗体的整体美观性。

2.3 拖拽调整窗体比例

(1)拖拽过程:

  • 用户点击并拖动拖拽样式的分割条时,应能够实时改变窗体的比例。
  • 拖拽过程中,应提供平滑的过渡效果,确保窗体布局的调整连贯且自然。

(2)横向分割调整:

  • 在横向分割模式下,拖动分割条将改变上下两部分窗体的高度比例。
  • 用户可以通过向上或向下拖动分割条来调整上下窗体的相对大小。

(3)纵向分隔调整:

  • 在纵向分隔模式下,拖动分割条将改变左右两部分窗体的宽度比例。
  • 用户可以通过向左或向右拖动分割条来调整左右窗体的相对大小。

2.4 最小比例设置

(1)设置功能:

  • 组件应提供设置最小比例的功能,允许用户自定义窗体在分割调整时的最小比例限制。
  • 用户可以通过配置项或API接口来设置最小比例值。

(2)横向分割调整:

  • 当用户尝试通过拖拽将窗体调整到小于最小比例时,应阻止进一步的调整操作。
  • 此时,可以通过视觉反馈(如提示信息、分割条位置固定等)来告知用户已达到最小比例限制。

3 代码实现

首先创建一个 neat_spliterwidget.js 文件,该文件用于本组件的工具类、目录处理函数的代码构建。

(1)创建分隔窗体的基类:

首先,定义核心数据变量:

class NeatSpliterWidget {constructor(container,para) {this.container = container;this.para = para;this.wid1 = null;this.wid2 = null;this.spliterRatio = para.spliterRatio ?? 0.3;this.minSpace = 20;this.spliterSpace = 3;              // 切换鼠标样式的间距this.dragReadyFalg = false;this.dragActiveFlag = true;this.dragFalg = false;this.dragStart = 0;this.render();}

接下来,进行基础类型的渲染,包括创建子窗体:

	render() {this.container.style.display = 'flex';this.wid1Tmp = document.createElement('div');this.wid2Tmp = document.createElement('div');this.widSpliter = document.createElement('div');this.wid1 = document.createElement('div');this.wid1.style.width = '100%';this.wid1.style.height = '100%';this.wid1Tmp.appendChild(this.wid1);this.wid2 = document.createElement('div');this.wid2.style.width = '100%';this.wid2.style.height = '100%';this.wid2Tmp.appendChild(this.wid2);}

最后,定义鼠标事件,计算拖拽时的初始位置:

	initSpliterEvent() {let that = this;if (!that.dragActiveFlag) {return;}this.container.addEventListener("mousedown", function (event) {if (!that.dragActiveFlag) {return;}if('column' == that.container.style.flexDirection){that.dragStart = event.clientY - event.currentTarget.offsetTop;}else{that.dragStart = event.clientX - event.currentTarget.offsetLeft;}if (that.dragReadyFalg) {that.dragFalg = true;this.onselectstart = function () { return false; };} else {that.dragFalg = false;this.onselectstart = function () { return true; };}});this.container.addEventListener("mouseup", function (event) {if (!that.dragActiveFlag) {return;}if('column' == that.container.style.flexDirection){that.dragStart = event.clientY - event.currentTarget.offsetTop;}else{that.dragStart = event.clientX - event.currentTarget.offsetLeft;}that.dragFalg = false;this.onselectstart = function () { return true; };});}
}

(2)接下来,开始定义纵向分割窗体的组件(支持水平拖拽):

class NeaterHSpliterWidget extends NeatSpliterWidget {constructor(container,para) {super(container,para);}render() {super.render();this.wid1Tmp.style.width = (this.spliterRatio * 100).toString() + '%';this.wid1Tmp.style.height = '100%';this.wid2Tmp.style.width = '10px';this.wid2Tmp.style.height = '100%';this.wid2Tmp.style.flex = 1;this.widSpliter.style.height = '100%';this.widSpliter.style.width = '1px';this.widSpliter.style.borderLeft = '1px solid #CACDD1';this.container.appendChild(this.wid1Tmp);this.container.appendChild(this.widSpliter);this.container.appendChild(this.wid2Tmp);this.initSpliterEvent();}

上面代码定义了 NeaterHSpliterWidget 的渲染方式,主要是将子窗体以及分割条做水平布局,接下来是处理水平拖拽事件:

	initSpliterEvent() {super.initSpliterEvent();let that = this;if (!that.dragActiveFlag) {return;}this.container.addEventListener("mousemove", function (event) {let clientX = event.clientX - event.currentTarget.offsetLeft;if (that.dragFalg) {let dragOffset = clientX - that.dragStart;let spliterWidth1 = that.wid1Tmp.offsetWidth + dragOffset;if (spliterWidth1 < that.minSpace || (that.container.offsetWidth - spliterWidth1) < that.minSpace) {return;}that.spliterRatio = spliterWidth1 / that.container.offsetWidth;that.wid1Tmp.style.width = spliterWidth1 + 'px';that.dragStart = clientX;} else {if (clientX > that.wid1Tmp.offsetWidth - that.spliterSpace && clientX < that.wid1Tmp.offsetWidth + that.spliterSpace + 1) {that.container.style.cursor = "col-resize";that.dragReadyFalg = true;} else {that.container.style.cursor = "default";that.dragReadyFalg = false;}}});}
}

上面代码的核心逻辑是计算更换鼠标样式的位置以及计算拖拽时分隔比例的变化。

(3)然后,定义横向分割窗体的组件(支持垂直拖拽):

class NeaterVSpliterWidget extends NeatSpliterWidget {constructor(container,para) {super(container,para);}render() {super.render();this.container.style.flexDirection = 'column';this.wid1Tmp.style.height = (this.spliterRatio * 100).toString() + '%';this.wid1Tmp.style.width = '100%';this.wid2Tmp.style.height = '10px';this.wid2Tmp.style.width = '100%';this.wid2Tmp.style.flex = 1;this.widSpliter.style.width = '100%';this.widSpliter.style.borderBottom = '1px solid #CACDD1';this.container.appendChild(this.wid1Tmp);this.container.appendChild(this.widSpliter);this.container.appendChild(this.wid2Tmp);this.initSpliterEvent();}

上面代码定义了 NeaterVSpliterWidget 的渲染方式,主要是将子窗体以及分割条做垂直布局,接下来是处理垂直拖拽事件:

	initSpliterEvent() {super.initSpliterEvent();let that = this;if (!that.dragActiveFlag) {return;}this.container.addEventListener("mousemove", function (event) {let clientY = event.clientY - event.currentTarget.offsetTop;if (that.dragFalg) {let dragOffset = clientY - that.dragStart;let spliterHeight1 = that.wid1Tmp.offsetHeight + dragOffset;if (spliterHeight1 < that.minSpace || (that.container.offsetHeight - spliterHeight1) < that.minSpace) {return;}that.spliterRatio = spliterHeight1 / that.container.offsetHeight;that.wid1Tmp.style.height = spliterHeight1 + 'px';that.dragStart = clientY;} else {if (clientY > that.wid1Tmp.offsetHeight - that.spliterSpace && clientY < that.wid1Tmp.offsetHeight + that.spliterSpace + 1) {that.container.style.cursor = "row-resize";that.dragReadyFalg = true;} else {that.container.style.cursor = "default";that.dragReadyFalg = false;}}});}
}

上面代码的核心逻辑是计算更换鼠标样式的位置以及计算拖拽时分隔比例的变化。

至此,整个分割窗体组件构建结束。

(4)完成目录导航功能的组件的代码编写后,可以创建 neat_spliterwidget.html 文件,调用该组件:

<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta http-equiv="X-UA-Compatible" content="ie=edge" /><title>spliter widget</title><style>html {height: 100%;}body {margin: 0;height: 100%;}</style>
</head><body><div id="divMain" style="height: 400px;width: 600px;margin: 20px;border: 1px solid #aaa;"></div>
</body>
<script src="./neat_spliterwidget.js"></script>
<script>let para = {spliterRatio:0.3,}let hSpliterWidget = new NeaterHSpliterWidget(document.getElementById('divMain'), para);para.spliterRatio = 0.7;let vSpliterWidget = new NeaterVSpliterWidget(hSpliterWidget.wid2, para);</script></html>

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI改写文案的注意事项

AI改写文案的注意事项 随着人工智能技术的不断发展&#xff0c;AI改写文案成为了一种新兴的应用场景。通过AI改写文案&#xff0c;可以快速生成大量内容&#xff0c;节省时间和人力成本&#xff0c;但在实际应用中也需要注意一些问题和注意事项。 1. 确保内容原创性 尽管AI改…

个人做量化交易是否可行呢?

考虑个人做量化交易&#xff0c;需要完成两步&#xff1a; 解决3个“什么”的问题&#xff1a;“你要在什么时间&#xff1f;交易什么标的&#xff1f;交易数量是多少&#xff1f;”把你的想法准确地表达出来&#xff0c;告诉交易下单系统 也就是自己形成策略----自己去实现。…

文件操作详解

1.为什么使用文件 目录 1.为什么使用文件 2.什么是文件 2.1程序文件 2.2数据文件 2.3文件名字 3.二进制文件与文本文件 4.文件的打开和关闭 4.1 流 4.2标准流 4.3文件指针 4.4 文件的打开和关闭 fopen fclose 5.文件的顺序读写 5.1文件读取结束原因的判定 5…

mysql 本地电脑服务部署

前提&#xff1a; 下载mysql 新建配置文档 在安装mysql目录新建 my.ini [mysqld] # 设置3306端口 port3306#设置mysql的安装目录 basedirC:\Program Files\MySQL\MySQL Server 8.3 #切记此处一定要用双斜杠\\,单斜杠我这里会出错&#xff0c;不过看别人的教程&#xff0c;有…

走进车厂 | 移远通信以前沿车载技术,照亮智能网联汽车产业创新发展之路

无钥匙自动解锁方便快捷、实时路况导航精准高效、语音指令轻松控制车辆、车载娱乐系统丰富多样……随着智能化、数字化浪潮的不断推进&#xff0c;现如今的汽车出行焕然一新。 正如我们所见&#xff0c;汽车产业正在经历前所未有的变革。物联网、车联网等前沿技术的发展和应用&…

argocd部署

一、前言 ArgoCD 是一个开源的、持续交付工具&#xff0c;用于自动化部署应用程序到 Kubernetes 集群。它基于 GitOps 理念&#xff0c;通过使用 Git 作为单一的源头来管理应用程序的配置和部署状态&#xff0c;argocd会定时监控git仓库中的yaml配置文件&#xff0c;当git仓库中…

后端前行Vue之路(二):模版语法之插值与指令

1.概述 Vue.js的模板语法是一种将Vue实例的数据绑定到HTML文档的方法。Vue的模板语法是一种基于HTML的扩展&#xff0c;允许开发者将Vue实例中的数据绑定到HTML元素&#xff0c;以及在HTML中使用一些简单的逻辑和指令。Vue.js 基于 HTML 的模板语法允许开发者声明式地将 DOM 绑…

瑞麦德机电设备将莅临2024第13届生物发酵展

参展企业介绍 河南瑞麦德机电设备有限公司是专业从事机械输送气力输送、称重配料、筛分、磁选设备研发和制造于一体的企业&#xff0c;公司采用国内外同行业产品的先进技术&#xff0c;经专业团队设计、研发、生产&#xff0c;产品满足“ISO9001”&#xff0c;“GMP”等标准要…

超图新建三维数据集继续学习

1 新建三维数据集 之前操作过新建三维数据集&#xff0c;还不熟悉&#xff0c;继续熟悉&#xff1b; 现在有一个文件型的数据源&#xff0c;名为swtest1&#xff1b;它前面小图标上有UDX三个字母&#xff0c;表明这是一个UDX类型的数据源&#xff1b;在此数据源上右击&#x…

LEAP模型的能源环境发展、碳排放建模预测及不确定性分析教程

原文链接&#xff1a;LEAP模型的能源环境发展、碳排放建模预测及不确定性分析教程https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247599754&idx4&sn243c9f8bff355235a7056c2cbb1331fa&chksmfa82076dcdf58e7b871c3369c95ead9ff1d90baa0431318b26b6abd27…

剑指offer--数组中重复的数字

一.题目描述 在一个长度为 n 的数组 nums 里的所有数字都在 0&#xff5e;n-1 的范围内。数组中某些数字是重复的&#xff0c;但不知道有几个数字重复了&#xff0c;也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。 算法1.排序,然后遍历,时间复杂度O(nlogn),空…

Flask Python:请求上下文和应用上下文

请求上下文和应用上下文详解 一、背景二、什么是上下文2.1、请求上下文2.2、应用上下文2.3、两种上下文的底层逻辑 三、写在最后 一、背景 在如何实现异步发送邮件的时候&#xff0c;遇到过这样一个报错 RuntimeError: Working outside of request context.This typically me…

Mysql实战--为什么表数据删掉一半,表文件大小不变

经常会有同学来问我&#xff0c;我的数据库占用空间太大&#xff0c;我把一个最大的表删掉了一半的数据&#xff0c;怎么表文件的大小还是没变&#xff1f; 那么今天&#xff0c;我就和你聊聊数据库表的空间回收&#xff0c;看看如何解决这个问题。 这里&#xff0c;我们还是针…

搜索与图论——Prim算法求最小生成树

在最小生成树问题里&#xff0c;正边和负边都没问题 朴素版prim算法 时间复杂度O(n^2) 生成树&#xff1a;每一次选中的t点&#xff0c;它和集合的距离对应的那条边&#xff0c;就是生成树的一条边 算法流程和dijkstra算法非常相似 #include<iostream> #include<cs…

是否应该升级到ChatGPT 4.0?深度对比ChatGPT 3.5与4.0的差异

如果只是想简单地体验AI的魅力&#xff0c;感受大模型的独特之处&#xff0c;或是玩一玩文字游戏&#xff0c;那么升级至ChatGPT 4.0可能并非必需。然而&#xff0c;若你期望将AI作为提升工作学习效率的得力助手&#xff0c;那么我强烈建议你升级到ChatGPT 4.0。 如果你不知道…

点点数据K参数加密逆向分析(RPC方案跟加密算法还原)

文章目录 1. 写在前面2. 接口分析3. 断点分析4. RPC调用5. 算法还原 【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长…

设计模式——行为型——责任链模式Chain Of Responsibility

请求类 public class ApproverRequest {private int type;//请求批准的类型private float price;//请求的金额private int id;//请求的编号 } 审批人抽象类 public abstract class ApproverPerson {protected ApproverPerson next;protected String name;//审批过程public a…

【详细讲解语言模型的原理、实战与评估】

&#x1f308;个人主页:程序员不想敲代码啊&#x1f308; &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家&#x1f3c6; &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提…

【Java面试题系列】基础篇

目录 基本常识标识符的命名规则八种基本数据类型的大小&#xff0c;以及他们的封装类3*0.10.3返回值是什么short s1 1; s1 s1 1;有什么错? short s1 1; s1 1;有什么错?简述&&与&的区别&#xff1f;简述break与continue、return的区别&#xff1f;Arrays类的…

【性能测试】性能场景收集与分析

本文章为学习笔记&#xff0c;内容是性能场景收集以及如何分析 压测场景 压测策略 系统架构梳理 性能场景设计-业务范围 分布式压测 指标监控