基于jQuery的左滑出現(xiàn)刪除按鈕的示例
最近在做項(xiàng)目的時(shí)候遇到了個(gè)需求,在網(wǎng)頁(yè)上實(shí)現(xiàn)類似于QQ會(huì)話列表那樣子的左滑出現(xiàn)刪除按鈕的效果,于是嘗試著寫(xiě)了一個(gè),寫(xiě)出來(lái)與大家交流分享,大神勿噴。
基本要求
由于我們是在做一個(gè)跨平臺(tái)的APP,里面部分界面其實(shí)就是WebView加載的網(wǎng)頁(yè),因此需要使用網(wǎng)頁(yè)實(shí)現(xiàn)這樣的效果:往左滑動(dòng)時(shí),顯示刪除按鈕,再往右滑,隱藏刪除按鈕。
成品示例圖
額,先上圖吧。下面分別是在PC瀏覽器里和在Mobile瀏覽器里的效果。
PC瀏覽器
手機(jī)瀏覽器
實(shí)現(xiàn)思路
為了說(shuō)明我的實(shí)現(xiàn)思路,做了兩個(gè)圖來(lái)輔助說(shuō)明。
首先,請(qǐng)看圖1。在圖中,我們?cè)O(shè)置每一行的寬度超過(guò)瀏覽器的寬度,其超出的部分就是放置按鈕的區(qū)域。由于超出了瀏覽器的最大寬度,因此按鈕區(qū)域此時(shí)是不可見(jiàn)的,只能顯示左側(cè)的常規(guī)信息部分。
圖1 普通狀態(tài)
接下來(lái),我們監(jiān)聽(tīng)左側(cè)常規(guī)信息區(qū)域,監(jiān)聽(tīng)滑動(dòng)事件(具體如何監(jiān)聽(tīng)先不考慮)。當(dāng)我們監(jiān)聽(tīng)到左滑事件時(shí),我們讓相應(yīng)行左偏移,讓按鈕顯示出來(lái),同時(shí)左側(cè)超出的部分被遮擋(請(qǐng)看圖2)。
圖2 左滑狀態(tài)
當(dāng)我們右滑時(shí),我們?cè)僮屜鄳?yīng)行回復(fù)到左偏移為0的時(shí)候就行了。
關(guān)鍵實(shí)現(xiàn)方式
對(duì)于左滑和右滑,我們通過(guò)設(shè)定常規(guī)信息區(qū)域的marin-left來(lái)實(shí)現(xiàn),當(dāng)設(shè)定margin-left為負(fù)值時(shí),實(shí)現(xiàn)左滑,當(dāng)再次設(shè)定margin-left為0時(shí),實(shí)現(xiàn)右滑。
對(duì)于滑動(dòng)事件監(jiān)聽(tīng),通過(guò)監(jiān)聽(tīng)鼠標(biāo)(手指)按下和抬起來(lái)實(shí)現(xiàn),根據(jù)兩點(diǎn)的X坐標(biāo)的差值的正負(fù)判定是右滑還是左滑。
完整代碼
需要注意的是,我在測(cè)試的時(shí)候用的是chrome的普通模式和mobile模擬器模式,發(fā)現(xiàn)兩種模式下監(jiān)聽(tīng)是不一樣的,因此我寫(xiě)了兩種監(jiān)聽(tīng),這樣至少有一種會(huì)執(zhí)行。也許有其他更好的適配方法,但不作為此處的重點(diǎn)。當(dāng)然也歡迎大家賜教。
至于代碼部分,用了jQuery,其實(shí)不用也沒(méi)啥問(wèn)題的,動(dòng)畫(huà)滑動(dòng)和監(jiān)聽(tīng)都可以用純js寫(xiě),但是由于這不是這里的重點(diǎn),那么為什么不用jQuery呢?成功者站在巨人的肩膀上,而且咱也沒(méi)有jQuery寫(xiě)的好 (。・`ω´・)
2015/11/13更新
有位同學(xué)提出說(shuō)代碼在QQ手機(jī)瀏覽器和Opera手機(jī)瀏覽器等中沒(méi)有滑動(dòng)效果,找了一下大概是帖子里說(shuō)的原因,于是根據(jù)帖子里的提示以及那位同學(xué)的一個(gè)大神同學(xué)的提示,做了一下修改。主要是在touchmove事件中根據(jù)橫縱坐標(biāo)位移來(lái)判斷是否阻止默認(rèn)事件,如下:
// 橫向位移大于縱向位移,阻止縱向滾動(dòng) if (Math.abs(delta.x) > Math.abs(delta.y)) { event.preventDefault(); }
2016/02/25更新
qq_25558115同學(xué)提到:“如果再能給大家提供出只能有一條記錄可以左滑, 倘若滑動(dòng)其他的記錄,則有左滑記錄的要回到原位”。于是進(jìn)行了簡(jiǎn)單實(shí)現(xiàn)。主要思路如下:
// 用一個(gè)變量記錄上一次左滑的對(duì)象 var lastLeftObj; // 在左滑發(fā)生的時(shí)候,判定上一個(gè)左滑的對(duì)象是否存在,若存在,且不是當(dāng)前被左滑的對(duì)象,則將其右滑 // 同時(shí),記錄新的左滑對(duì)象 // 在右滑發(fā)生時(shí),將上一個(gè)左滑對(duì)象清空 if (左滑) { pressedObj左滑 lastLeftObj && lastLeftObj != pressedObj && lastLeftObj右滑 lastLeftObj = pressedObj; // 記錄上一個(gè)左滑的對(duì)象 } else if (右滑) { pressedObj右滑 lastLeftObj = null; // 清空上一個(gè)左滑的對(duì)象 }
2016/09/06更新
根據(jù)馬燦發(fā)同學(xué)提出的bug進(jìn)行修改:
右滑時(shí)進(jìn)行判斷,僅當(dāng)要右滑的對(duì)象(pressedObj)是上一次左滑的對(duì)象(lastLeftObj)時(shí)才將對(duì)象右滑并清空l(shuí)astLeftObj。
if (pressedObj == lastLeftObj) {...}
根據(jù)girlyougo同學(xué)的提議,添加“在除本行外的其他區(qū)域點(diǎn)擊時(shí)均復(fù)位當(dāng)前左滑按鈕”的功能。思路為在滑動(dòng)結(jié)束時(shí),判定pressedObj!=lastLeftObj,即可知點(diǎn)擊/滑動(dòng)的對(duì)象為其他對(duì)象:
// 點(diǎn)擊除當(dāng)前左滑對(duì)象之外的任意其他位置 if (lastLeftObj && pressedObj != lastLeftObj) { $(lastLeftObj).animate({marginLeft:"0"}, 500); // 右滑 lastLeftObj = null; // 清空上一個(gè)左滑的對(duì)象 }
實(shí)際上,在添加了上述功能之后,前面提到的bug不存在了。不過(guò)此處保留了消除bug的那部分代碼。
更新后的完整代碼如下:
<!doctype html> <html> <head> <meta charset="utf-8"> <title>左劃出現(xiàn)刪除按鈕,右滑隱藏</title> <script type="text/javascript" src="jquery-1.11.2.min.js"></script> <script type="text/javascript"> $(document).ready(function(e) { // 設(shè)定每一行的寬度=屏幕寬度+按鈕寬度 $(".line-scroll-wrapper").width($(".line-wrapper").width() + $(".line-btn-delete").width()); // 設(shè)定常規(guī)信息區(qū)域?qū)挾?屏幕寬度 $(".line-normal-wrapper").width($(".line-wrapper").width()); // 設(shè)定文字部分寬度(為了實(shí)現(xiàn)文字過(guò)長(zhǎng)時(shí)在末尾顯示...) $(".line-normal-msg").width($(".line-normal-wrapper").width() - 280); // 獲取所有行,對(duì)每一行設(shè)置監(jiān)聽(tīng) var lines = $(".line-normal-wrapper"); var len = lines.length; var lastX, lastXForMobile; // 用于記錄被按下的對(duì)象 var pressedObj; // 當(dāng)前左滑的對(duì)象 var lastLeftObj; // 上一個(gè)左滑的對(duì)象 // 用于記錄按下的點(diǎn) var start; // 網(wǎng)頁(yè)在移動(dòng)端運(yùn)行時(shí)的監(jiān)聽(tīng) for (var i = 0; i < len; ++i) { lines[i].addEventListener('touchstart', function(e){ lastXForMobile = e.changedTouches[0].pageX; pressedObj = this; // 記錄被按下的對(duì)象 // 記錄開(kāi)始按下時(shí)的點(diǎn) var touches = event.touches[0]; start = { x: touches.pageX, // 橫坐標(biāo) y: touches.pageY // 縱坐標(biāo) }; }); lines[i].addEventListener('touchmove',function(e){ // 計(jì)算劃動(dòng)過(guò)程中x和y的變化量 var touches = event.touches[0]; delta = { x: touches.pageX - start.x, y: touches.pageY - start.y }; // 橫向位移大于縱向位移,阻止縱向滾動(dòng) if (Math.abs(delta.x) > Math.abs(delta.y)) { event.preventDefault(); } }); lines[i].addEventListener('touchend', function(e){ if (lastLeftObj && pressedObj != lastLeftObj) { // 點(diǎn)擊除當(dāng)前左滑對(duì)象之外的任意其他位置 $(lastLeftObj).animate({marginLeft:"0"}, 500); // 右滑 lastLeftObj = null; // 清空上一個(gè)左滑的對(duì)象 } var diffX = e.changedTouches[0].pageX - lastXForMobile; if (diffX < -150) { $(pressedObj).animate({marginLeft:"-132px"}, 500); // 左滑 lastLeftObj && lastLeftObj != pressedObj && $(lastLeftObj).animate({marginLeft:"0"}, 500); // 已經(jīng)左滑狀態(tài)的按鈕右滑 lastLeftObj = pressedObj; // 記錄上一個(gè)左滑的對(duì)象 } else if (diffX > 150) { if (pressedObj == lastLeftObj) { $(pressedObj).animate({marginLeft:"0"}, 500); // 右滑 lastLeftObj = null; // 清空上一個(gè)左滑的對(duì)象 } } }); } // 網(wǎng)頁(yè)在PC瀏覽器中運(yùn)行時(shí)的監(jiān)聽(tīng) for (var i = 0; i < len; ++i) { $(lines[i]).bind('mousedown', function(e){ lastX = e.clientX; pressedObj = this; // 記錄被按下的對(duì)象 }); $(lines[i]).bind('mouseup', function(e){ if (lastLeftObj && pressedObj != lastLeftObj) { // 點(diǎn)擊除當(dāng)前左滑對(duì)象之外的任意其他位置 $(lastLeftObj).animate({marginLeft:"0"}, 500); // 右滑 lastLeftObj = null; // 清空上一個(gè)左滑的對(duì)象 } var diffX = e.clientX - lastX; if (diffX < -150) { $(pressedObj).animate({marginLeft:"-132px"}, 500); // 左滑 lastLeftObj && lastLeftObj != pressedObj && $(lastLeftObj).animate({marginLeft:"0"}, 500); // 已經(jīng)左滑狀態(tài)的按鈕右滑 lastLeftObj = pressedObj; // 記錄上一個(gè)左滑的對(duì)象 } else if (diffX > 150) { if (pressedObj == lastLeftObj) { $(pressedObj).animate({marginLeft:"0"}, 500); // 右滑 lastLeftObj = null; // 清空上一個(gè)左滑的對(duì)象 } } }); } }); </script> <style type="text/css"> * { margin: 0; padding: 0; } .line-wrapper { width: 100%; height: 144px; overflow: hidden; font-size: 28px; border-bottom: 1px solid #aaa; } .line-scroll-wrapper { white-space: nowrap; height: 144px; clear: both; } .line-btn-delete { float: left; width: 132px; height: 144px; } .line-btn-delete button { width: 100%; height: 100%; background: red; border: none; font-size: 24px; font-family: 'Microsoft Yahei'; color: #fff; } .line-normal-wrapper { display: inline-block; line-height: 100px; float: left; padding-top: 10px; padding-bottom: 10px; } .line-normal-icon-wrapper { float: right; width: 120px; height: 120px; margin-right: 12px; } .line-normal-icon-wrapper img { width: 120px; height: 120px; } .line-normal-avatar-wrapper { width: 100px; height: 124px; float: left; margin-left: 12px; } .line-normal-avatar-wrapper img { width: 92px; height: 92px; border-radius: 60px; } .line-normal-left-wrapper { float: left; overflow: hidden; } .line-normal-info-wrapper { float: left; margin-left: 10px; } .line-normal-user-name { height: 28px; line-height: 28px; color: #4e4e4e; margin-top: 7px; } .line-normal-msg { height: 28px; line-height: 28px; overflow:hidden; text-overflow:ellipsis; color: #4e4e4e; margin-top: 11px; } .line-normal-time { height: 28px; line-height: 28px; color: #999; margin-top: 11px; } </style> </head> <body> <div class="line-wrapper"> <div class="line-scroll-wrapper"> <div class="line-normal-wrapper"> <div class="line-normal-left-wrapper"> <div class="line-normal-avatar-wrapper"><img src="1.jpg" /></div> <div class="line-normal-info-wrapper"> <div class="line-normal-user-name">蠟筆小新</div> <div class="line-normal-msg">在同行的小伙伴中提到了你</div> <div class="line-normal-time">1分鐘前</div> </div> </div> <div class="line-normal-icon-wrapper"><img src="5.jpg"/></div> </div> <div class="line-btn-delete"><button>刪除</button></div> </div> </div> <div class="line-wrapper"> <div class="line-scroll-wrapper"> <div class="line-normal-wrapper"> <div class="line-normal-left-wrapper"> <div class="line-normal-avatar-wrapper"><img src="2.jpg" /></div> <div class="line-normal-info-wrapper"> <div class="line-normal-user-name">喬巴</div> <div class="line-normal-msg">你看不到我哦</div> <div class="line-normal-time">1分鐘前</div> </div> </div> <div class="line-normal-icon-wrapper"><img src="6.jpg"/></div> </div> <div class="line-btn-delete"><button>刪除</button></div> </div> </div> <div class="line-wrapper"> <div class="line-scroll-wrapper"> <div class="line-normal-wrapper"> <div class="line-normal-left-wrapper"> <div class="line-normal-avatar-wrapper"><img src="3.jpg" /></div> <div class="line-normal-info-wrapper"> <div class="line-normal-user-name">賤行賤遠(yuǎn)</div> <div class="line-normal-msg">回憶里想起模糊的小時(shí)候,云朵漂浮在藍(lán)藍(lán)的天空,那時(shí)的你說(shuō),要和我手牽手,一起走到時(shí)間的盡頭</div> <div class="line-normal-time">1分鐘前</div> </div> </div> <div class="line-normal-icon-wrapper"><img src="7.jpg"/></div> </div> <div class="line-btn-delete"><button>刪除</button></div> </div> </div> <div class="line-wrapper"> <div class="line-scroll-wrapper"> <div class="line-normal-wrapper"> <div class="line-normal-left-wrapper"> <div class="line-normal-avatar-wrapper"><img src="4.png" /></div> <div class="line-normal-info-wrapper"> <div class="line-normal-user-name">小黃人</div> <div class="line-normal-msg">哈哈哈哈哈……暑假來(lái)看小黃人電影哦~哈哈哈……</div> <div class="line-normal-time">1分鐘前</div> </div> </div> <div class="line-normal-icon-wrapper"><img src="8.jpg"/></div> </div> <div class="line-btn-delete"><button>刪除</button></div> </div> </div> </body> </html>
總結(jié)
代碼還比較粗糙,存在很多bug,也有些地方不是那么絕對(duì)。比如當(dāng)我按下時(shí)是在第一條記錄,然后抬起時(shí)是在第二條記錄,那么這時(shí)候滑動(dòng)將是第一條記錄。但是這個(gè)看具體需求了,如果你覺(jué)得滑動(dòng)的對(duì)象應(yīng)該以按下去時(shí)的對(duì)象為準(zhǔn)的話,那就不管在哪抬起都滑動(dòng)那個(gè)按下時(shí)的對(duì)象;如果你覺(jué)得滑動(dòng)的對(duì)象應(yīng)該是抬起時(shí)的對(duì)象,那也沒(méi)問(wèn)題,或者你覺(jué)得按下和抬起時(shí)不是同一個(gè)對(duì)象就不滑動(dòng)任何對(duì)象那也行??傊葱枨?。
源碼請(qǐng)戳:源碼下載
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
jquery 判斷div show的狀態(tài)實(shí)例
下面小編就為大家?guī)?lái)一篇jquery 判斷div show的狀態(tài)實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,祝大家游戲愉快哦2016-12-12ASP.NET中AJAX 調(diào)用實(shí)例代碼
最近在ASP.NET中做了一個(gè)AJAX調(diào)用 : Client端先從ASP.NET Server后臺(tái)取到一個(gè)頁(yè)面模板,然后在頁(yè)面初始化時(shí)再?gòu)腟erver中取一些相關(guān)數(shù)據(jù)以實(shí)現(xiàn)頁(yè)面模板的動(dòng)態(tài)顯示2012-05-05擴(kuò)展Jquery插件處理mouseover時(shí)內(nèi)部有子元素時(shí)發(fā)生樣式閃爍
在我們對(duì)一個(gè)dom添加mouseover和mouseout時(shí),也就是jquery的hover事件,如果該dom有子元素,鼠標(biāo)移到子元素時(shí)會(huì)觸發(fā)mouseout事件,但往往實(shí)際情況我們希望在子元素上不觸發(fā)out事件2011-12-12bootstrap+jquery項(xiàng)目引入文件報(bào)錯(cuò)的解決方法
這篇文章主要介紹了bootstrap+jquery項(xiàng)目引入文件的常見(jiàn)報(bào)錯(cuò)問(wèn)題,下面小編給大家?guī)?lái)了一些錯(cuò)誤及錯(cuò)誤的解決方法,需要的朋友可以參考下2018-01-01jQuery中serializeArray()與serialize()的區(qū)別實(shí)例分析
這篇文章主要介紹了jQuery中serializeArray()與serialize()的區(qū)別,結(jié)合實(shí)例形式分析了jQuery中serializeArray()與serialize()的具體功能、使用技巧與用法區(qū)別,需要的朋友可以參考下2015-12-12