Resig本身包装的javascript,面向对象实战之封装拖

时间:2019-09-25 09:13来源:关于计算机
前端基础进级(10):面向对象实战之封装拖拽对象 2017/04/02 · JavaScript·面向对象 初稿出处: 波同学    终于 日前几篇小说,我跟大家共享了JavaScript的一些基础知识,那篇文章,将会

前端基础进级(10):面向对象实战之封装拖拽对象

2017/04/02 · JavaScript · 面向对象

初稿出处: 波同学   

图片 1

终于

日前几篇小说,我跟大家共享了JavaScript的一些基础知识,那篇文章,将会跻身第2个实战环节:利用前面几章的所关联到的学问,封装二个拖拽对象。为了能够扶助我们探听越多的措施与扩充对照,作者会使用二种不相同的艺术来促成拖拽。

  • 不封装对象直接达成;
  • 利用原生JavaScript封装拖拽对象;
  • 经过扩展jQuery来落实拖拽对象。

正文的例证会停放于codepen.io中,供大家在翻阅时一直查看。如若对于codepen不精通的同桌,能够花点时间稍微精晓一下。

拖拽的兑现进度会涉嫌到十分的多的实用小知识,因而为了加固本人本身的文化积攒,也为了大家能够学到越来越多的学问,小编会尽量详细的将有个别细节分享出来,相信大家认真读书之后,一定能学到一些东西。

复制代码 代码如下:

1、怎样让四个DOM成分动起来

咱俩平时会由此改产生分的top,left,translate来其的岗位发生转移。在底下的例证中,每点击三次按键,对应的因素就能够移动5px。大家可点击查看。

点击查看三个让元素动起来的小例子

出于修改叁个要素top/left值会唤起页面重绘,而translate不会,由此从性质优化上来判别,大家会先行使用translate属性。

