本教程操作環境:Windows10系統、react18.0.0版、Dell G3電腦。
react怎么實現滑動?
(相關資料圖)
react 實現左右滑動效果
React 中滑動手勢的實現
最近做了一點關于react在移動端滑動翻頁的功能。
開始搜索了一下,發現居然沒找到合適的庫,唯一找到了名字叫react-touch的庫,一看,前端世界四五百star===自己擼,而且似乎也不是想要的功能,算了自己寫點吧。
看了下原理,基本就是配合onTouchStart,onTouchMove和onTouchEnd這三個事件,來記錄滑動過的點,然后來計算手勢。
顯然對于多點觸摸,需要找到每個點觸摸的路徑,所以有如下幾步:
在onTouchStart事件找到touches,根據identifier中記錄新的touch出現。
在onTouchMove事件中根據identifier來記錄每個touch經過的點的坐標。
在onTouchEnd事件中,找到結束的touch事件,然后通過結束的touch事件劃過的點來計算要執行的手勢。
對于我來說我只是想要上下滑動的功能那么我就只關注單點觸摸的情況。
接下來準備上代碼。哦,不對,首先要想想要怎么封裝。開始自問自答:
我想用一個單例模式。
是不是使用有點太麻煩了,還要先實例化一下?
那用靜態類?
都js了還要啥靜態類,輸出個字典完事。
那好吧,開始擼吧。
const touchData = { touching: false, trace: [] };// 單點觸摸,所以只要當前在觸摸中,就可以把劃過的點記錄到trace中了function* idGenerator() { let start = 0; while (true) { yield start; start += 1; }}//這個生成器用來生成不同事件回調的id,這樣我們可以注冊不同的回調,然后在不需要的時候刪掉。const callbacks = { onSlideUpPage: { generator: idGenerator(), callbacks: {} }, onSlideDownPage: { generator: idGenerator(), callbacks: {} }};//存儲向上、下換頁的回調函數
這里的事件處理的是react的合成事件,并非原生事件。
function onTouchStart(evt) { if (evt.touches.length !== 1) { touchData.touching = false; touchData.trace = []; return; } touchData.touching = true; touchData.trace = [{ x: evt.touches[0].screenX, y: evt.touches[0].screenY }];}//在onTouchStart事件,如果是多點觸摸直接清空所有數據。如果是單點觸摸,記錄第一個點,并設置狀態function onTouchMove(evt) { if (!touchData.touching) return; touchData.trace.push({ x: evt.touches[0].screenX, y: evt.touches[0].screenY });}//如果在單點觸摸過程中,持續記錄觸摸的位置。function onTouchEnd() { if (!touchData.touching) return; let trace = touchData.trace; touchData.touching = false; touchData.trace = []; handleTouch(trace); //判斷touch類型并調用適當回調}//在觸摸結束事件,中調用handleTouch函數來處理手勢判斷邏輯并執行回調
function handleTouch(trace) { let start = trace[0]; let end = trace[trace.length - 1]; if (end.y - start.y > 200) { Object.keys(callbacks.onSlideUpPage.callbacks).map(key => callbacks.onSlideUpPage.callbacks[key]() ); // 向上翻頁 } else if (start.y - end.y > 200) { Object.keys(callbacks.onSlideDownPage.callbacks).map(key => callbacks.onSlideDownPage.callbacks[key]() ); // 向下翻頁 }}
在這里我只判斷了向上向下翻頁兩個事件,如果事件達成,則會調用所有注冊到該事件的回調。如果有多個回調可按照需求對回調的執行順序進行調整。這里應該是無序的。
function addSlideUpPage(f) { let key = callbacks.onSlideUpPage.generator.next().value; callbacks.onSlideUpPage.callbacks[key] = f; return key;}//注冊向上滑動回調并返回回調idfunction addSlideDownPage(f) { let key = callbacks.onSlideDownPage.generator.next().value; callbacks.onSlideDownPage.callbacks[key] = f; return key;}//注冊向下滑動回調并返回回調idfunction removeSlideUpPage(key) { delete callbacks.onSlideUpPage.callbacks[key];}//使用回調id刪除向上滑動回調function removeSlideDownPage(key) { delete callbacks.onSlideDownPage.callbacks[key];}//使用回調id刪除向下滑動回調export default { onTouchEnd, onTouchMove, onTouchStart, addSlideDownPage, addSlideUpPage, removeSlideDownPage, removeSlideUpPage};//輸出所有接口函數
這沒啥說的,就是折麼簡單粗暴。接下來,就在react中使用吧!
我使用的next.js+create-next-app。在pages目錄下的_app.js文件中綁定所有touch事件。
//pages/_app.jsimport App, { Container } from "next/app";import React from "react";import withReduxStore from "../redux/with-redux-store";import { Provider } from "react-redux";import touch from "../components/touch";class MyApp extends App { render() { const { Component, pageProps, reduxStore } = this.props; return ( <Container> <Provider store={reduxStore}> <div onTouchEnd={touch.onTouchEnd} onTouchStart={touch.onTouchStart} onTouchMove={touch.onTouchMove} > <Component {...pageProps} /> </div> {// 將所有導出的touch事件綁定在最外層的div上// 這樣就可以全局注冊事件了} </Provider> </Container> ); }}export default withReduxStore(MyApp);
接下來看看如何使用。
import React, {useEffect} from "react";import touch from "../touch";const Example = () => { useEffect(() => { let key = touch.addSlideDownPage(() => { console.log("try to slideDownPage!!") }); return () => { touch.removeSlideDownPage(key) // 用完別忘了刪除事件 }; }, []); return ( <div>This is an example!!</div> );};
這個項目使用create-react-app生成的
//src/App.jsimport React from "react";import logo from "./logo.svg";import "./App.css";import touch from "./components/touch";function App() { return ( <div className="App" onTouchEnd={touch.onTouchEnd} onTouchStart={touch.onTouchStart} onTouchMove={touch.onTouchMove} > <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.js</code> and save to reload. </p> <a className="App-link" target="_blank" rel="noopener noreferrer" > Learn React </a> </header> </div> );}
如果真的有人仔細看了代碼,可能會有個問題,這個touch.js里的內容除了使用了react的合成事件,然后就沒react什么事了,好像不太常規。
的確是這樣,就沒關react什么事了。解釋就是這些數據不用通過react的state或者redux的state太傳遞,一來是在性能上,一更新redux或者react的state就會觸發react的重新渲染,沒有必要,二就是希望可以全局使用這些接口,所以就并沒有借助react的機制。其實這就像是react所說的uncontrolled components。
最后附上完整的touch.js
//touch.jsconst touchData = { touching: false, trace: [] };function* idGenerator() { let start = 0; while (true) { yield start; start += 1; }}const callbacks = { onSlideUpPage: { generator: idGenerator(), callbacks: {} }, onSlideDownPage: { generator: idGenerator(), callbacks: {} }};function onTouchStart(evt) { if (evt.touches.length !== 1) { touchData.touching = false; touchData.trace = []; return; } touchData.touching = true; touchData.trace = [{ x: evt.touches[0].screenX, y: evt.touches[0].screenY }];}function onTouchMove(evt) { if (!touchData.touching) return; touchData.trace.push({ x: evt.touches[0].screenX, y: evt.touches[0].screenY });}function onTouchEnd() { if (!touchData.touching) return; let trace = touchData.trace; touchData.touching = false; touchData.trace = []; handleTouch(trace);}function handleTouch(trace) { let start = trace[0]; let end = trace[trace.length - 1]; if (end.y - start.y > 200) { Object.keys(callbacks.onSlideUpPage.callbacks).map(key => callbacks.onSlideUpPage.callbacks[key]() ); } else if (start.y - end.y > 200) { Object.keys(callbacks.onSlideDownPage.callbacks).map(key => callbacks.onSlideDownPage.callbacks[key]() ); }}function addSlideUpPage(f) { let key = callbacks.onSlideUpPage.generator.next().value; callbacks.onSlideUpPage.callbacks[key] = f; return key;}function addSlideDownPage(f) { let key = callbacks.onSlideDownPage.generator.next().value; callbacks.onSlideDownPage.callbacks[key] = f; return key;}function removeSlideUpPage(key) { delete callbacks.onSlideUpPage.callbacks[key];}function removeSlideDownPage(key) { delete callbacks.onSlideDownPage.callbacks[key];}export default { onTouchEnd, onTouchMove, onTouchStart, addSlideDownPage, addSlideUpPage, removeSlideDownPage, removeSlideUpPage};
推薦學習:《react視頻教程》
以上就是react怎么實現滑動的詳細內容,更多請關注php中文網其它相關文章!
關鍵詞: React