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 日

相关推荐

  • 一文搞懂架构设计的衡量标准:功能性、可用性、性能、可扩展性、安全性、协作效率、复杂度、成本效益

    大家好,我是汤师爷~ 架构设计的首要目标是服务于业务需求。因此,我们不应该盲目追求所谓的”最厉害的”架构,而应该致力于寻找最适合当前业务环境和未来发展需求的架构方案。 衡量架构的合理性是一个复杂的过程,需要从多个角度进行全面评估。主要可以从以下视角进行分析: 功能需求视角:评估架构是否有效支撑当前业务需求,并具有充分的灵活性以适应未来业务发展。 非功能需求视…

    未分类 2025 年 1 月 15 日
    65600
  • 一问一答学习PyQT6,对比WxPython和PyQt6的差异

    在我的基于WxPython的跨平台框架完成后,对WxPython的灵活性以及强大功能有了很深的了解,在跨平台的桌面应用上我突然对PyQt6的开发也感兴趣,于是准备了开发环境学习PyQt 6,并对比下WxPython的差异来进行深入的了解,发现它们很多理念和做法是如此的类似。 1、pyqt6都有那些布局控件? PyQt6 提供了多种布局控件,帮助开发者轻松地将…

    2025 年 1 月 10 日
    71200
  • Grok Super微信支付宝订阅教程

    国内用户开通 Grok Super 的充值教程,整理 Grok 充值、代充、国内支付、账号 ID 获取和确认充值步骤。

    未分类 4天前
    3500
  • Claude 国内支付被拒还能怎么充值

    Claude 国内支付被拒还能怎么充值。围绕 Claude Pro 国内充值、代充开通、支付宝微信支付、续费和到账确认,整理适合国内用户的处理思路。

    未分类 2026 年 5 月 17 日
    6600
  • JDK、IDEA安装教程 IDEA安装2023年10月 最新最详细!免费、亲测成功!!!

    系列文章目录(Intellij IDEA2023年10月 最新教程) Java学习之IDEA的安装教程和使用 以下是第一章的内容:IntelliJ IDEA安装教程 文章目录 前言 准备工作 步骤(敲详细!!!) 前言 IDEA的安装是Java课程的入门,本人台式机于2023年7月份进行了系统重装,恰巧最近需要重新安装IDEA进行使用,借此机会给同学们分享我…

    未分类 2025 年 5 月 13 日
    50500

发表回复

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

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

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

关注微信