成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

原生 js 實(shí)現(xiàn)移動端 Touch 滑動反彈

xiongzenghui / 2065人閱讀

摘要:移動端滑動反彈什么是滑動就是類似于端的滾動事件,但是在移動端是沒有滾動事件的,所以就要用到事件結(jié)合去實(shí)現(xiàn),效果如下準(zhǔn)備工作什么是移動端的事件在移動端事件可以細(xì)分成三種,分別是和,并且事件必須要用去監(jiān)聽。

移動端 Touch 滑動反彈
什么是Touch滑動?就是類似于PC端的滾動事件,但是在移動端是沒有滾動事件的,所以就要用到Touch事件結(jié)合js去實(shí)現(xiàn),效果如下:

1. 準(zhǔn)備工作
什么是移動端的Touch事件?在移動端Touch事件可以細(xì)分成三種,分別是:touchstart、touchmovetouchend,并且touch事件必須要用addEventListener去監(jiān)聽。

touchStart當(dāng)手指觸碰到屏幕的時(shí)候觸發(fā)

touchmove當(dāng)手指在屏幕上不斷移動的時(shí)候觸發(fā)

touchend當(dāng)手指離開屏幕的時(shí)候觸發(fā)

Touch 事件觸發(fā)的 Event 對象:

// 手指觸碰到屏幕時(shí)觸發(fā)
element.addEventListener("touchstart", function (e) {
    // 打印的事件對象
    console.log(e);
})

changedTouches、targetTouches、touches都是偽數(shù)組,里面裝的是手指列表

三種返回對象的區(qū)別:

其實(shí)這三種返回的對象,都是表示用戶觸摸事件時(shí)的手指信息,之所以是一個(gè)偽數(shù)組,是因?yàn)橛锌赡艹霈F(xiàn)多指同時(shí)觸摸,但是在實(shí)際工作中一般不去考慮多指的情況。而它們唯一的區(qū)別就是在touchstarttouchmove事件的時(shí)候,changedTouches、targetTouches、touches都能獲取到手指的信息,但是在touchend事件的時(shí)候,targetTouches、touches對象是不能返回離開屏幕時(shí)的手指信息,只有changedTouches對象能返回。

有哪些手指信息?

我們可以看下上面的圖片,在changedTouche[0]中,有些值:
clientX:74    // 觸摸點(diǎn)相對于瀏覽器的 viewport 左邊緣的 x 坐標(biāo),不會包括左邊的滾動距離。
clientY:73    // 觸摸點(diǎn)相對于瀏覽器的 viewport 上邊緣的 Y 坐標(biāo),不會包括上邊的滾動距離。
screenX:2202  // 觸摸點(diǎn)相對于屏幕左邊緣的 x 坐標(biāo)。
screenY:327   // 觸摸點(diǎn)相對于屏幕上邊緣的 Y 坐標(biāo)。
pageX:65      // 觸摸點(diǎn)相對于 document 的左邊緣的 x 坐標(biāo),包括左邊的滾動距離
pageY:18      // 觸摸點(diǎn)相對于 document 的上邊緣的 Y 坐標(biāo),包括左邊的滾動距離
2. 基本結(jié)構(gòu)
此案例模擬的是移動端的一種滑動菜單效果。

HTML部分:

css部分:

在列表的父盒子上設(shè)定一個(gè)overflow: hidden屬性,使超出盒子部分的列表暫時(shí)隱藏掉,后面會通過js去實(shí)現(xiàn)滑動。
/* 樣式初始化 */
* {
  margin: 0;
  padding: 0;
}

html,
body {
  width: 100%;

}

aside {
  height: 100%;
  width: 100%;
}
/* 列表的父盒子,限制寬高 */
/* 注意設(shè)置overflow: hidden;樣式后,超出這個(gè)盒子的ul將不會顯示 */
.draw {
  width: 60px;
  height: 500px;
  border: 2px solid #ccc;
  overflow: hidden;
  position: fixed;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
}

/* li 設(shè)置了浮動, 所以 ul 要清除浮動 */
ul:after {
  content: "";
  display: block;
  visibility: hidden;
  height: 0;
  clear: both;
}

ul {
  zoom: 1;
}

li {
  list-style: none;
  float: left;
  width: 60px;
  height: 60px;
  line-height: 60px;
  text-align: center;
}

效果圖:

3. 首次滑動
手指觸摸到列表向下滑動的時(shí)候,列表應(yīng)該跟著向下滑動,當(dāng)手指離開屏幕的時(shí)候,列表應(yīng)該停在滑動的位置。這里就會用到上面準(zhǔn)備階段的知識點(diǎn)了,不明白的可以參考上面的概念。

實(shí)現(xiàn)原理:

1、touchstart的時(shí)候,獲取手指觸摸的落點(diǎn)A,通過這個(gè)點(diǎn)對象里面的clientY屬性,獲取距離頂部可視區(qū)的距離;

2、touchmove的時(shí)候,獲取手指的點(diǎn)B,同樣的獲取移動時(shí)距離頂部可視區(qū)的距離;

3、touchmove的時(shí)候,還要做另一件事情,就是獲取兩點(diǎn)的差值(B.clientY-A.clientY),將這個(gè)差值動態(tài)賦值給ul,ul只需要設(shè)置向Y軸方向偏移這個(gè)距離,就能實(shí)現(xiàn)列表隨手指滑動

先來張示意圖,怎么通過 js 讓列表滑動起來:

示例代碼:

var draw = document.querySelector("#draw");
var ul = draw.children[0];

// touchstart 時(shí),記錄手指在 Y 軸上的落點(diǎn)距離可視頂部距離
var startY = 0
ul.addEventListener("touchstart", function (e) {
  startY = e.changedTouches[0].clientY;
})

// touchmove 時(shí),記錄此時(shí)手指在 Y 軸上的落點(diǎn)距離可視頂部距離
ul.addEventListener("touchmove", function (e) {
  // 獲取差值
  var dy = e.changedTouches[0].clientY - startY;
  // 設(shè)置 ul 在 Y 軸上的偏移
  ul.style.transform = "translateY(" + dy + "px)";
})

效果圖:

4. 再次滑動
上面的效果圖,細(xì)心的朋友可能已經(jīng)發(fā)現(xiàn)了問題,在第一次的時(shí)候,得到了我們想要的效果,但是在第二次的時(shí)候,我們繼續(xù)向下移動了一段距離,但是ul并沒有接著第一次的位置繼續(xù)向下,而是瞬間跳了上去。

問題分析:

雖然第二次是繼續(xù)向下移動了一段距離,但是觸摸結(jié)束后,最終是將此時(shí)的差值,重新賦值給了ulY軸偏移,所以視覺上“跳了上去”。

解決方法:

每一次滑動結(jié)束之后,都應(yīng)該記錄下此次滑動的距離,與之前的進(jìn)行累加,待下一次滑動的時(shí)候,ulY軸的偏移值應(yīng)該是之前的距離加上本次滑動的距離。

新增touchend事件,在該事件里同樣的可以獲取到本次滑動的距離,將它與上一次的距離相加,賦值給一個(gè)全局變量;

touchmove事件里有點(diǎn)小改動,就是在給ul設(shè)置偏移值的時(shí)候,除了本次滑動的差值還要加上這個(gè)上一次的值;

示意圖:

示例代碼:

var draw = document.querySelector("#draw");
var ul = draw.children[0];

var startY = 0 // 剛觸碰到屏幕的時(shí)的手指信息
var centerY = 0 // 用來記錄每次觸摸時(shí)上一次的偏移距離

// touchstart 時(shí),記錄手指在 Y 軸上的落點(diǎn)距離可視頂部距離
ul.addEventListener("touchstart", function (e) {
  startY = e.changedTouches[0].clientY;
})

// touchmove 時(shí),記錄此時(shí)手指在 Y 軸上的落點(diǎn)距離可視頂部距離
ul.addEventListener("touchmove", function (e) {
  // 獲取差值
  var dy = e.changedTouches[0].clientY - startY;
  // 上次的滑動距離加上本次的滑動距離
  var tempY = centerY + dy;
  // 設(shè)置 ul 在 Y 軸上的偏移
  ul.style.transform = "translateY(" + tempY + "px)";
})

// touchend 時(shí),記錄此時(shí)手指在 Y 軸上的落點(diǎn)距離可視頂部距離
ul.addEventListener("touchend", function (e) {
  // 獲取差值
  var dy = e.changedTouches[0].clientY - startY;
  // 記錄移動的距離
  centerY = centerY + dy;
})

效果圖:

5. 限制滑動區(qū)間
到上面一步,我們已經(jīng)可以實(shí)現(xiàn)列表的滑動了,但是也存在一個(gè)問題,就是向上或者向下的時(shí)候沒有限制,上下可以無限的滑動,甚至再用點(diǎn)力,就看不到列表了。為了美觀和實(shí)用,這樣肯定不行的,需要給它設(shè)定一個(gè)區(qū)間,設(shè)定向上或者向下最多只能留白多少。

限制向下滑動最大區(qū)間:

設(shè)定向下最大區(qū)間的值比較簡單,直接設(shè)定一個(gè)值,當(dāng)上一次滑動的距離加上本次滑動的距離大于這個(gè)值的時(shí)候,就不讓它再繼續(xù)往下滑了,讓他直接等于這個(gè)設(shè)定的值。

示例代碼:

var maxDown = 50; // 設(shè)定一個(gè)最大向下滑動的距離

// touchmove 時(shí),記錄此時(shí)手指在 Y 軸上的落點(diǎn)距離可視頂部距離
ul.addEventListener("touchmove", function (e) {
  // 獲取差值
  var dy = e.changedTouches[0].clientY - startY;

  // 上次的滑動距離加上本次的滑動距離
  var tempY = centerY + dy;

  // 當(dāng)上次滑動的距離加上本次滑動的距離 大于 設(shè)定的最大向下距離的時(shí)候
  if (tempY > maxDown) {
    // 直接讓偏移的值 等于這個(gè)設(shè)定值
    tempY = maxDown;
  }

  // 設(shè)置 ul 在 Y 軸上的偏移
  ul.style.transform = "translateY(" + tempY + "px)";
})

限制向上滑動最大區(qū)間:

向上滑動時(shí),當(dāng)ul的底部距盒子底部的距離大于設(shè)定值的時(shí)候,不讓其繼續(xù)向上滑動,關(guān)鍵是這個(gè)值怎么去判斷?

求出向上滑動最大值:

注意:因?yàn)?b>ul是向上滑動的,所以求得的距離前面要加上一個(gè)負(fù)號(-

示例代碼:

// 設(shè)定一個(gè)最大向下滑動的距離
var maxDown = 50; 
// 求得一個(gè)最大向上滑動的距離
var maxUp = -(ul.offsetHeight - draw.offsetHeight + maxDown); 

// touchmove 時(shí),記錄此時(shí)手指在 Y 軸上的落點(diǎn)距離可視頂部距離
ul.addEventListener("touchmove", function (e) {
  // 獲取差值
  var dy = e.changedTouches[0].clientY - startY;

  // 上次的滑動距離加上本次的滑動距離
  var tempY = centerY + dy;

  // 當(dāng)上次滑動的距離加上本次滑動的距離 大于 設(shè)定的最大向下距離的時(shí)候
  if (tempY > maxDown) {
    tempY = maxDown;
  }
  // 當(dāng)上次滑動的距離加上本次滑動的距離 小于 設(shè)定的最大向上距離的時(shí)候 
  else if (tempY < maxUp) {
    // 直接讓偏移的值 等于這個(gè)設(shè)定值
    tempY = maxUp;
  }

  // 設(shè)置 ul 在 Y 軸上的偏移
  ul.style.transform = "translateY(" + tempY + "px)";
})

效果圖:

認(rèn)真觀察上圖,雖然成功的設(shè)置了最大滑動區(qū)間,但是你有沒有發(fā)現(xiàn),一直往一個(gè)方向滑動的時(shí)候,雖然列表不會繼續(xù)往下滑動,但是接著往相反方向滑動的時(shí)候,感覺列表滑不動,需要滑一段距離后,列表才會跟著走,這是為什么呢?因?yàn)榛瑒拥倪^程centerY是一直變的,列表雖然視覺上不動了,但是在touchend事件的時(shí)候,它的centerY值一直在累加。解決方法請往下看:

6. 設(shè)定反彈區(qū)間
“滑動反彈”,這里的反彈是本篇文章的最后一步,上面說到的問題,就在這里解決。因?yàn)槊恳淮斡|發(fā)touchend事件的時(shí)候,centerY值就累加一次,所以需要在touchend事件里做判斷。我們設(shè)定一個(gè)反彈區(qū)間,就是當(dāng)centerY的值大于或者小于某個(gè)值的時(shí)候,讓它觸發(fā)反彈。

設(shè)定向上反彈值:

向上的值比較簡單,設(shè)置成“0”。為什么是“0”呢?我們限定只要手指離開時(shí),上一次的滑動距離加上本次的距離> 0的時(shí)候,就讓它觸發(fā)反彈,并且反彈回0點(diǎn)的位置,也就是兩次滑動的距離和= 0。

示例代碼:

// 向上反彈
var maxUpBounce = 0;

// touchend 時(shí),記錄此時(shí)手指在 Y 軸上的落點(diǎn)距離可視頂部距離
ul.addEventListener("touchend", function (e) {
  // 獲取差值
  var dy = e.changedTouches[0].clientY - startY;
  // 記錄移動的距離
  centerY = centerY + dy;

  // 兩次滑動的距離 大于 設(shè)定的 向上 反彈值時(shí)
  if (centerY > maxUpBounce) {
    // 讓兩次滑動的距離 等于 設(shè)置的值
    centerY = maxUpBounce;
    // 添加過渡
    ul.style.transition = "transform .5s";
    ul.style.transform = "translateY(" + centerY + "px)";
  }
})

