須要實現相似QQ中對聯繫人的操做:向左滑動,滑出刪除按鈕。滑動超過一半時鬆開則自動滑到底,不到一半時鬆開則返回原處。javascript
使用了h5的touchmove等事件,以及用js動態改變css3的translate屬性來達到動畫效果:css
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" id="viewport" content="width=device-width, initial-scale=1"> <title>html5向左滑動刪除特效</title> <style> * { padding: 0; margin: 0; list-style: none; } header { background: #f7483b; border-bottom: 1px solid #ccc } header h2 { text-align: center; line-height: 54px; font-size: 16px; color: #fff } .list-ul { overflow: hidden } .list-li { line-height: 60px; border-bottom: 1px solid #fcfcfc; position: relative; padding: 0 12px; color: #666; background: #f2f2f2; -webkit-transform: translateX(0px); } .btn { position: absolute; top: 0; right: -80px; text-align: center; background: #ffcb20; color: #fff; width: 80px } </style> <script> /* * 描述:html5蘋果手機向左滑動刪除特效 */ window.addEventListener('load', function() { var initX; //觸摸位置 var moveX; //滑動時的位置 var X = 0; //移動距離 var objX = 0; //目標對象位置 window.addEventListener('touchstart', function(event) { event.preventDefault(); var obj = event.target.parentNode; if (obj.className == "list-li") { initX = event.targetTouches[0].pageX; objX = (obj.style.WebkitTransform.replace(/translateX\(/g, "").replace(/px\)/g, "")) * 1; } if (objX == 0) { window.addEventListener('touchmove', function(event) { event.preventDefault(); var obj = event.target.parentNode; if (obj.className == "list-li") { moveX = event.targetTouches[0].pageX; X = moveX - initX; if (X >= 0) { obj.style.WebkitTransform = "translateX(" + 0 + "px)"; } else if (X < 0) { var l = Math.abs(X); obj.style.WebkitTransform = "translateX(" + -l + "px)"; if (l > 80) { l = 80; obj.style.WebkitTransform = "translateX(" + -l + "px)"; } } } }); } else if (objX < 0) { window.addEventListener('touchmove', function(event) { event.preventDefault(); var obj = event.target.parentNode; if (obj.className == "list-li") { moveX = event.targetTouches[0].pageX; X = moveX - initX; if (X >= 0) { var r = -80 + Math.abs(X); obj.style.WebkitTransform = "translateX(" + r + "px)"; if (r > 0) { r = 0; obj.style.WebkitTransform = "translateX(" + r + "px)"; } } else { //向左滑動 obj.style.WebkitTransform = "translateX(" + -80 + "px)"; } } }); } }) window.addEventListener('touchend', function(event) { event.preventDefault(); var obj = event.target.parentNode; if (obj.className == "list-li") { objX = (obj.style.WebkitTransform.replace(/translateX\(/g, "").replace(/px\)/g, "")) * 1; if (objX > -40) { obj.style.WebkitTransform = "translateX(" + 0 + "px)"; objX = 0; } else { obj.style.WebkitTransform = "translateX(" + -80 + "px)"; objX = -80; } } }) }) </script> </head> <body> <header> <h2>消息列表</h2> </header> <section class="list"> <ul class="list-ul"> <li id="li" class="list-li"> <div class="con"> 你的快遞到了,請到樓下簽收 </div> <div class="btn">刪除</div> </li> <li class="list-li"> <div class="con"> 哇,你在幹嗎,快點來啊就等你了 </div> <div class="btn">刪除</div> </li> </ul> </section> </body> </html>
實際項目中,咱們可能有不少個地方會用到這個功能。如今咱們將這個功能作成zepto插件,方便後面使用。html
這個插件,咱們僅實現這個功能,而後傳入參數(刪除按鈕的樣式名),讓程序在js中計算所須要滑動的距離,方便複用。html5
zepto.touchWipe.jsjava
1 /** 2 * zepto插件:向左滑動刪除動效 3 * 使用方法:$('.itemWipe').touchWipe({itemDelete: '.item-delete'}); 4 * 參數:itemDelete 刪除按鈕的樣式名 5 */ 6 ; 7 (function($) { 8 $.fn.touchWipe = function(option) { 9 var defaults = { 10 itemDelete: '.item-delete', //刪除元素 11 }; 12 var opts = $.extend({}, defaults, option); //配置選項 13 14 var delWidth = $(opts.itemDelete).width(); 15 16 var initX; //觸摸位置 17 var moveX; //滑動時的位置 18 var X = 0; //移動距離 19 var objX = 0; //目標對象位置 20 $(this).on('touchstart', function(event) { 21 event.preventDefault(); 22 var obj = this; 23 initX = event.targetTouches[0].pageX; 24 objX = (obj.style.WebkitTransform.replace(/translateX\(/g, "").replace(/px\)/g, "")) * 1; 25 if (objX == 0) { 26 $(this).on('touchmove', function(event) { 27 event.preventDefault(); 28 var obj = this; 29 moveX = event.targetTouches[0].pageX; 30 X = moveX - initX; 31 if (X >= 0) { 32 obj.style.WebkitTransform = "translateX(" + 0 + "px)"; 33 } else if (X < 0) { 34 var l = Math.abs(X); 35 obj.style.WebkitTransform = "translateX(" + -l + "px)"; 36 if (l > delWidth) { 37 l = delWidth; 38 obj.style.WebkitTransform = "translateX(" + -l + "px)"; 39 } 40 } 41 }); 42 } else if (objX < 0) { 43 $(this).on('touchmove', function(event) { 44 event.preventDefault(); 45 var obj = this; 46 moveX = event.targetTouches[0].pageX; 47 X = moveX - initX; 48 if (X >= 0) { 49 var r = -delWidth + Math.abs(X); 50 obj.style.WebkitTransform = "translateX(" + r + "px)"; 51 if (r > 0) { 52 r = 0; 53 obj.style.WebkitTransform = "translateX(" + r + "px)"; 54 } 55 } else { //向左滑動 56 obj.style.WebkitTransform = "translateX(" + -delWidth + "px)"; 57 } 58 }); 59 } 60 61 }) 62 $(this).on('touchend', function(event) { 63 event.preventDefault(); 64 var obj = this; 65 objX = (obj.style.WebkitTransform.replace(/translateX\(/g, "").replace(/px\)/g, "")) * 1; 66 if (objX > -delWidth / 2) { 67 obj.style.transition = "all 0.2s"; 68 obj.style.WebkitTransform = "translateX(" + 0 + "px)"; 69 obj.style.transition = "all 0"; 70 objX = 0; 71 } else { 72 obj.style.transition = "all 0.2s"; 73 obj.style.WebkitTransform = "translateX(" + -delWidth + "px)"; 74 obj.style.transition = "all 0"; 75 objX = -delWidth; 76 } 77 }) 78 79 //鏈式返回 80 return this; 81 }; 82 83 })(Zepto);
touchWipe.htmlcss3
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" id="viewport" content="width=device-width, initial-scale=1"> 6 <title>html5向左滑動刪除特效</title> 7 8 <style> 9 *{ padding:0; margin:0; list-style: none;} 10 header{ background: #f7483b; border-bottom: 1px solid #ccc} 11 header h2{ text-align: center; line-height: 54px; font-size: 16px; color: #fff} 12 .list-ul{ overflow: hidden} 13 .list-li{ line-height: 60px; border-bottom: 1px solid #fcfcfc; position:relative;padding: 0 12px; color: #666; 14 background: #f2f2f2; 15 -webkit-transform: translateX(0px); 16 } 17 .btn{ position: absolute; top: 0; right: -80px; text-align: center; background: #ffcb20; color: #fff; width: 80px} 18 </style> 19 20 </head> 21 <body> 22 <header> 23 <h2>消息列表</h2> 24 </header> 25 <section class="list"> 26 <ul class="list-ul"> 27 <li id="li" class="list-li"> 28 <div class="con"> 29 你的快遞到了,請到樓下簽收 30 </div> 31 <div class="btn">刪除</div> 32 </li> 33 <li class="list-li"> 34 <div class="con"> 35 哇,你在幹嗎,快點來啊就等你了 36 </div> 37 <div class="btn">刪除</div> 38 </li> 39 </ul> 40 </section> 41 42 <p>X: <span id="X"></span></p> 43 <p>objX: <span id="objX"></span></p> 44 <p>initX: <span id="initX"></span></p> 45 <p>moveX: <span id="moveX"></span></p> 46 47 <script type="text/javascript" src="http://apps.bdimg.com/libs/zepto/1.1.4/zepto.min.js"></script> 48 <script type="text/javascript" src="zepto.touchWipe.js"></script> 49 <script type="text/javascript"> 50 $(function() { 51 $('.list-li').touchWipe({itemDelete: '.btn'}); 52 }); 53 54 </script> 55 </body> 56 </html>
效果:web
實際項目中的應用效果:瀏覽器
到上面一步,基本實現了咱們所須要的功能。可是有幾個問題:app
1. 右邊的刪除按鈕點擊失靈,由於span沒法冒泡到大按鈕上;動畫
2. 很是嚴重的問題,咱們給div添加了touchmove事件同時用preventDefault()屏蔽了原始的瀏覽器事件,致使上下滑動div的時候 頁面沒法滾動了!
第一個問題比較容易解決,咱們把span直接去掉,將「刪除」寫到css中的:before裏,像這樣:
.itemWipe .item-delete:before { content: '刪除'; color: #fff; }
對於第二個問題,網上說用iscroll來解決。咱們這裏參考手機QQ中對聯繫人的滑動操做。
大體原理:在滑動最開始的時候,判斷是Y軸的移動多 仍是 X軸的移動多。 若是是X軸移動大,則判斷爲滑動刪除操做,咱們再使用preventDefault();
其中,咱們加入一個變量flaxX來判斷滑動方向,會在第一次觸發滑動事件時設置。
以後就能夠根據滑動方向來選擇是否阻止瀏覽器默認事件了。
修改後: zepto.touchWipe.js
1 /** 2 * zepto插件:向左滑動刪除動效 3 * 使用方法:$('.itemWipe').touchWipe({itemDelete: '.item-delete'}); 4 * 參數:itemDelete 刪除按鈕的樣式名 5 */ 6 ; 7 (function($) { 8 $.fn.touchWipe = function(option) { 9 var defaults = { 10 itemDelete: '.item-delete', //刪除元素 11 }; 12 var opts = $.extend({}, defaults, option); //配置選項 13 var delWidth = $(opts.itemDelete).width(); 14 15 var initX; //觸摸位置X 16 var initY; //觸摸位置Y 17 var moveX; //滑動時的位置X 18 var moveY; //滑動時的位置Y 19 var X = 0; //移動距離X 20 var Y = 0; //移動距離Y 21 var flagX = 0; //是不是左右滑動 0爲初始,1爲左右,2爲上下,在move中設置,在end中歸零 22 var objX = 0; //目標對象位置 23 24 $(this).on('touchstart', function(event) { 25 console.log('start..'); 26 var obj = this; 27 initX = event.targetTouches[0].pageX; 28 initY = event.targetTouches[0].pageY; 29 console.log(initX + ':' + initY); 30 objX = (obj.style.WebkitTransform.replace(/translateX\(/g, "").replace(/px\)/g, "")) * 1; 31 console.log (objX); 32 if (objX == 0) { 33 $(this).on('touchmove', function(event) { 34 35 // 判斷滑動方向,X軸阻止默認事件,Y軸跳出使用瀏覽器默認 36 if (flagX == 0) { 37 setScrollX(event); 38 return; 39 } else if (flagX == 1) { 40 event.preventDefault(); 41 } else { 42 return; 43 } 44 45 var obj = this; 46 moveX = event.targetTouches[0].pageX; 47 X = moveX - initX; 48 if (X >= 0) { 49 obj.style.WebkitTransform = "translateX(" + 0 + "px)"; 50 } else if (X < 0) { 51 var l = Math.abs(X); 52 obj.style.WebkitTransform = "translateX(" + -l + "px)"; 53 if (l > delWidth) { 54 l = delWidth; 55 obj.style.WebkitTransform = "translateX(" + -l + "px)"; 56 } 57 } 58 }); 59 } else if (objX < 0) { 60 $(this).on('touchmove', function(event) { 61 62 // 判斷滑動方向,X軸阻止默認事件,Y軸跳出使用瀏覽器默認 63 if (flagX == 0) { 64 setScrollX(event); 65 return; 66 } else if (flagX == 1) { 67 event.preventDefault(); 68 } else { 69 return; 70 } 71 72 var obj = this; 73 moveX = event.targetTouches[0].pageX; 74 X = moveX - initX; 75 if (X >= 0) { 76 var r = -delWidth + Math.abs(X); 77 obj.style.WebkitTransform = "translateX(" + r + "px)"; 78 if (r > 0) { 79 r = 0; 80 obj.style.WebkitTransform = "translateX(" + r + "px)"; 81 } 82 } else { //向左滑動 83 obj.style.WebkitTransform = "translateX(" + -delWidth + "px)"; 84 } 85 }); 86 } 87 }) 88 89 //結束時判斷,並自動滑動到底或返回 90 $(this).on('touchend', function(event) { 91 var obj = this; 92 objX = (obj.style.WebkitTransform.replace(/translateX\(/g, "").replace(/px\)/g, "")) * 1; 93 if (objX > -delWidth / 2) { 94 obj.style.transition = "all 0.2s"; 95 obj.style.WebkitTransform = "translateX(" + 0 + "px)"; 96 obj.style.transition = "all 0"; 97 objX = 0; 98 } else { 99 obj.style.transition = "all 0.2s"; 100 obj.style.WebkitTransform = "translateX(" + -delWidth + "px)"; 101 obj.style.transition = "all 0"; 102 objX = -delWidth; 103 } 104 flagX = 0; 105 }) 106 107 //設置滑動方向 108 function setScrollX(event) { 109 moveX = event.targetTouches[0].pageX; 110 moveY = event.targetTouches[0].pageY; 111 X = moveX - initX; 112 Y = moveY - initY; 113 114 if (Math.abs(X) > Math.abs(Y)) { 115 flagX = 1; 116 } else { 117 flagX = 2; 118 } 119 return flagX; 120 } 121 122 //鏈式返回 123 return this; 124 }; 125 126 })(Zepto);