//获取成分的样式值。
function getStyle(elem,name){
if(elem.style[name]){
return elem.style[name];
}else if(elem.currentStyle){
return elem.currentStyle[name];
}else if(document.defaultView&&document.defaultView.getComputedStyle){
name=name.replace(/([A-Z])/g,”-$1″);
name=name.toLowerCase();
var s=document.defaultView.getComputedStyle(elem,”");
return s&&s.getPropertyValue(name);
}else{
return null
}
}
//获取成分相对于那么些页面包车型地铁x和y坐标。
function pageX(elem){
return elem.offsetParent?(elem.offsetLeft+pageX(elem.offsetParent)):elem.offsetLeft;
}
function pageY(elem){
return elem.offsetParent?(elem.offsetTop+pageY(elem.offsetParent)):elem.offsetTop;
}
//获取成分相对于父成分的x和y坐标。
function parentX(elem){
return elem.parentNode==elem.offsetParent?elem.offsetLeft:pageX(elem)-pageX(elem.parentNode);
}
function parentY(elem){
return elem.parentNode==elem.offsetParent?elem.offsetTop:pageY(elem)-pageY(elem.parentNode);
}
//获取使用css定位的要素的x和y坐标。
function posX(elem){
return parseInt(getStyle(elem,”left”));
}
function posY(elem){
return parseInt(getStyle(elem,”top”));
}
//设置成分地方。
function setX(elem,pos){
elem.style.left=pos+”px”;
}
function setY(elem,pos){
elem.style.top=pos+”px”;
}
//增韩元素X和y坐标。
function addX(elem,pos){
set(elem,(posX(elem)+pos));
}
function addY(elem,pos){
set(elem,(posY(elem)+pos));
}
//获取成分选取css调整大小的惊人和增长幅度
function getHeight(elem){
return parseInt(getStyle(elem,”height”));
}
function getWidth(elem){
return parseInt(getStyle(elem,”width”));
}
//获取成分恐怕,完整的万丈和幅度
function getFullHeight(elem){
if(getStyle(elem,”display”)!=”none”){
return getHeight(elem)||elem.offsetHeight;
}else{
var old=resetCss(elem,{display:”block”,visibility:”hidden”,position:”absolute”});
var h=elem.clientHeight||getHeight(elem);
restoreCss(elem,old);
return h;
}
}
function getFullWidth(elem){
if(getStyle(elem,”display”)!=”none”){
return getWidth(elem)||elem.offsetWidth;
}else{
var old=resetCss(elem,{display:”block”,visibility:”hidden”,position:”absolute”});
var w=elem.clientWidth||getWidth(elem);
restoreCss(elem,old);
return w;
}
}
//设置css,并保存旧的css
function resetCss(elem,prop){
var old={};
for(var i in prop){
old[i]=elem.style[i];
elem.style[i]=prop[i];
}
return old;
}
function restoreCss(elem,prop){
for(var i in prop){
elem.style[i]=prop[i];
}
}
//展现和隐身
function show(elem){
elem.style.display=elem.$oldDisplay||” “;
}
function hide(elem){
var curDisplay=getStyle(elem,”display”);
if(curDisplay!=”none”){
elem.$oldDisplay=curDisplay;
elem.style.display=”none”;
}
}
//设置折射率
function setOpacity(elem,num){
if(elem.filters){
elem.style.filter=”alpha(opacity=”+num+”)”;
}else{
elem.style.opacity=num/100;
}
}
//滑动
function slideDown(elem){
var h=getFullHeight(elem);
elem.style.height=”0px”;
show(elem);
for(var i=0;i<=100;i+=5){
new function(){
var pos=i;
setTimeout(function(){elem.style.height=(pos/100*h)+”px”;},(pos*10));
}
}
}
//渐变
function fadeIn(elem){
show(elem);
setOpacity(elem,0);
for(var i=0;i<=100;i+=5){
new function(){
var pos=i;
setTimeout(function(){setOpacity(elem,pos);},(pos+1)*10);
}
}
}
//获取鼠标光标相对于整个页面包车型地铁岗位。
function getX(e){
e=e||window.event;
return e.pageX||e.clientX+document.body.scrollLeft;
}
function getY(e){
e=e||window.event;
return e.pageY||e.clientY+document.body.scrollTop;
}
//获取鼠标光标相对于当下成分的地方。
function getElementX(e){
return (e&&e.layerX)||window.event.offsetX;
}
function getElementY(e){
return (e&&e.layerY)||window.event.offsetY;
}
//获取页面包车型大巴惊人和宽度
function getPageHeight(){
var de=document.documentElement;
return document.body.scrollHeight||(de&&de.scrollHeight);
}
function getPageWidth(){
var de=document.documentElement;
return document.body.scrollWidth||(de&&de.scrollWidth);
}
//获取滚动条的岗位。
function scrollX(){
var de=document.documentElement;
return self.pageXOffset||(de&&de.scrollLeft)||document.body.scrollLeft;
}
function scrollY(){
var de=document.documentElement;
return self.pageYOffset||(de&&de.scrollTop)||document.body.scrollTop;
}
//获取视口的低度和宽度。
function windowHeight() {
var de = document.documentElement;
return self.innerHeight||(de && de.offsetHeight)||document.body.offsetHeight;
}
function windowWidth() {
var de = document.documentElement;
return self.innerWidth||( de && de.offsetWidth )||document.body.offsetWidth;
}

2、怎么着获得当前浏览器辅助的transform包容写法

transform是css3的属性,当我们应用它时就只好面前碰到包容性的标题。区别版本浏览器的极其写法大概有如下三种:

['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'OTransform']

为此大家需求决断当前浏览器情况帮忙的transform属性是哪个种类,方法如下:

JavaScript

// 获取当前浏览器扶助的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; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 获取当前浏览器支持的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;
}

该方法用于获取浏览器帮衬的transform属性。借使回到的为空字符串,则表示方今浏览器并不辅助transform,今年我们就必要选择left,top值来更改元素的职位。假设协助,就改变transform的值。

你也许感兴趣的篇章:

  • jQuery常用知识点总计以及平时打包常用函数
  • 依据jquery封装的贰个js分页
  • jquery数组封装使用格局分享(jquery数组遍历)
  • Jquery封装tab自动切换效果的切实落到实处
  • jquery自动将form表单封装成json的具体贯彻
  • jquery datatable后台封装数据示例代码
  • jQuery主题图切换特效插件封装实例
  • 听闻jquery的用dl模拟达成可自定义样式的SELECT下拉列表(已打包)
  • jQueryUI的Dialog的简便包装
  • 【精粹源码收藏】基于jQuery的档期的顺序常见函数封装群集
3、 怎么着获得成分的初阶地点

咱俩先是要求获得到对象成分的起来地方,因而这里大家要求一个特意用来得到成分样式的成效函数。

而是获取成分样式在IE浏览器与任何浏览器有部分区别,因而咱们必要三个包容性的写法。

JavaScript

function getStyle(elem, property) { // ie通过currentStyle来博取成分的体制,别的浏览器通过getComputedStyle来收获 return document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(elem, false)[property] : elem.currentStyle[property]; }

1
2
3
4
function getStyle(elem, property) {
    // ie通过currentStyle来获取元素的样式,其他浏览器通过getComputedStyle来获取
    return document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(elem, false)[property] : elem.currentStyle[property];
}

有了那几个主意之后,就能够起来动手写获取目的成分开首地方的不二秘籍了。

JavaScript

function getTargetPos(elem) { var pos = {x: 0, y: 0}; var transform = getTransform(); if(transform) { var transformValue = getStyle(elem, transform); if(transformValue == 'none') { elem.style[transform] = 'translate(0, 0)'; return pos; } else { var temp = transformValue.match(/-?d+/g); return pos = { x: parseInt(temp[4].trim()), y: parseInt(temp[5].trim()) } } } else { if(getStyle(elem, 'position') == 'static') { elem.style.position = 'relative'; return pos; } else { var x = parseInt(getStyle(elem, 'left') ? getStyle(elem, 'left') : 0); var y = parseInt(getStyle(elem, 'top') ? getStyle(elem, 'top') : 0); return pos = { x: x, y: y } } } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function getTargetPos(elem) {
    var pos = {x: 0, y: 0};
    var transform = getTransform();
    if(transform) {
        var transformValue = getStyle(elem, transform);
        if(transformValue == 'none') {
            elem.style[transform] = 'translate(0, 0)';
            return pos;
        } else {
            var temp = transformValue.match(/-?d+/g);
            return pos = {
                x: parseInt(temp[4].trim()),
                y: parseInt(temp[5].trim())
            }
        }
    } else {
        if(getStyle(elem, 'position') == 'static') {
            elem.style.position = 'relative';
            return pos;
        } else {
            var x = parseInt(getStyle(elem, 'left') ? getStyle(elem, 'left') : 0);
            var y = parseInt(getStyle(elem, 'top') ? getStyle(elem, 'top') : 0);
            return pos = {
                x: x,
                y: y
            }
        }
    }
}

在拖拽进程中,大家需求不停的装置指标元素的新岗位,那样它才会活动起来,因而大家供给三个安装目的成分地点的诀窍。

JavaScript

// pos = { x: 200, y: 100 } function setTargetPos(elem, pos) { var transform = getTransform(); if(transform) { elem.style[transform] = 'translate('+ pos.x +'px, '+ pos.y +'px)'; } else { elem.style.left = pos.x + 'px'; elem.style.top = pos.y + 'px'; } return elem; }

1
2
3
4
5
6
7
8
9
10
11
// pos = { x: 200, y: 100 }
function setTargetPos(elem, pos) {
    var transform = getTransform();
    if(transform) {
        elem.style[transform] = 'translate('+ pos.x +'px, '+ pos.y +'px)';
    } else {
        elem.style.left = pos.x + 'px';
        elem.style.top = pos.y + 'px';
    }
    return elem;
}
5、我们必要用到哪边事件?

在pc上的浏览器中,结合mousedown、mousemove、mouseup那四个事件能够辅助大家兑现拖拽。

  • mousedown 鼠标按下时接触
  • mousemove 鼠标按下后拖动时接触
  • mouseup 鼠标松手时触发

而在移动端,分别与之对应的则是touchstart、touchmove、touchend

当大家将成分绑定那个事件时,有三个风浪指标将会作为参数字传送递给回调函数,通过事件指标,我们得以博得到当下鼠标的准确地方,鼠标地点新闻是落到实处拖拽的重要。

事件目的特别着重,在那之中蕴涵了相当多的灵光的新闻,这里笔者就不扩大了,大家能够在函数准将事件指标打字与印刷出来查看里面包车型地铁实际性质,那几个艺术对于记不清事件指标首要性质的童鞋非常有效。

6、拖拽的规律

当事件触发时,大家能够通过事件目的获得到鼠标的精切地点。那是落到实处拖拽的第一。当鼠标按下(mousedown触发)时,大家要求记住鼠标的初步地点与指标成分的最先地点,大家的对象便是达成当鼠标移动时,目的成分也跟着移动,遵照原理大家可以得出如下事关:

移动后的鼠标位置 - 鼠标开端位置 = 移动后的指标元素地方 - 指标成分的起来地点

1
移动后的鼠标位置 - 鼠标初始位置 = 移动后的目标元素位置 - 目标元素的初始位置

假设鼠标地点的差值大家用dis来代表,那么目的成分的职位就拾分:

活动后目的成分的职务 = dis + 指标成分的开始地方

1
移动后目标元素的位置 = dis + 目标元素的初始位置

因这事件目的,我们可以准确的接头鼠标的当下地点,由此当鼠标拖动(mousemove)时,大家能够不停的乘除出鼠标移动的差值,以此来求出目的成分的此时此刻任务。这些历程,就完结了拖拽。

而在鼠标放手(mouseup)甘休拖拽时,大家要求管理部分完结职业。实际情况见代码。

7、 小编又来推荐思维导图援助写代码了

经常有新人朋友跑来问笔者,如若逻辑思维技术不强,能还是不可能写代码做前端。作者的答案是:能。因为依附思维导图,能够很自在的弥补逻辑的短板。何况比在自身头脑中脑补逻辑更是清晰明了,不易出错。

地点第六点作者介绍了规律,因而怎么着做就展现不是那么难了,而现实的步调,则在底下的妄想导图中鲜明给出,大家只须求听从这么些手续来写代码就能够,试试看,一定很轻便。

图片 2

选取思维导图清晰的抒发出成套拖拽进度大家需求干的事务

8、代码完成

part1、策动专门的学业

JavaScript

// 获取目的成分对象 var oElem = document.getElementById('target'); // 申明2个变量用来保存鼠标开始地点的x,y坐标 var startX = 0; var startY = 0; // 注解2个变量用来保存目的成分起头地方的x,y坐标 var sourceX = 0; var sourceY = 0;

1
2
3
4
5
6
7
8
9
10
// 获取目标元素对象
var oElem = document.getElementById('target');
 
// 声明2个变量用来保存鼠标初始位置的x,y坐标
var startX = 0;
var startY = 0;
 
// 声明2个变量用来保存目标元素初始位置的x,y坐标
var sourceX = 0;
var sourceY = 0;

part2、作用函数

因为从前曾经贴过代码,就不再重复

JavaScript

// 获取当前浏览器协理的transform包容写法 function getTransform() {} // 获取元素属性 function getStyle(elem, property) {} // 获取成分的启幕地方function getTargetPos(elem) {} // 设置成分的初步地点 function setTargetPos(elem, potions) {}

1
2
3
4
5
6
7
8
9
10
11
// 获取当前浏览器支持的transform兼容写法
function getTransform() {}
 
// 获取元素属性
function getStyle(elem, property) {}
 
// 获取元素的初始位置
function getTargetPos(elem) {}
 
// 设置元素的初始位置
function setTargetPos(elem, potions) {}

part3、证明多个事件的回调函数

这两个章程就是实现拖拽的基本所在,作者将严酷依照地点思维导图中的步骤来成功大家的代码。

JavaScript

// 绑定在mousedown上的回调,event为流传的风浪目的 function start(event) { // 获取鼠标开始地点 startX = event.pageX; startY = event.pageY; // 获取成分起先地点 var pos = getTargetPos(oElem); sourceX = pos.x; 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 - startX; var distanceY = currentY - startY; // 总结并安装成分当前职分setTargetPos(oElem, { x: (sourceX + distanceX).toFixed(), y: (sourceY + distanceY).toFixed() }) } function end(event) { document.removeEventListener('mousemove', move); document.removeEventListener('mouseup', end); // do other things }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 绑定在mousedown上的回调,event为传入的事件对象
function start(event) {
    // 获取鼠标初始位置
    startX = event.pageX;
    startY = event.pageY;
 
    // 获取元素初始位置
    var pos = getTargetPos(oElem);
 
    sourceX = pos.x;
    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 - startX;
    var distanceY = currentY - startY;
 
    // 计算并设置元素当前位置
    setTargetPos(oElem, {
        x: (sourceX + distanceX).toFixed(),
        y: (sourceY + distanceY).toFixed()
    })
}
 
function end(event) {
    document.removeEventListener('mousemove', move);
    document.removeEventListener('mouseup', end);
    // do other things
}

OK,一个简短的拖拽,就好像此喜欢的兑现了。点击上面包车型大巴链接,能够在线查看该例子的demo。

运用原生js达成拖拽

9、封装拖拽对象

在前方一章笔者给我们大快朵颐了面向对象怎样落到实处,基于那多少个基础知识,大家来将地点完结的拖拽封装为三个拖拽对象。大家的对象是,只要大家声美素佳儿个拖拽实例,那么传入的指标成分将机关具备能够被拖拽的机能。

在骨子里付出中,多个目的大家经常会单独放在四个js文件中,那些js文件将独自作为贰个模块,利用各个模块的诀窍组织起来使用。当然这里未有复杂的模块交互,因为那一个例子,大家只必要一个模块即可。

为了幸免变量污染,大家必要将模块放置于四个函数自进行办法模拟的块级作用域中。

JavaScript

; (function() { ... })();

1
2
3
4
;
(function() {
    ...
})();

在平常的模块协会中,我们只是独自的将过多js文件降低成为三个js文件,因而这里的率先个分行则是为了以免万一上一个模块的末尾不用分号导致报错。不能缺少。当然在经过require或许ES6模块等艺术就不会油然则生如此的情状。

咱俩精通,在卷入叁个对象的时候,我们能够将品质与办法放置于构造函数大概原型中,而在扩张了自奉行函数之后,大家又足以将质量和形式幸免与模块的内部功用域。那是闭包的知识。

那正是说大家面前蒙受的挑衅就在于,怎么着合理的拍卖属性与格局的位置。

当然,每一个指标的意况都区别等,不能够视同一律,大家须求显然的驾驭那三种职位的特征才干做出最契合的决定。

  • 构造函数中: 属性与方法为近期实例单独具有,只好被当下实例访谈,何况每声爱他美(Aptamil)(Aptamil)个实例,个中的艺术都会被重新创制贰遍。
  • 原型中: 属性与办法为全部实例共同持有,能够被抱有实例访问,新表明实例不会再一次创立方法。
  • 模块功效域中:属性和艺术不可能被别的实例访谈,不过能被内部方法访谈,新评释的实例,不会再次成立一样的格局。

对此艺术的判定相比简单。

因为在构造函数中的方法总会在注解一(Wissu)个新的实例时被重新创造,因而大家注脚的措施都尽量防止出现在构造函数中。

而纵然你的方法中须求用到构造函数中的变量,只怕想要公开,那就须要放在原型中。

就算方式必要个人不被外面访问,那么就停放在模块功用域中。

对此属性放置于怎么样职位有个别时候很难做出精确的判别,因而我很难交付一个准儿的概念告诉你什么性质一定要放在怎么样职位,那亟需在实质上支出中反复的计算经验。不过总的来讲,依旧要组成那八个职分的性状来做出最合适的论断。

就算属性值只可以被实例单独具备,举个例子person对象的name,只好属于某一个person实例,又例如这里拖拽对象中,某一个要素的最初地点,也仅仅只是那几个因素的当前职分,那一个性格,则吻合放在构造函数中。

而假诺两本性质仅仅供内部方法访谈,那几个天性就符合放在模块成效域中。

关于面向对象,上边的几点挂念本人觉着是那篇小说最值得认真想想的美貌。倘使在封装时未有考虑清楚,很大概会碰着比比较多你想不到的bug,所以建议我们结合本人的开销经历,多多怀恋,计算出团结的观念。

依据那个考虑,大家能够团结尝试封装一下。然后与自家的做一些对照,看看大家的主张有如何不一致,在底下例子的解说中,作者将和谐的主见表明出来。

点击查阅已经封装好的demo

js 源码

JavaScript

; (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.add伊夫ntListener('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.remove伊芙ntListener('mousemove', move); document.remove伊芙ntListener('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('target'); new Drag('target2');

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
;
(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('target');
new Drag('target2');

那样一个拖拽对象就封装实现了。

建议大家根据自个儿提供的思索方法,多多尝试封装一些组件。比方封装二个弹窗,封装八个生生不息轮播等。练得多了,面向对象就不再是主题材料了。这种考虑方式,在现在任哪天候都以能够使用的。

下一章深入分析jQuery对象的完结,与什么将大家那边封装的拖拽对象扩展为jQuery插件。

2 赞 1 收藏 评论

图片 3

编辑:关于计算机 本文来源:Resig本身包装的javascript,面向对象实战之封装拖

关键词: