目录
只用style完成的代码
重点!!JS
transform和style的结合
浏览器的兼容写法
PS:记住createElement()这个方法,下次判断浏览器兼容时用得着!
PS:之所以要判断transformValue是否为none,是因为在初始化状态是,元素未被设置transform属性,这样正则之后的数组是找不到[4][5] 的,所以我们让val的两个属性为0,也就是稍后会成为的transform的translateX和translateY的值。
注意上面一段代码我们修改的的内容,在这里我们增加了一个判断:即当支持transform属性的浏览器存在时,我们会用transform属性修改元素的值,把之前在getTranslate中得到的x、y赋值给pos的x、y。
首页 web前端 js教程 封装一个自己的模块实例详解

封装一个自己的模块实例详解

Jan 30, 2018 pm 05:16 PM
实例 模块 自己的

试着封装了一个拖拽模块。过程中经历了一些曲折,最开始我是打算只用style.left的方式,但是这个需要设置position:absolute。可能对代码造成一定影响。虽然CSS的transform会影响兼容,但这里我还是使用了这个属性的translate来完成移动。

只用style完成的代码

话不多说,直接上代码:

html和css,这里必须设置position,第一次写这段代码的时候忘了,结果尽管JS写对了,效果完全出不来....真是短路了

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>学习</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        #box{
            width: 200px;
            height: 200px;
            background: #6f6;
            font-size: 20px;
            cursor:move;
            position: absolute;
        }
    </style>

</head>
<body>
  <p id="box"></p>
  <script src="js/drag_module.js"></script>
</body>
</html>
登录后复制

重点!!JS

;    //这个分号是为了防止其他的模块最后忘记加分号,导致错误。
(function() {
  
  //构造函数,属于每一个实例
  function Drag(selector) {
    this.elem = typeof selector == 'object' ? selector : document.getElementById(selector);
    //鼠标初始位置
    this.startX = 0;
    this.startY = 0;
    //元素初始位置
    this.sourceX = 0;
    this.sourceY = 0;

    this.init();
  }

  //原型,共有的
  Drag.prototype = {
    constructor: Drag,
    init: function() {
      this.setDrag();
    },

    //用于获取元素当前的位置信息
    getPosition: function() {
      var that = this;
      var pos = {};
      pos = {
        x: that.elem.offsetLeft,
        y: that.elem.offsetTop
      };
      return pos;
    },
    //用来设置当前元素的位置
    setPosition: function(pos) {
      this.elem.style.left = pos.x + 'px';
      this.elem.style.top = pos.y + 'px';
    },

    //该方法用来绑定事件
    setDrag: function() {
      var self = this;
      this.elem.addEventListener('mousedown', start, false);

      function start(event) {

        self.startX = event.pageX;
        self.startY = event.pageY;

        var pos = self.getPosition();

        self.sourceX = pos.x;
        self.sourceY = pos.y;

        document.addEventListener('mousemove', move, false);
        document.addEventListener('mouseup', end, false);
      }

      function move(event) {
        //总体思想:鼠标距浏览器距-鼠标距元素距离
        var currentX = event.pageX; //当前的鼠标x位置
        var currentY = event.pageY; //当前的鼠标y位置

        var distanceX = currentX - self.startX; //鼠标移动的距离x
        var distanceY = currentY - self.startY; //鼠标移动的距离y

        self.setPosition({
          x: self.sourceX + distanceX,
          y: self.sourceY + distanceY
        });

      }

      function end(event) {
        document.removeEventListener('mousemove', move);
        document.removeEventListener('mouseup', end);
      }
    }
  };
  
  //暴露在外
  window.Drag = Drag;
})();


new Drag('box');
登录后复制

这段代码是比较好理解的,在一开始看波大神的代码时,对于translate的运用实际上我没看太明白,因为没想到为啥要用到正则......

虽然比较简单,但是我们还是要分析一下这段代码的原理:

