首頁 >web前端 >前端問答 >react怎麼實現滑動

react怎麼實現滑動

藏色散人
藏色散人原創
2022-12-30 11:09:002236瀏覽

react實現滑動的方法:1、在onTouchStart事件找到t​​ouches,根據identifier中記錄新的touch出現;2、在onTouchMove事件中根據identifier來記錄每個touch經過的點的坐標;3、在onTouchEnd事件中,找到結束的touch事件,然後透過結束的touch事件劃過的點來計算要執行的手勢即可。

react怎麼實現滑動

本教學操作環境:Windows10系統、react18.0.0版、Dell G3電腦。

react怎麼實現滑動?

react 實作左右滑動效果

#React 中滑動手勢的實作

react怎麼實現滑動

最近做了一點關於react在行動端滑動翻頁的功能。

開始搜尋了一下,發現居然沒找到合適的庫,唯一找到了名字叫react-touch的庫,一看,前端世界四五百star===自己擼,而且似乎也不是想要的功能,算了自己寫點吧。

看了下原理,基本上就是配合onTouchStart,onTouchMove和onTouchEnd這三個事件,來記錄滑動過的點,然後來計算手勢。

顯然對於多點觸控,需要找到每個點觸控的路徑,所以有以下幾步:

  • 在onTouchStart事件找到t​​ouches,根據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函数来处理手势判断逻辑并执行回调

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;
}
//注册向上滑动回调并返回回调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
};
//输出所有接口函数

這沒啥說的,就是折麽簡單粗暴。接下來,就在react中使用吧!

在next.js中使用

我使用的next.js create-next-app。在pages目錄下的_app.js檔案中綁定所有touch事件。

//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);

接下來看看如何使用。

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>
  );
};

在原生react中使用

這個專案使用create-react-app產生的

//src/App.js
import React from &#39;react&#39;;
import logo from &#39;./logo.svg&#39;;
import &#39;./App.css&#39;;
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>
  );
}

結語

如果真的有人仔細看了程式碼,可能會有個問題,這個touch.js裡的內容除了使用了react的合成事件,然後就沒react什麼事了,好像不太常規。

的確是這樣,就沒關react什麼事了。解釋就是這些資料不用透過react的state或redux的state太傳遞,一來是在效能上,一更新redux或是react的state就會觸發react的重新渲染,沒有必要,二就是希望可以全域使用這些接口,所以就並沒有借助react的機制。其實這就像是react所說的uncontrolled components。

最後附上完整的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
};

#推薦學習:《react影片教學

以上是react怎麼實現滑動的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn