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

news/2024/7/23 8:40:26 标签: 前端, javascript, 开发语言

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>javascript">
    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.niftyadmin.cn/n/5465781.html

相关文章

Java进阶-反射的详解与应用

本文深入探讨了Java反射机制的核心概念、应用实例及其在现代Java开发中的重要性。文章首先介绍了反射的基本原理和能力&#xff0c;包括在运行时动态获取类信息、操作对象字段和方法的能力。随后&#xff0c;通过具体代码示例&#xff0c;展示了如何利用反射进行字段访问、方法…

SpringCloud学习(2)-OpenFeign

1.OpenFeign简介 Feign是一个声明式的Web服务客户端&#xff08;Web服务客户端就是Http客户端&#xff09;&#xff0c;让编写Web服务客户端变得非常容易&#xff0c;只需创建一个接口并在接口上添加注解即可。 cloud官网介绍Feign&#xff1a;Spring Cloud OpenFeign OpenF…

30. UE5 RPG GamplayAbility的配置项

在上一篇文章&#xff0c;我们介绍了如何将GA应用到角色身上的&#xff0c;接下来这篇文章&#xff0c;将主要介绍一下GA的相关配置项。 在这之前&#xff0c;再多一嘴&#xff0c;你要能激活技能&#xff0c;首先要先应用到ASC上面&#xff0c;才能够被激活。 标签 之前介绍…

操作系统注入漏洞

命令注入漏洞是一种安全漏洞&#xff0c;允许攻击者通过在应用程序中注入恶意命令来执行非法操作。在操作系统中&#xff0c;这种漏洞可能存在于用户输入被不正确处理的情况下。攻击者可能通过恶意构造的输入来执行系统命令&#xff0c;这可能导致未经授权的访问、数据泄露、拒…

中介者模式:优雅解耦的利器

在软件设计中&#xff0c;随着系统功能的不断扩展&#xff0c;对象之间的依赖关系往往会变得错综复杂&#xff0c;导致系统难以维护和扩展。为了降低对象之间的耦合度&#xff0c;提高系统的可维护性和可扩展性&#xff0c;设计模式应运而生。中介者模式&#xff08;Mediator P…

【three.js】简介和入门

目录 Three.js简介Three.js的应用Three.js的基础知识利用Three.js实现一个3D页面 Three.js简介 Three.js是一个基于JavaScript编写的开源3D图形库&#xff0c;利用WebGL技术在网页上渲染3D图形。它提供了许多高级功能&#xff0c;如几何体、纹理、光照、阴影等&#xff0c;以便…

rabbitMQ实战应用

rabbitMQ实战应用 异步任务处理&#xff1a;在Java项目中&#xff0c;可以将一些耗时的任务&#xff08;如文件处理、邮件发送等&#xff09;放入消息队列中&#xff0c;由后台的消费者异步地处理这些任务&#xff0c;提高系统的吞吐量和响应速度。 // 生产者 public class Tas…

Nginx 对客户端请求的限制

按方法名限制请求 limit_except limit_except method...{...} method 可取值&#xff1a; GET&#xff1a;用于请求指定的资源。 POST&#xff1a;向指定资源提交数据进行处理请求。 PUT&#xff1a;用于向服务器上传文件。 DELETE&#xff1a;请求服务器删除指定的资源。…