React method to implement sliding: 1. Find touches in the onTouchStart event, and record the occurrence of new touches according to the identifier; 2. Record the coordinates of each point passed by the touch according to the identifier in the onTouchMove event; 3. In the onTouchEnd event, find the ending touch event, and then calculate the gesture to be performed based on the point crossed by the ending touch event.
The operating environment of this tutorial: Windows 10 system, react18.0.0 version, Dell G3 computer.
How to implement sliding in react?
react to achieve left and right sliding effects
React implementation of sliding gestures
Recently I did a little bit about the sliding page turning function of react on the mobile terminal.
I started searching and found that I couldn’t find a suitable library. The only library I found was a library named react-touch. At first glance, there were four to five hundred stars in the front-end world === I did it myself, and it didn’t seem like I wanted to If you want the function you want, forget about writing it yourself.
After looking at the principle, it basically works with the three events of onTouchStart, onTouchMove and onTouchEnd to record the sliding point and then calculate the gesture.
Obviously for multi-touch, you need to find the path of each touch point, so there are the following steps:
Find the touches in the onTouchStart event, and record the new ones according to the identifier The touch appears.
In the onTouchMove event, record the coordinates of each point passed by the touch based on the identifier.
In the onTouchEnd event, find the ending touch event, and then calculate the gesture to be performed by the point crossed by the ending touch event.
For me, I just want the function of sliding up and down, so I only focus on the single touch situation.
Next, prepare to write the code. Oh, no, first we have to think about how to encapsulate it. Start asking and answering yourself:
I want to use a singleton pattern.
Is it too troublesome to use? Do I need to instantiate it first?
Then use static classes?
If you already have js, what kind of static class is needed? Just output a dictionary and that’s it.
Okay then, let’s start masturbating.
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: {} } }; //存储向上、下换页的回调函数
The events here deal with react's synthetic events, not native events.
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]() ); // 向下翻页 } }
Here I only judged up and down Page two events, if the event is reached, all callbacks registered for the event will be called. If there are multiple callbacks, the execution order of the callbacks can be adjusted as needed. There should be no order here.
function addSlideUpPage(f) { let key = callbacks.onSlideUpPage.generator.next().value; callbacks.onSlideUpPage.callbacks[key] = f; return key; } //注册向上滑动回调并返回回调id function addSlideDownPage(f) { let key = callbacks.onSlideDownPage.generator.next().value; callbacks.onSlideDownPage.callbacks[key] = f; return key; } //注册向下滑动回调并返回回调id function 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 }; //输出所有接口函数
There’s nothing to say, it’s just so simple and crude. Next, let’s use it in react!
I use next.js create-next-app. Bind all touch events in the _app.js file in the pages directory.
//pages/_app.js import 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);
Let’s see how to use it.
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> ); };
This project is generated using create-react-app
//src/App.js import 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" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </a> </header> </div> ); }
If someone really reads the code carefully, there may be a problem with the content in touch.js Except for using react's synthetic events, there is nothing else to do with react, which seems unconventional.
This is indeed the case, and it has nothing to do with react. The explanation is that these data do not need to be passed through react's state or redux's state. Firstly, in terms of performance, updating redux or react's state will trigger react's re-rendering, which is not necessary. Secondly, we hope that these interfaces can be used globally. So I didn’t use the react mechanism. In fact, this is like what react calls uncontrolled components.
Finally attached is the complete touch.js
//touch.js const 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 };
Recommended learning: "react video tutorial"
The above is the detailed content of How to implement sliding in react. For more information, please follow other related articles on the PHP Chinese website!