JavaScript 拖拽与观察者模式的实现及应用

前言

本文将通过几个具体的代码片段,深入探讨 JavaScript 中的拖拽功能和观察者模式(发布-订阅模式)的实现及其应用场景。

这些代码片段不仅展示了如何实现这些功能,还解释了其背后的原理和实际用途。通过阅读本文,读者可以更好地理解 JavaScript 的高级特性,并将其应用到实际项目中。


1. 拖拽功能的实现

在这里插入图片描述

代码片段

```html



    
    
    
    Document
    


    
father
son
```

代码解析

拖拽类 Drag
```javascript
class Drag {
    constructor(selector) {
        // 获取拖拽的对象
        this.ele = document.querySelector(selector);
        // 添加事件
        this.ele.onmousedown = function (evt) {
            // this: 原来指向了 ele 对象,这里需要一个实例对象
            this.fnDown(evt);
        }.bind(this);
    }

    fnDown(evt) {
        let e = evt || window.event;
        // 求鼠标的相对坐标值
        this.dis_x = e.offsetX;
        this.dis_y = e.offsetY;

        // 移动事件
        document.onmousemove = function (evt) {
            // this: document
            this.fnMove(evt);
        }.bind(this);

        // 鼠标抬起事件
        document.onmouseup = this.fnUp.bind(this);

        // 取消默认行为
        document.ondragstart = function () {
            return false;
        };
    }

    fnMove(evt) {
        let e = evt || window.event;
        this.ele.style.left = e.pageX - this.dis_x + 'px';
        this.ele.style.top = e.pageY - this.dis_y + 'px';
    }

    fnUp() {
        document.onmousemove = null;
    }
}

```
子类 Subdrag 继承自 Drag
```javascript
class Subdrag extends Drag {
    constructor(selector) {
        // 调用父类的构造函数
        super(selector);
    }

    fnMove(evt) {
        let e = evt || window.event;
        let left = e.pageX - this.dis_x;
        let top = e.pageY - this.dis_y;

        // 设置边界
        if (left <= 0) {
            left = 0;
        } else if (left >= document.documentElement.clientWidth - this.ele.offsetWidth) {
            left = document.documentElement.clientWidth - this.ele.offsetWidth;
        }

        if (top <= 0) {
            top = 0;
        } else if (top >= document.documentElement.clientHeight - this.ele.offsetHeight) {
            top = document.documentElement.clientHeight - this.ele.offsetHeight;
        }

        this.ele.style.left = left + 'px';
        this.ele.style.top = top + 'px';
    }
}

```

在这里插入图片描述

功能说明

拖拽功能 是一种常见的用户交互方式,允许用户通过鼠标移动元素。在上述代码中,Drag 类实现了基本的拖拽功能,包括:

  1. 获取拖拽对象 :通过选择器获取要拖拽的 DOM 元素。
  2. 添加鼠标按下事件 :当用户按下鼠标时,记录鼠标相对于元素的位置 (dis_x, dis_y)。
  3. 添加鼠标移动事件 :根据鼠标的当前位置更新元素的位置。
  4. 添加鼠标抬起事件 :当用户释放鼠标时,移除鼠标移动事件,防止后续不必要的移动。
  5. 取消默认行为 :阻止浏览器的默认拖拽行为。

Subdrag 类继承自 Drag 类,并在其基础上增加了边界限制,确保拖拽的元素不会超出视口范围。这使得拖拽体验更加友好和实用。


2. 观察者模式(发布-订阅模式)

代码片段 1:药店示例

```html



    
    
    
    Document


    



```

在这里插入图片描述

代码解析

观察者模式 (发布-订阅模式)是一种设计模式,用于定义对象间的一种一对多依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都会收到通知并自动更新。在上述代码中,drugstore 作为发布者,维护了一个名为 obj 的花名册,记录了不同事件的订阅者列表。

具体实现如下:

  1. 订阅方法listen:接收事件名称 eventName 和回调函数 fn,将回调函数添加到对应事件的订阅者列表中。
  2. 发布方法publish:接收事件名称 eventName 和数据 data,遍历对应的订阅者列表,依次调用每个回调函数并传递数据。