設(shè)定向下反彈值:

向下的值其實(shí)跟之前求滑動區(qū)間差不多,我們參考下圖,當(dāng)列表向上滑動,滑動到列表底部的時(shí)候,只要此時(shí)再向上滑動,就讓它向下反彈。向下反彈值就是-(ul.offsetHeight - draw.offsetHeight),只要滑動的差值小于這個(gè)設(shè)定值,就讓它向下反彈,并且反彈回設(shè)定值的位置。

示例代碼:

// 向上反彈值
var maxUpBounce = 0; 
 // 向下反彈值
var maxDownBounce = -(ul.offsetHeight - draw.offsetHeight);

// touchend 時(shí),記錄此時(shí)手指在 Y 軸上的落點(diǎn)距離可視頂部距離
ul.addEventListener("touchend", function (e) {
  // 獲取差值
  var dy = e.changedTouches[0].clientY - startY;
  // 記錄移動的距離
  centerY = centerY + dy;

  // 兩次滑動的距離 大于 設(shè)定的 向上 反彈值時(shí)
  if (centerY > maxUpBounce) {
    // 讓兩次滑動的距離 等于 設(shè)置的值
    centerY = maxUpBounce;
    // 添加過渡
    ul.style.transition = "transform .5s";
    ul.style.transform = "translateY(" + centerY + "px)";
  }
  // 兩次滑動的距離 小于 設(shè)定的 向下 反彈值時(shí)
  else if (centerY < maxDownBounce) {
    // 讓兩次滑動的距離 等于 設(shè)置的值
    centerY = maxDownBounce;
    // 添加過渡
    ul.style.transition = "transform .5s";
    ul.style.transform = "translateY(" + centerY + "px)";
  }
})

注意:touchend事件的時(shí)候,給列表添加了transition屬性才會有反彈的效果,但是,下一次滑動的時(shí)候,touchmove事件的時(shí)候,這個(gè)屬性還存在,所以就會出現(xiàn)滑動的時(shí)候有頓挫感,所以在touchmove事件的時(shí)候,一進(jìn)來就清一下過渡ul.style.transition = "none";。

完成后效果圖:

7. 完整代碼




  
  
  
  移動端 Touch 滑動反彈
  




  


文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/117241.html

相關(guān)文章

  • 原生 js 實(shí)現(xiàn)移動 Touch 滑動反彈

    摘要:移動端滑動反彈什么是滑動就是類似于端的滾動事件,但是在移動端是沒有滾動事件的,所以就要用到事件結(jié)合去實(shí)現(xiàn),效果如下準(zhǔn)備工作什么是移動端的事件在移動端事件可以細(xì)分成三種,分別是和,并且事件必須要用去監(jiān)聽。 showImg(https://segmentfault.com/img/remote/1460000017852500?w=1920&h=1080); 移動端 Touch 滑動反彈 ...

    instein 評論0 收藏0
  • 原生 js 實(shí)現(xiàn)移動 Touch 輪播圖

    摘要:輪播圖輪播圖其實(shí)就是通過手指的滑動,來左右切換輪播圖,下面我們通過一個(gè)案例,來實(shí)現(xiàn)下。結(jié)構(gòu)結(jié)構(gòu)上,還是用來存放輪播圖片,來存放輪播小圓點(diǎn)樣式初始化的一些標(biāo)簽,都會有一些默認(rèn)樣式,比如標(biāo)簽?zāi)J(rèn)是有一個(gè)邊距的,為了不影響美觀,我們需要清除掉。 showImg(https://segmentfault.com/img/remote/1460000017719408?w=1920&h=1080...

    Elle 評論0 收藏0
  • 移動原生JS實(shí)現(xiàn)手指跟隨的觸控滑動

    摘要:為了模擬原生應(yīng)用的觸控效果,大量的應(yīng)用使用了手指跟隨的滑動效果,也就是用手指滑動幻燈片的效果,什么是手指跟隨如圖網(wǎng)上滑動插件有不少,但好像沒一個(gè)好用的不是太多,就是不靈活這里用原生實(shí)現(xiàn)了該功能,不僅代碼量不多,邏輯也較簡單。 為了模擬原生應(yīng)用的觸控效果,大量的H5應(yīng)用使用了手指跟隨的滑動效果,也就是用手指滑動幻燈片的效果, 什么是手指跟隨,如圖;showImg(https://segm...

    時(shí)飛 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<