Skip to content

Instantly share code, notes, and snippets.

@ifyour
Last active December 20, 2018 10:14
Show Gist options
  • Save ifyour/cab82e303a1bd16aea92ed1519916dcc to your computer and use it in GitHub Desktop.
Save ifyour/cab82e303a1bd16aea92ed1519916dcc to your computer and use it in GitHub Desktop.
原生 JS 实现封装拖拽实例 // Demo: http://js.jirengu.com/hitoj
<!DOCTYPE html>
<html>
<head>
<title>Drag 实例</title>
<style type="text/css">
#box1,
#box2 {
width: 100px;
height: 100px;
background-color: red;
}
#box2 {
background-color: green;
}
</style>
</head>
<body>
<div id="box1"></div>
<div id="box2"></div>
<script>
;(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();
},
// 稍作改造,仅用于获取当前元素的属性,类似于getName
getStyle: function(property) {
return document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(this.elem, false)[property] : this.elem.currentStyle[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;
},
// 用来设置当前元素的位置
setPostion: 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;
var currentY = event.pageY;
var distanceX = currentX - self.startX;
var distanceY = currentY - self.startY;
self.setPostion({
x: (self.sourceX + distanceX).toFixed(),
y: (self.sourceY + distanceY).toFixed()
})
}
function end(event) {
document.removeEventListener('mousemove', move);
document.removeEventListener('mouseup', end);
// do other things
}
}
}
// 私有方法,仅仅用来获取transform的兼容写法
function getTransform() {
var transform = '',
divStyle = document.createElement('div').style,
transformArr = ['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'OTransform'],
i = 0,
len = transformArr.length;
for (; i < len; i++) {
if (transformArr[i] in divStyle) {
return transform = transformArr[i];
}
}
return transform;
}
// 一种对外暴露的方式
window.Drag = Drag;
})();
// 使用:声明2个拖拽实例
new Drag('box1');
new Drag('box2');
</script>
</body>
</html>
@ifyour
Copy link
Author

ifyour commented Jun 25, 2017

对象封装

理清思路(借助思维导图)

image

各个位置的区别

  • 构造函数中: 属性与方法为当前实例单独拥有,只能被当前实例访问,并且每声明一个实例,其中的方法都会被重新创建一次。
  • 原型中: 属性与方法为所有实例共同拥有,可以被所有实例访问,新声明实例不会重复创建方法。
  • 模块作用域中:属性和方法不能被任何实例访问,但是能被内部方法访问,新声明的实例,不会重复创建相同的方法。

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

  • 因为在构造函数中的方法总会在声明一个新的实例时被重复创建,因此我们声明的方法都尽量避免出现在构造函数中。
  • 而如果你的方法中需要用到构造函数中的变量,或者想要公开,那就需要放在原型中。
  • 如果方法需要私有不被外界访问,那么就放置在模块作用域中。

@ifyour
Copy link
Author

ifyour commented Dec 20, 2018

ES6 Class 改写:

Edit jn85wmvwky

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment