摘要:上一周學了閉包和模塊,這一周仍然是跟著波同學,試著封裝了一個拖拽模塊。
上一周學了閉包和模塊,這一周仍然是跟著@波同學,試著封裝了一個拖拽模塊。過程中經歷了一些曲折,最開始我是打算只用style.left的方式,但是這個需要設置position:absolute。可能對代碼造成一定影響。雖然CSS的transform會影響兼容,但這里我還是使用了這個屬性的translate來完成移動。只用style完成的代碼
話不多說,直接上代碼:
html和css,這里必須設置position,第一次寫這段代碼的時候忘了,結果盡管JS寫對了,效果完全出不來....真是短路了
重點!!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 = "", divStyle = document.createElement("div").style, transformArr = ["transform", "webkitTransform", "MozTransform", "msTransform", "oTransform"], i = 0, l = transformArr.length; for (; i < l; i++) { if (transformArr[i] in divStyle) { 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 = "", divStyle = document.createElement("div").style, transformArr = ["transform", "webkitTransform", "MozTransform", "msTransform", "oTransform"], i = 0, l = transformArr.length; for (; i < l; i++) { if (transformArr[i] in divStyle) { return transform = transformArr[i]; } } return transform; } //暴露在外 window.Drag = Drag; })(); new Drag("box");
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/107087.html
摘要:一背景業務組件化或者叫模塊化作為移動端應用架構的主流方式之一,近年來一直是業界積極探索和實踐的方向。有贊移動團隊自年起也在不斷嘗試各種組件化方案,在有贊微商城,有贊零售,有贊美業等多個應用中進行了實踐。相比組件,個人感覺稱之為模塊更為合適。 一、背景 業務組件化(或者叫模塊化)作為移動端應用架構的主流方式之一,近年來一直是業界積極探索和實踐的方向。有贊移動團隊自16年起也在不斷嘗試各種...
摘要:前面幾篇文章,我跟大家分享了的一些基礎知識,這篇文章,將會進入第一個實戰環節利用前面幾章的所涉及到的知識,封裝一個拖拽對象。不封裝對象直接實現利用原生封裝拖拽對象通過擴展來實現拖拽對象。 showImg(https://segmentfault.com/img/remote/1460000008699587); 前面幾篇文章,我跟大家分享了JavaScript的一些基礎知識,這篇文章,...
摘要:也是的獨特性,使得組件化成為了可能。簡單的說就是組件內部標簽對內語義化,組件自定義標簽對外語義化對內語義化保存自定義標簽具有正確的語義,自定義標簽對外語義是對內部標簽組合出的功能概括。 組件化 這里首先介紹WebComponents標準,以下為騰訊alloyteam團隊的一篇文章里的內容。 模板能力,WebComponent提供原生的模板能力 ShadowDOm封裝組件獨立的內部結構...
摘要:重試會增加的響應時間。提供了輔助方法來為包含遠程調用的函數式接口或表達式創建裝飾器。如果我們想創建一個裝飾器并在代碼庫的不同位置重用它,我們將使用。 在本文中,我們將從快速介紹 Resilience4j 開始,然后深入探討其 Retry 模塊。我們將了解何時、如何使用它,以及它提供的功能。在此過程中,我們還將學...
摘要:下面列舉了游戲開發中常見的崗位以及兩條常見的協作開發的流水線其實學習游戲引擎,前期對于任何崗位來說路線都是相似的,基本上就是一個熟悉基本操作理解基本概念拓展專業知識的過程。當然這不是絕對的,任何引擎的開始階段和大成階段都是相似的。 這是【游戲開發那些事】第51篇原創 前言:游戲引擎,表面...
閱讀 3104·2021-10-13 09:40
閱讀 3959·2021-09-22 15:51
閱讀 1504·2021-09-22 15:48
閱讀 1073·2021-09-06 15:00
閱讀 1797·2019-08-30 15:43
閱讀 2367·2019-08-29 18:35
閱讀 1678·2019-08-29 16:18
閱讀 3622·2019-08-29 12:49