vue項(xiàng)目中解決 IOS + H5 滑動(dòng)邊界橡皮筋彈性效果(解決思路)
問(wèn)題:
最近遇到一個(gè)問(wèn)題,我們?cè)谄髽I(yè)微信中的 H5 項(xiàng)目中需要用到table表格(支持懶加載 上劃加載數(shù)據(jù))。但是他們?cè)阪i頭、鎖列的情況下,依舊會(huì)出現(xiàn)邊界橡皮筋效果。就會(huì)顯示的很奇怪。
什么是ios橡皮筋效果:
我們知道元素超出所給定的高度會(huì)出現(xiàn)滾動(dòng)條 | 橫向的或縱向的,在ios手機(jī)上當(dāng)在全局范圍或局部范圍出現(xiàn)滾動(dòng)的地方時(shí),滑動(dòng)使?jié)L動(dòng)到頭時(shí)還可以繼續(xù)拖拽出一段距離的空白,松開手時(shí)立刻回彈回去。雖不影響功能,但是操作有點(diǎn)別扭,感覺(jué)這個(gè)table表格滑動(dòng)的時(shí)候像是飄著上面的,不是固定的。
嘗試思路:
針對(duì)這個(gè)問(wèn)題我也嘗試了不同的方案都不盡人意;
1,首先想到先使用css解決,前后使用了絕對(duì)定位和固定定位來(lái)提高層級(jí),發(fā)現(xiàn)問(wèn)題依然存在;
2,然后是用css屬性&::-webkit-scrollbar { display: none;} 來(lái)隱藏滾動(dòng)條 ,還是不行,
3,后面引入網(wǎng)上的inobounce插件還是不行。此插件會(huì)禁用頁(yè)面的touchmove事件,導(dǎo)致頁(yè)面無(wú)法進(jìn)行滑動(dòng);
4,因?yàn)槲矣玫氖窃膖able來(lái)布局的,難道是table標(biāo)簽的問(wèn)題,后面我又重新用div來(lái)實(shí)現(xiàn)table表格的布局,發(fā)現(xiàn)還是會(huì)出現(xiàn)橡皮筋效果,說(shuō)明不是標(biāo)簽的問(wèn)題,是ios瀏覽器隱藏的特性;
解決方案:
最后我想到,既然我關(guān)不掉,那我自己完全控制滑動(dòng)好了;原理是禁用掉頁(yè)面touchumove的默認(rèn)的滑動(dòng)效果,使用元素的scrollLeft 和scrollTop這兩個(gè)原生的可寫屬性,來(lái)進(jìn)行元素的上下和左右移動(dòng);
這樣做的好處在于,我自己完全控制了拖拽滑動(dòng)行為。壞處在于丟失了原生滑動(dòng)的慣性滑動(dòng),看著沒(méi)那么絲滑了。不過(guò)這點(diǎn)也可以后續(xù)通過(guò) JavaScript 來(lái)優(yōu)化(暫時(shí)還沒(méi)寫 ,寫出來(lái)的效果不太好,不絲滑)。
效果圖如下:
可以上下左右滑動(dòng),是固頂?shù)模蛏匣瑒?dòng)時(shí)標(biāo)題部分不會(huì)跟隨移動(dòng);
可以懶加載:當(dāng)下滑到觸底時(shí)會(huì)向父元素傳遞一個(gè)事件告訴父組件該請(qǐng)求下一頁(yè)的數(shù)據(jù)了;