1.自执行函数里有一个构造函数Drag(),在构造函数里我们设置的方法和属性时每一个构造函数实例独有的,比如他们的位置信息等。而在原型里的有三个方法:分别是获取元素位置信息的getPosition()、设置元素位置的setPosition()和绑定事件的setDrag(),这三个因为是公用的,为了节省资源,我们就放在原型里了。

2.这段代码执行的原理是:当鼠标按下时,获取元素初始位置信息sourceX/Y、鼠标初始位置信息startX/Y;当鼠标移动完成时,获取鼠标新的位置currentX/Y,两个鼠标位置相减就能得到鼠标移动的距离distanceX/Y,这同时也是元素移动的距离,然后,我们把这个值赋给元素的style.left/top。元素的拖拽就实现了。

transform和style的结合

由于技术的发展,越来越多的设备开始支持CSS3了,加上style的资源占用的更多,效率方面存在问题,所以我们考虑使用transform。

浏览器的兼容写法

我们首先在函数Drag()前加上私有属性:

var transform = getTransform();
登录后复制

在下面再加上私有方法:

function getTransform() {
    var transform = "",
      pStyle = document.createElement('p').style,
      transformArr = ['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'oTransform'],
      i = 0,
      l = transformArr.length;

    for (; i < l; i++) {
      if (transformArr[i] in pStyle) {
        return transform = transformArr[i];
      }
    }
    return transform;
  }
登录后复制

PS:记住createElement()这个方法,下次判断浏览器兼容时用得着!

我们还需要在getPosition()的下面加上一个函数,用同样的形式:

getTranslate: function() {
      var val = {};
      var transformValue = document.defaultView.getComputedStyle(this.elem, false)[transform];
      if(transformValue=='none'){
        val={x:0,y:0};
      }else{
        var transformArr = transformValue.match(/-?\d+/g);
        val = {
          x: Number(transformArr[4]),
          y: Number(transformArr[5])
        };
      }


      return val;
    },
登录后复制

PS:之所以要判断transformValue是否为none,是因为在初始化状态是,元素未被设置transform属性,这样正则之后的数组是找不到[4][5] 的,所以我们让val的两个属性为0,也就是稍后会成为的transform的translateX和translateY的值。

继续写代码。上面一段我们用来提取translate的X、Y值。看下面一段:

getPosition: function() {
      var that = this;
      var pos = {};
      if(transform){
        var val=this.getTranslate();
        pos={
          x:val.x,
          y:val.y
        };
      }else{
        pos = {
          x: that.elem.offsetLeft,
          y: that.elem.offsetTop
        };
      }
      return pos;
    },
登录后复制

注意上面一段代码我们修改的的内容,在这里我们增加了一个判断:即当支持transform属性的浏览器存在时,我们会用transform属性修改元素的值,把之前在getTranslate中得到的x、y赋值给pos的x、y。

在上面一段代码中,我们会根据浏览器的情况,用不同的方法取到相同的值,val的值来自getTranslate(),是我们从元素的transform中提取出来的。同样,在下面的setPosition()中,我们也要设置if判断。

setPosition: function(pos) {
      if (transform) {
        this.elem.style[transform] = 'translate(' + pos.x + 'px' + ',' + pos.y + 'px)';
      } else {
        this.elem.style.left = pos.x + 'px';
        this.elem.style.top = pos.y + 'px';
      }
    },
登录后复制

这一段没什么好讲的,就是用不同的形式赋值而已。

到这里,这个模块就封装完毕了。接下来让我们看看完整代码:

;
(function() {
  //私有属性
  var transform = getTransform();
  //构造函数,属于每一个实例
  function Drag(selector) {
    this.elem = typeof selector == 'object' ? selector : document.getElementById(selector);
    //鼠标初始位置
    this.startX = 0;
    this.startY = 0;
    //元素初始位置
    this.sourceX = 0;
    this.sourceY = 0;

    this.init();
  }

  //原型,共有的
  Drag.prototype = {
    constructor: Drag,
    init: function() {
      this.setDrag();
    },

    //用于获取元素当前的位置信息
    getPosition: function() {
      var that = this;
      var pos = {};
      if(transform){
        var val=this.getTranslate();
        pos={
          x:val.x,
          y:val.y
        };
      }else{
        pos = {
          x: that.elem.offsetLeft,
          y: that.elem.offsetTop
        };
      }
      return pos;
    },

    //获取translate值
    getTranslate: function() {
      var val = {};
      var transformValue = document.defaultView.getComputedStyle(this.elem, false)[transform];
      if(transformValue=='none'){
        val={x:0,y:0};
      }else{
        var transformArr = transformValue.match(/-?\d+/g);
        val = {
          x: Number(transformArr[4]),
          y: Number(transformArr[5])
        };
      }


      return val;
    },
    //用来设置当前元素的位置
    setPosition: function(pos) {
      if (transform) {
        this.elem.style[transform] = 'translate(' + pos.x + 'px' + ',' + pos.y + 'px)';
      } else {
        this.elem.style.left = pos.x + 'px';
        this.elem.style.top = pos.y + 'px';
      }
    },

    //该方法用来绑定事件
    setDrag: function() {
      var self = this;
      this.elem.addEventListener('mousedown', start, false);

      function start(event) {

        self.startX = event.pageX;
        self.startY = event.pageY;

        var pos = self.getPosition();

        self.sourceX = pos.x;
        self.sourceY = pos.y;

        document.addEventListener('mousemove', move, false);
        document.addEventListener('mouseup', end, false);
      }

      function move(event) {
        //总体思想:鼠标距浏览器距-鼠标距元素距离
        var currentX = event.pageX; //当前的鼠标x位置
        var currentY = event.pageY; //当前的鼠标y位置

        var distanceX = currentX - self.startX; //鼠标移动的距离x
        var distanceY = currentY - self.startY; //鼠标移动的距离y

        self.setPosition({
          x: self.sourceX + distanceX,
          y: self.sourceY + distanceY
        });

      }

      function end(event) {
        document.removeEventListener('mousemove', move);
        document.removeEventListener('mouseup', end);
      }
    }
  };
  //私有方法,用来获取transform的兼容写法
  function getTransform() {
    var transform = "",
      pStyle = document.createElement('p').style,
      transformArr = ['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'oTransform'],
      i = 0,
      l = transformArr.length;

    for (; i < l; i++) {
      if (transformArr[i] in pStyle) {
        return transform = transformArr[i];
      }
    }
    return transform;
  }
  //暴露在外
  window.Drag = Drag;
})();


new Drag('box');
登录后复制

相关推荐:

javascript全局变量封装模块实现代码_javascript技巧

以上是封装一个自己的模块实例详解的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

WLAN扩展模块已停止[修复] WLAN扩展模块已停止[修复] Feb 19, 2024 pm 02:18 PM

如果您的Windows计算机上的WLAN扩展模块出现问题,可能会导致您与互联网断开连接。这种情况常常让人感到困扰,但幸运的是,本文提供了一些简单的建议,可以帮助您解决这个问题,让您的无线连接重新正常运行。修复WLAN扩展模块已停止如果您的Windows计算机上的WLAN可扩展性模块已停止工作,请按照以下建议进行修复:运行网络和Internet故障排除程序禁用并重新启用无线网络连接重新启动WLAN自动配置服务修改电源选项修改高级电源设置重新安装网络适配器驱动程序运行一些网络命令现在,让我们来详细看

WLAN可扩展性模块无法启动 WLAN可扩展性模块无法启动 Feb 19, 2024 pm 05:09 PM

本文详细介绍了解决事件ID10000的方法,该事件表明无线局域网扩展模块无法启动。在Windows11/10PC的事件日志中可能会显示此错误。WLAN可扩展性模块是Windows的一个组件,允许独立硬件供应商(IHV)和独立软件供应商(ISV)为用户提供定制的无线网络特性和功能。它通过增加Windows默认功能以扩展本机Windows网络组件的功能。在操作系统加载网络组件时,WLAN可扩展性模块作为初始化的一部分启动。如果无线局域网扩展模块遇到问题无法启动,您可能会在事件查看器的日志中看到错误消

Python中的SVM实例 Python中的SVM实例 Jun 11, 2023 pm 08:42 PM

Python中的支持向量机(SupportVectorMachine,SVM)是一个强大的有监督学习算法,可以用来解决分类和回归问题。SVM在处理高维度数据和非线性问题的时候表现出色,被广泛地应用于数据挖掘、图像分类、文本分类、生物信息学等领域。在本文中,我们将介绍在Python中使用SVM进行分类的实例。我们将使用scikit-learn库中的SVM模

Ansible工作原理详解 Ansible工作原理详解 Feb 18, 2024 pm 05:40 PM

Ansible工作原理从上面的图上可以了解到:管理端支持local、ssh、zeromq三种方式连接被管理端,默认使用基于ssh的连接,这部分对应上面架构图中的连接模块;可以按应用类型等方式进行HostInventory(主机清单)分类,管理节点通过各类模块实现相应的操作,单个模块,单条命令的批量执行,我们可以称之为ad-hoc;管理节点可以通过playbooks实现多个task的集合实现一类功能,如web服务的安装部署、数据库服务器的批量备份等。playbooks我们可以简单的理解为,系统通过

Ansible Ad-Hoc(点对点模式) Ansible Ad-Hoc(点对点模式) Feb 18, 2024 pm 04:48 PM

官方文档:https://docs.ansible.com/ansible/latest/command_guide/intro_adhoc.html简介Ad-hoc命令是一种临时输入并执行的命令,通常用于测试和调试。它们不需要永久保存,简单来说,ad-hoc就是“即时命令”。常用模块1、command模块(默认模块)默认模块,没有shell强大,基本上shell模块都可以支持command模块的功能。【1】帮助ansible-doccommand#推荐使用下面这个ansible-doccomm

一文总结特征增强&个性化在CTR预估中的经典方法和效果对比 一文总结特征增强&个性化在CTR预估中的经典方法和效果对比 Dec 15, 2023 am 09:23 AM

在CTR预估中,主流都采用特征embedding+MLP的方式,其中特征非常关键。然而对于相同的特征,在不同的样本中,表征是相同的,这种方式输入到下游模型,会限制模型的表达能力。为了解决这个问题,CTR预估领域提出了一系列相关工作,被称为特征增强模块。特征增强模块根据不同的样本,对embedding层的输出结果进行一次矫正,以适应不同样本的特征表示,提升模型的表达能力。最近,复旦大学和微软亚洲研究院合作发布了一篇关于特征增强工作的综述,对比了不同特征增强模块的实现方法及其效果。现在,我们来介绍一

学习Golang指针转换的最佳实践示例 学习Golang指针转换的最佳实践示例 Feb 24, 2024 pm 03:51 PM

Golang是一门功能强大且高效的编程语言,可以用于开发各种应用程序和服务。在Golang中,指针是一种非常重要的概念,它可以帮助我们更灵活和高效地操作数据。指针转换是指在不同类型之间进行指针操作的过程,本文将通过具体的实例来学习Golang中指针转换的最佳实践。1.基本概念在Golang中,每个变量都有一个地址,地址就是变量在内存中的位置。

VUE3入门实例:制作一个简单的视频播放器 VUE3入门实例:制作一个简单的视频播放器 Jun 15, 2023 pm 09:42 PM

随着新一代前端框架的不断涌现,VUE3作为一个快速、灵活、易上手的前端框架备受热爱。接下来,我们就来一起学习VUE3的基础知识,制作一个简单的视频播放器。一、安装VUE3首先,我们需要在本地安装VUE3。打开命令行工具,执行以下命令:npminstallvue@next接着,新建一个HTML文件,引入VUE3:&lt;!doctypehtml&gt;

See all articles