通过这种方式,多个订阅者可以根据不同的条件对同一事件做出响应。例如,在上述代码中,四个不同的订阅者(小周、小易、小王、老王)根据药店发布的口罩信息做出了不同的反应。

代码片段 2:售楼处示例

```html



    
    
    
    Document


    



```

在这里插入图片描述

代码解析

在售楼处示例中,salesOffice 作为发布者,同样使用了花名册 arr 来记录订阅者的回调函数。不同的是,这里的订阅者只关心新楼盘推出的消息,而不需要区分不同的事件类型。

具体实现如下:

  1. 订阅方法listen:接收回调函数 fn 并将其添加到花名册中。
  2. 发布方法publish:接收数据 data,遍历花名册中的所有回调函数并依次调用。

通过这种方式,多个订阅者可以根据新楼盘的信息做出不同的反应。例如,在上述代码中,三个不同的订阅者(小明、小龙、小强)根据售楼处发布的房屋信息做出了不同的决策。


结尾

通过以上两个主要部分的详细探讨,我们深入分析了 JavaScript 中的拖拽功能和观察者模式的实现及其应用场景。拖拽功能使得用户能够直观地操作页面元素,而观察者模式则提供了一种优雅的方式来处理对象间的依赖关系,避免了紧耦合的问题。

在实际项目中,合理运用这些技术和模式可以显著提高用户体验和代码的可维护性。希望本文的内容对读者有所帮助,欢迎继续探索 JavaScript 的更多可能性。无论是构建复杂的用户界面还是实现高效的数据通信,掌握这些高级编程技巧都将为开发者带来更多的便利和灵活性。


文章整理自互联网,只做测试使用。发布者:Lomu,转转请注明出处:https://www.it1024doc.com/6837.html

(0)
LomuLomu
上一篇 2025 年 1 月 19 日
下一篇 2025 年 1 月 21 日

相关推荐

  • MySQL 安装部署

    概述 本文主要介绍如何在 Linux 中以 RPM 包的方式安装 MySQL 并进行相关的初始化配置,文中方案均已实践验证。 操作系统 CentOS 7.6 数据库版本 MySQL 8.4.3 LTS [!NOTE] 说明 本文主要介绍 RPM 包的安装方式,其他安装方法可查阅官网:MySQL :: MySQL 8.4 Reference Manual ::…

    未分类 2025 年 1 月 11 日
    12000
  • Java MyBatis 面试题

    谈谈MyBatis的启动过程? 加载配置文件: MyBatis的配置文件是一个XML文件,包含了数据库连接信息、映射文件的位置等配置信息。在启动过程中,MyBatis会读取并解析这个配置文件。 创建SqlSessionFactory对象: SqlSessionFactory是MyBatis的核心对象,用于创建SqlSession对象。在启动过程中,MyBat…

    未分类 2025 年 1 月 15 日
    12400
  • MySQL连接IDEA(Java Web)保姆级教程

    第一步:新建项目(File)->Project 第二步:New Project(JDK最好设置1.8版本与数据库适配,详细适配网请到MySQL官网查询MySQL :: MySQL 8.3 Reference Manual :: Search Results) 第三步:点中MySQLTest(项目名)并连续双击shift键->搜索Add Framework S…

    2025 年 1 月 15 日
    13300
  • Python包管理不再头疼:uv工具快速上手

    Python 包管理生态中存在多种工具,如 pip、pip-tools、poetry、conda 等,各自具备一定功能。 而今天介绍的uv 是 Astral 公司推出的一款基于 Rust 编写的 Python 包管理工具,旨在成为 “Python 的 Cargo ”。 它提供了快速、可靠且易用的包管理体验,在性能、兼容性和功能上都有出色表现,为 Python…

    2024 年 12 月 31 日
    20500
  • 履约系统:发货单、配送单模型设计详解

    大家好,我是汤师爷~ 概念模型设计是系统开发的关键步骤,它能帮助我们厘清业务逻辑并定义核心实体。我们将从订单履约的基本概念入手,深入探讨各实体间的关系。 履约域核心概念模型 如图展示了履约域的核心概念模型。 1、发货单 发货单是订单履约过程中的重要执行单据,它将订单转化为具体的发货任务。门店和仓储部门通过发货单进行拣货、打包并安排物流服务商发货。发货单确保货…

    2024 年 12 月 31 日
    11900

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信