面向对象思想-封装拖拽对象

1、我们常常会通过修改元素的top,left,translate来其的位置发生改变。修改元素的left,top值,但会引起页面重绘,而transform不会,所以要优先使用transform
2、如何获取当前浏览器支持的transform兼容写法
3、获取元素的初始位置:
4、需要绑定的事件:mousedown,mousemove,mouseup
而在移动端,分别与之对应的则是touchstart、touchmove、touchend。
5、原理

当事件触发时,我们可以通过事件对象获取到鼠标的精切位置。这是实现拖拽的关键。当鼠标按下(mousedown触发)时,我们需要记住鼠标的初始位置与目标元素的初始位置,我们的目标就是实现当鼠标移动时,目标元素也跟着移动,根据常理我们可以得出如下关系:
移动后的鼠标位置 - 鼠标初始位置 = 移动后的目标元素位置 - 目标元素的初始位置
如果鼠标位置的差值我们用dis来表示,那么目标元素的位置就等于:
移动后目标元素的位置 = dis + 目标元素的初始位置

通过事件对象,我们可以精确的知道鼠标的当前位置,因此当鼠标拖动(mousemove)时,我们可以不停的计算出鼠标移动的差值,以此来求出目标元素的当前位置。这个过程,就实现了拖拽。

而在鼠标松开(mouseup)结束拖拽时,我们需要处理一些收尾工作。

6、封装原则

如何合理的处理属性与方法的位置。

  • 构造函数中: 属性与方法为当前实例单独拥有,只能被当前实例访问,并且每声明一个实例,其中的方法都会被重新创建一次。

  • 原型中: 属性与方法为所有实例共同拥有,可以被所有实例访问,新声明实例不会重复创建方法。

  • 模块作用域中:属性和方法不能被任何实例访问,但是能被内部方法访问,新声明的实例,不会重复创建相同的方法。

对于方法的判断比较简单。

  • 因为在构造函数中的方法总会在声明一个新的实例时被重复创建,因此我们声明的方法都尽量避免出现在构造函数中。

  • 而如果你的方法中需要用到构造函数中的变量,或者想要公开,那就需要放在原型中。

  • 如果方法需要私有不被外界访问,那么就放置在模块作用域中。

对于属性的判断

对于属性放置于什么位置需要在实际开发中不断的总结经验。

  • 如果属性值只能被实例单独拥有,比如person对象的name,只能属于某一个person实例,又比如这里拖拽对象中,某一个元素的初始位置,也仅仅只是这个元素的当前位置,这个属性,则适合放在构造函数中。

  • 而如果一个属性仅仅供内部方法访问,这个属性就适合放在模块作用域中。

模块封装代码:

; //文件合并时,防止前一个文件末尾没加分号
  (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();
      },

      getStyle: function(property) {
        return window.getComputedStyle ? window.getComputedStyle(this.elem, null).getPropertyValue(property) : this.currentStyle.getAttribute(property);

      },

      //获取当前元素的位置信息,注意与之前的不同之处
      getPosition: function() {
        var pos = { x: 0, y: 0 };
        if (transform) {
          var transformValue = this.getStyle(transform);
          if (transformValue == 'none') {
            this.elem.style[transform] = 'translate(0,0)';
          } else {
            var temp = transformValue.match(/-?\d+/g);
            pos = {
              x: parseInt(temp[4].trim()),
              y: parseInt(temp[5].trim())
            }
          }
        } else {
          if (this.getStyle('position') == 'static') {
            this.elem.style.position = 'relative';
          } else {
            pos = {
              x: parseInt(this.getStyle('left') ? this.getStyle('left') : 0),
              y: parseInt(this.getStyle('top') ? this.getStyle('top') : 0)
            }
          }
        }
        return pos;
      },
      // 用来设置当前元素的位置
      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 curX = event.pageX;
          var curY = event.pageY;

          // 计算差值
          var disX = curX - self.startX;
          var disY = curY - self.startY;

          self.setPosition({
            x: (self.sourceX + disX).toFixed(),
            y: (self.sourceY + disY).toFixed()
          });
        }

        function end(event) {
          document.removeEventListener('mousemove', move);
          document.removeEventListener('mouseup', end);
          //do other things
        }
      }

    }

    //私有方法
    function getTransform() {
      var transform = '',
        divStyle = document.createElement('div').style,
        transformArr = ['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'oTransform'];

      //通过循环找出浏览器识别的那个,in操作符用于判断是否识别
      for (var i = 0, len = transformArr.length; i < len; i++) {
        if (transformArr[i] in divStyle) {
          return transform = transformArr[i];
        }
      }
      return transform;
    }

    window.Drag = Drag;
  })();

  new Drag('target');
  new Drag('target2');

html:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
  * {
    padding: 0;
    margin: 0;
  }

  #target,
  #target2 {
    width: 50px;
    height: 50px;
    background-color: orange;
    cursor: move;
  }

  #target2 {
    background-color: red;
  }

  </style>
</head>

<body>
  <div style="height:1000px">hha</div>
  <div id="target"></div>
  <div id="target2"></div>
 </body>
</html>

jquery实例方法扩展:

// 通过扩展方法将拖拽扩展为jQuery的一个实例方法
(function ($) {
  $.fn.extend({
    becomeDrag: function () {
      new Drag(this[0]);
      return this;   // 注意:为了保证jQuery所有的方法都能够链式访问,每一个方法的最后都需要返回this,即返回jQuery实例
    }
  })
})(jQuery);

参考链接:http://www.jianshu.com/p/b3dee0e84454
http://www.jianshu.com/p/3f97570d22b4

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值