摘要:問題移動設(shè)備上的觸摸事件如何利用它們?nèi)齻€來處理點擊長按滑動等操作,以及如何在測試用例中模擬它們的操作參考了實現(xiàn)方法上這位大哥的思路移動設(shè)備的點擊優(yōu)化參考了感謝解決使用自定義指令來干這件事來記錄開始點擊的位置和時間,并在這里邊判斷長按操作來確
問題:
移動設(shè)備上的觸摸事件:touchstart、touchmove、touchend
如何利用它們?nèi)齻€來處理點擊、長按、滑動等操作,以及如何在測試用例中模擬它們的操作
實現(xiàn)方法上 https://blog.csdn.net/qq_1775... 這位大哥的思路
移動設(shè)備的點擊優(yōu)化參考了MUI
//感謝?。?!解決
使用vue自定義指令來干這件事
touchstart來記錄開始點擊的位置和時間,并在這里邊判斷 長按 操作
touchend來確定結(jié)束點擊的位置和時間,來區(qū)分 點擊 操作以及 不同方向的滑動 操作
需要有v-on一樣的修飾符來處理不同的觸發(fā)條件(.stop .prevent .self .once)
移動設(shè)備上人類手指太粗導(dǎo)致的點擊位置的問題的修正(使用Touch事件中的changeTouches來確定點擊的中心位置)
移動設(shè)備滑動方向的判斷(思路來自mui源碼)
然后直接上操作類
class VueTouch { /** * @param el 綁定的DOM * @param binding 自定義指令中的binding對象 * @param type 綁定的事件類型 */ constructor(el, binding, type) { let g = this; g.obj = el; g.binding = binding; g.touchType = type; g.firstTouchPosition = {x: 0, y: 0}; g.firstTouchTime = 0; /** * ========================================= * 事件綁定有兩種方式 * @example * 1. v-tap="showDialog" 綁定一個方法對象 * 2. v-tap="{fn:click123, param1:1, param2:2, param3:{aaa:"123"} ...}" * 綁定一個JSON字面量,fn是執(zhí)行的方法,后邊的是需要傳遞的參數(shù) * 事件回調(diào)參數(shù) * @param 第一個參數(shù)是event,事件對象 * @param 第二個參數(shù)是 binding.value,也就是v-tap=""雙引號中的部分(如示例2,第二個參數(shù)就是 {fn:click123, param1:1, param2:2, param3:{aaa:"123"} ...}) * ========================================= */ g.callBack = typeof(binding.value) === "object" ? binding.value.fn : binding.value; // 事件監(jiān)聽回調(diào)集合 let _listener = Object.create(null); // 事件方法 let _listen = (type) => { return function (e) { /** * 取出修飾符(和v-on的一樣) */ let {stop, prevent, self, once} = g.binding.modifiers; // 配置判斷 if (stop) e.stopPropagation(); if (prevent) e.preventDefault(); if (once) g.obj.removeEventListener("touch" + type, _listener[type]); if (self && e.target !== e.currentTarget) return; g[type](e); } }; _listener.start = _listen("start"); _listener.end = _listen("end"); _listener.move = _listen("move"); // 事件綁定 this.obj.addEventListener("touchstart", _listener.start, false); this.obj.addEventListener("touchend", _listener.end, false); this.obj.addEventListener("touchmove", _listener.move, false); } // 點擊開始 start(e) { let g = this; // @update 2018.3.26 這里做了一個修改 g.moved = false; //是否移動了 g.leaved = false; //是否離開了 g.longTouched = false; //是否執(zhí)行了長按操作 // 獲取開始點擊位置和時間 g.firstTouchPosition = g.getMultiCenter(e.changedTouches); g.firstTouchTime = e.timeStamp; // 判斷長按操作 @TODO 稍微有點觸發(fā)時機上的問題,待修正 g.time = setTimeout(function () { if (!g.leaved && !g.moved) { g.touchType === "longtap" && g.callBack(e, g.binding.value); g.longTouched = true; } }.bind(g), 1000); } // 點擊結(jié)束 end(e) { let g = this; // 點擊結(jié)束獲取點擊位置并計算位移和時差 let {x, y} = g.getMultiCenter(e.changedTouches); let _disX = x - g.firstTouchPosition.x; let _disY = y - g.firstTouchPosition.y; let _dis = Math.sqrt(_disX * _disX + _disY * _disY); let _timeDis = e.timeStamp - g.firstTouchTime; clearTimeout(g.time); // 計算滑動角度 let _angle = this.getAngle(_disX, _disY); // 判斷滑動方向 if (_dis > 18 && _timeDis < 300) { g.touchType === "swipe" && g.callBack(e, g.binding.value); if (_angle >= 60 && _angle <= 120) g.touchType === "swipedown" && g.callBack(e, g.binding.value); if (_angle <= -60 && _angle >= -120) g.touchType === "swipeup" && g.callBack(e, g.binding.value); if (_angle <= 20 && _angle >= -20) g.touchType === "swipeleft" && g.callBack(e, g.binding.value); if ((_angle <= -160 && _angle > -180) || (_angle >= 160 && _angle <= 180)) g.touchType === "swiperight" && g.callBack(e, g.binding.value); } else { if (!g.longTouched && !g.moved) { g.touchType === "tap" && g.callBack(e, g.binding.value); g.leaved = true; } } } move() { this.moved = true; } /** * 獲取點擊集合的中心坐標 * @param touches touch對象集合 * @return {{x: number, y: number}} */ getMultiCenter(touches) { let g = this, x = 0, y = 0; const _length = touches.length; for (let i = 0; i < _length; i++) { x += touches[i].pageX; y += touches[i].pageY; } return { x: Math.round(x / _length), y: Math.round(y / _length) }; }; /** * 獲取滑動的角度 * @param disX X軸的位移 * @param disY Y軸的位移 * @return 角度 */ getAngle(disX, disY) { let g = this; if (typeof disX !== "number" || typeof disY !== "number") return 45; return Math.atan2(disY, disX) * 180 / Math.PI; } }
然后執(zhí)行生成指令
Vue.directive("tap", { bind: function (el, binding) { new VueTouch(el, binding, "tap"); } }); Vue.directive("swipe", { bind: function (el, binding) { new VueTouch(el, binding, "swipe"); } }); Vue.directive("swipeleft", { bind: function (el, binding) { new VueTouch(el, binding, "swipeleft"); } }); Vue.directive("swiperight", { bind: function (el, binding) { new VueTouch(el, binding, "swiperight"); } }); Vue.directive("swipedown", { bind: function (el, binding) { new VueTouch(el, binding, "swipedown"); } }); Vue.directive("swipeup", { bind: function (el, binding) { new VueTouch(el, binding, "swipeup"); } }); Vue.directive("longtap", { bind: function (el, binding) { new VueTouch(el, binding, "longtap"); } });
源碼參看:https://github.com/LylaYuKako...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/93614.html
摘要:去年年底自己搭了一個在移動端的開發(fā)框架,感覺體驗不是很好。路由懶加載首頁終于寫完了,以上這些就是我在移動端體驗優(yōu)化的實戰(zhàn)。去年年底自己搭了一個vue在移動端的開發(fā)框架,感覺體驗不是很好。上個星期又要做移動端的項目了。所以我花了兩天時間對之前的那個開發(fā)框架做了以下優(yōu)化 自定義vuex-plugins-loading 路由切換動畫 + keep alive 動態(tài)管理緩存組件 better-sc...
項目需求簡單描述 用戶長按錄音,松手后直接結(jié)束錄音,結(jié)束錄音后,用戶可以選擇重新錄音、播放剛才的錄音,上傳錄音(這里的上傳錄音指上傳到自己服務(wù)器,上傳步驟是,前端調(diào)用wx.uploadVoice,后臺再到微信服務(wù)器下載音頻文件,上傳到自己的服務(wù)器)。注意,音頻文件自上傳時間算起在微信服務(wù)器的有效期為3天。由于后臺從微信服務(wù)器下載的音頻文件是amr格式的,需要后臺先把amr文件轉(zhuǎn)換成MP3,前端用a...
摘要:里邊涉及到的指令是自定義的指令,為了處理移動端的點擊操作,我還整理了一片陋文移動點擊長按滑動指令然后這個組件的源碼我放在了我出來的項目上謝謝各位品嘗, 以下這段都是廢話,請?zhí)^ 公司移動端開發(fā)平臺進行了大變革,前端架構(gòu)由DCloud大生態(tài)轉(zhuǎn)換為VUE,所以移動端的UI組件庫從MUI改為使用MintUI,然后開始大刀闊斧的把MintUI組件改成MUI組件的樣子,然后發(fā)現(xiàn)少了幾個較為常用的...
閱讀 2181·2021-11-19 09:55
閱讀 2637·2021-11-11 16:55
閱讀 3175·2021-09-28 09:36
閱讀 1945·2021-09-22 16:05
閱讀 3269·2019-08-30 15:53
閱讀 1805·2019-08-30 15:44
閱讀 2899·2019-08-29 13:10
閱讀 1339·2019-08-29 12:30