主要實(shí)現(xiàn)代碼如下:
表格組件部分代碼如下:tableStrick.vue;
data() {
return {
listEle: null, // dom元素
// 記錄坐標(biāo)
touchX: "",
touchY: "",
// 滑動(dòng)坐標(biāo)
startX: 0,
startY: 0,
// 滑動(dòng)方向
direction: "",
};
}
mounted() {
/* 獲取dom元素 這里最好不要用原生的dom獲取方式 */
this.listEle = this.$refs.main;
/* 自己實(shí)現(xiàn)滾動(dòng)效果 不會(huì)出現(xiàn)滾動(dòng)回彈問(wèn)題 但是滾動(dòng)不絲滑了且沒(méi)有慣性 */
this.listEle.addEventListener("touchstart", this.touchstart, false);
this.listEle.addEventListener("touchmove", this.touchmove, false);
this.listEle.addEventListener("touchend", this.touchend, false);
},
methods:{
/* 修改 瀏覽器默認(rèn)的滑動(dòng)容器行為 */
// 1,手指接觸屏幕
touchstart(event) {
this.touchX = event.changedTouches[0].clientX;
this.touchY = event.changedTouches[0].clientY;
// 獲取此刻手指的橫坐標(biāo)startX和縱坐標(biāo)startY
this.startX = event.touches[0].pageX;
this.startY = event.touches[0].pageY;
},
// 2, 手指滑動(dòng)的過(guò)程
touchmove(event) {
event.preventDefault();
// 計(jì)算手指偏移量
const offsetX = event.changedTouches[0].clientX - this.touchX;
const offsetY = event.changedTouches[0].clientY - this.touchY;
// 觸摸的坐標(biāo)
this.touchX = event.changedTouches[0].clientX;
this.touchY = event.changedTouches[0].clientY;
// 手指滑動(dòng)的方向
let moveEndX = event.changedTouches[0].pageX;
let moveEndY = event.changedTouches[0].pageY;
let X = moveEndX - this.startX;
let Y = moveEndY - this.startY;
// 注意 上下移動(dòng)只能是上劃或下劃 左右移動(dòng)也是同理
if (Math.abs(X) > Math.abs(Y) && X > 0) {
// 開始移動(dòng)
console.log('我向右滑了)
this.listEle.scrollLeft = this.listEle.scrollLeft - offsetX;
this.direction = "right";
} else if (Math.abs(X) > Math.abs(Y) && X < 0) {
console.log('我向左滑了)
this.listEle.scrollLeft = this.listEle.scrollLeft - offsetX;
this.direction = "left";
} else if (Math.abs(Y) > Math.abs(X) && Y > 0) {
console.log('我向下滑了)
this.listEle.scrollTop = this.listEle.scrollTop - offsetY;
/* 設(shè)置滾動(dòng)到底的處理 */
this.scrollBottom(event);
this.direction = "bottom";
} else if (Math.abs(Y) > Math.abs(X) && Y < 0) {
console.log('我向上滑了)
this.listEle.scrollTop = this.listEle.scrollTop - offsetY;
this.direction = "top";
/* 設(shè)置滾動(dòng)到底的處理 */
this.scrollBottom(event);
} else {
this.direction = "";
}
},
// 3,手指離開屏幕
touchend(event) {
this.touchX = event.changedTouches[0].clientX;
this.touchY = event.changedTouches[0].clientY;
// TODO 此處可以進(jìn)行優(yōu)化滾動(dòng)的慣性 暫未實(shí)現(xiàn)
},
// 監(jiān)聽(tīng)滾動(dòng)條 注意 scroll 可能是橫向滾動(dòng)條 也可能是縱向滾動(dòng)條
scrollBottom(event) {
// 1,可視區(qū)域
let clientHeight = this.listEle.clientHeight;
// 2,滾動(dòng)文檔高度
let scrollHeight = this.listEle.scrollHeight;
// 3,此處相等說(shuō)明:沒(méi)有縱向滾動(dòng)條 可能出現(xiàn)了橫向滾動(dòng)條 所以要忽略
if (clientHeight == scrollHeight) {
return;
}
// 4,已滾動(dòng)的高度
let scrollTop = parseInt(this.listEle.scrollTop);
// 這里 -2 是為了控制誤差
if (scrollTop + clientHeight >= scrollHeight - 2) {
console.log("滾動(dòng)到底了");
// 把事件傳出去 父元素開始請(qǐng)求下一頁(yè)的數(shù)據(jù)
this.$emit("scrollBottom");
}
},
}
上面代碼講解:
1,mounted里面獲取表格元素或父元素,然后監(jiān)聽(tīng)手指點(diǎn)擊事件,移動(dòng)事件,離開事件;
2,touchstart方法中記錄坐標(biāo),touchmove使用 event.preventDefault();禁用掉原先的滑動(dòng)效果,自己通過(guò)this.listEle.scrollLeft和this.listEle.scrollTop來(lái)進(jìn)行移動(dòng);
3,注意:下面的代碼的意思是先要計(jì)算滑動(dòng)的方向,然后再進(jìn)行向?qū)?yīng)的移動(dòng),防止上下左右一起移動(dòng),導(dǎo)致移動(dòng)時(shí)太過(guò)敏感導(dǎo)致表格一直抖動(dòng);

4,scrollBottom方法是懶加載的處理 ,如果需要的話可以加上;主要是判斷上下滑動(dòng)時(shí)距離是否觸底,觸底就讓父組件請(qǐng)求數(shù)據(jù)。
最后注意:
最后需要注意的是需要使用了懶加載 :需要對(duì)父元素中的scrollBottom這個(gè)方法進(jìn)行防抖設(shè)置,因?yàn)榛瑒?dòng)到底部觸底時(shí)存在多次連續(xù)觸底的行為(比較靈敏),這樣會(huì)同時(shí)執(zhí)行多次scrollBottom這個(gè)方法;導(dǎo)致數(shù)據(jù)請(qǐng)求過(guò)多;
防抖可以使用lodash庫(kù)里面的debounce方法;
使用如下:在mounted中對(duì)scrollBottom進(jìn)行防抖 ,也可以對(duì)實(shí)際請(qǐng)求接口的 自定義方法 進(jìn)行防抖,
mounted(){
/* 設(shè)置接口防抖 */
this.scrollBottom= _.debounce(this.scrollBottom, 500);
}通過(guò) JavaScript 來(lái)優(yōu)化滾動(dòng)的慣性 ,這個(gè)如果小伙伴們有好的方法可以放到評(píng)論區(qū)里學(xué)習(xí)一下;
到此這篇關(guān)于vue項(xiàng)目中解決 IOS + H5 滑動(dòng)邊界橡皮筋彈性效果的文章就介紹到這了,更多相關(guān) IOS + H5 滑動(dòng)邊界橡皮筋彈性內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決Antd中Form表單的onChange事件中執(zhí)行setFieldsValue不生效
這篇文章主要介紹了解決Antd中Form表單的onChange事件中執(zhí)行setFieldsValue不生效問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
electron-vite新一代electron開發(fā)構(gòu)建工具
這篇文章主要介紹了electron-vite新一代electron開發(fā)構(gòu)建工具,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
Vue3對(duì)比Vue2的優(yōu)點(diǎn)總結(jié)
vue3解決了vue2的一些缺陷與弊端,學(xué)習(xí)新的技術(shù)是很有必要的,本文總結(jié)了一些vue3的優(yōu)點(diǎn),希望各位能盡快轉(zhuǎn)入vue3的使用中2021-06-06
Vue2.0父組件與子組件之間的事件發(fā)射與接收實(shí)例代碼
這篇文章主要介紹了Vue2.0父組件與子組件之間的事件發(fā)射與接收實(shí)例代碼,需要的朋友可以參考下2017-09-09
使用Vue3-Ace-Editor如何在Vue3項(xiàng)目中集成代碼編輯器
這篇文章主要介紹了使用Vue3-Ace-Editor如何在Vue3項(xiàng)目中集成代碼編輯器,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
vue自定義權(quán)限標(biāo)簽詳細(xì)代碼示例
這篇文章主要給大家介紹了關(guān)于vue自定義權(quán)限標(biāo)簽的相關(guān)資料,在Vue中你可以通過(guò)創(chuàng)建自定義組件來(lái)實(shí)現(xiàn)自定義標(biāo)簽組件,文中給出了詳細(xì)的代碼示例,需要的朋友可以參考下2023-09-09

