最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

React實(shí)現(xiàn)前端選區(qū)的示例代碼

 更新時(shí)間:2023年05月05日 15:31:09   作者:sole  
本文主要介紹了React實(shí)現(xiàn)前端選區(qū)的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

什么是選區(qū)

前端選區(qū)非常常見,通過鼠標(biāo)的點(diǎn)擊和移動來創(chuàng)建一個(gè)選中頁面,在多個(gè)元素需要被選中的情況下,一個(gè)個(gè)點(diǎn)擊顯的非常拖沓,所以需要通過建立選區(qū)來應(yīng)對多個(gè)元素的操作。以下是簡單的建立選區(qū)圖片例子:

image.png

如何建立選區(qū)

瀏覽器繪制選區(qū)方式

在瀏覽器中繪制一個(gè)矩形,通常是通過其元素的top和left來決定,瀏覽器通過確定元素的top和left位置,并監(jiān)聽鼠標(biāo)在移動過程中的偏移量offsetX和offsetY來計(jì)算元素的總寬高,最后繪制成元素的總體形狀,固定好元素的top和left極為重要。如下是瀏覽器繪制的示意圖:

image.png

瀏覽器在繪制時(shí),總是以左上角的頂點(diǎn)作為元素的起始位置,也就是說如果你的選區(qū)是從右往左或者從下往上建立,瀏覽器都會以最終圖形的左上角頂點(diǎn)作為元素的起始位置進(jìn)行繪制。所以確定左上角頂點(diǎn)位置尤為關(guān)鍵。

React計(jì)算選區(qū)范圍

通過監(jiān)聽瀏覽器的鼠標(biāo)移動事件來獲取鼠標(biāo)移動的范圍,在這里我們需要先獲取鼠標(biāo)初始位置,通過movedown事件確定鼠標(biāo)起始位置,通過isMove來判斷是否鼠標(biāo)落下并開始移動,記錄鼠標(biāo)落點(diǎn)位置。代碼如下圖所示:

const [isMove, setIsMove] = useState<boolean>(false);
const [downAndUpPosition, setDownAndUpPosition] = useState<Position>();
const handleMouseDown = (event: React.MouseEvent) => {
    setIsMove(true);
    let mouseDownPosition: Position = {
      offsetX: event.pageX - left,
      offsetY: event.pageY,
    };
    setDownAndUpPosition(mouseDownPosition);
  };

記錄鼠標(biāo)落點(diǎn)后,通過mousemove事件記錄鼠標(biāo)移動坐標(biāo)點(diǎn),如果鼠標(biāo)未落下則不觸發(fā)移動事件,避免重復(fù)渲染,最后在moveup事件中取消移動標(biāo)記即可:

const [movePosition, setMovePosition] = useState<Position>();
const handleMouseMove = (event: React.MouseEvent) => {
    if (!isMove) return;
    let movePosition: Position = {
      offsetX: event.pageX - left,
      offsetY: event.pageY,
    };
    setMovePosition(movePosition);
  };
const handleMouseUp = () => {
    setIsMove(false);
  };

得到鼠標(biāo)落點(diǎn)位置和鼠標(biāo)移動坐標(biāo)后,我們需要去計(jì)算鼠標(biāo)移動坐標(biāo)與起始位置的坐標(biāo)象限,如果起始位置的left與top均小于鼠標(biāo)移動后坐標(biāo),則選區(qū)在第四象限。以起始位置為坐標(biāo)原點(diǎn)去計(jì)算。代碼如下所示:

const returnDivPosition = (
    downAndUpPosition: Position,
    movePosition: Position
  ) => {
    const downPageX = downAndUpPosition.offsetX;
    const downPageY = downAndUpPosition.offsetY;
    const movePageX = movePosition.offsetX;
    const movePageY = movePosition.offsetY;
    if (downPageX >= movePageX && downPageY >= movePageY) {
      return 1;
    }
    if (downPageX <= movePageX && downPageY >= movePageY) {
      return 2;
    }
    if (downPageX >= movePageX && downPageY <= movePageY) {
      return 3;
    }
    if (downPageX <= movePageX && downPageY <= movePageY) {
      return 4;
    }
 };

計(jì)算出鼠標(biāo)最終位置處于哪個(gè)象限后,我們就可以計(jì)算出選區(qū)的top和left。如果為第一象限則鼠標(biāo)移動的最終位置就是元素偏移量,如果為第二象限則鼠標(biāo)移動最終位置的top為元素偏移top,鼠標(biāo)落點(diǎn)left為元素偏移left,以此類推即可。代碼如下圖:

const offsetPosition = useMemo(() => {
    if (downAndUpPosition && movePosition) {
      const quadrant = returnDivPosition(downAndUpPosition, movePosition);
      switch (quadrant) {
        case 1:
          return {
            top: movePosition.offsetY,
            left: movePosition.offsetX,
          };
        case 2:
          return {
            top: movePosition.offsetY,
            left: downAndUpPosition.offsetX,
          };
        case 3:
          return {
            top: downAndUpPosition.offsetY,
            left: movePosition.offsetX,
          };
        case 4:
          return {
            top: downAndUpPosition.offsetY,
            left: downAndUpPosition.offsetX,
          };
      }
    }
    return {
      top: 0,
      left: 0,
    };
 }, [downAndUpPosition, movePosition]);

最后我們計(jì)算選區(qū)的寬度和高度,通過計(jì)算落點(diǎn)位置與鼠標(biāo)移動后最終位置的差值可獲取寬高。代碼如下:

const offsetSize = useMemo(() => {
    if (downAndUpPosition && movePosition) {
      return {
        width: Math.abs(downAndUpPosition.offsetX - movePosition.offsetX),
        height: Math.abs(downAndUpPosition.offsetY - movePosition.offsetY),
      };
    }
    return {
      width: 0,
      height: 0,
    };
 }, [downAndUpPosition, movePosition]);

這樣就能夠創(chuàng)建一個(gè)選區(qū),完整代碼如下圖:

type Position = {
  offsetX: number;
  offsetY: number;
};
const boardStyle: CSSProperties = {
  width: "100%",
  height: "calc(100vh - 10px)",
  position: "relative",
};
const SelectArea = ()=>{
const [isMove, setIsMove] = useState<boolean>(false);
const [downAndUpPosition, setDownAndUpPosition] = useState<Position>();
const [movePosition, setMovePosition] = useState<Position>();
const handleMouseDown = (event: React.MouseEvent) => {
    setIsMove(true);
    let mouseDownPosition: Position = {
      offsetX: event.pageX - left,
      offsetY: event.pageY,
    };
    setDownAndUpPosition(mouseDownPosition);
  };
const handleMouseMove = (event: React.MouseEvent) => {
    if (!isMove) return;
    let movePosition: Position = {
      offsetX: event.pageX - left,
      offsetY: event.pageY,
    };
    setMovePosition(movePosition);
  };
const handleMouseUp = () => {
    setIsMove(false);
  };
const returnDivPosition = (
    downAndUpPosition: Position,
    movePosition: Position
  ) => {
    const downPageX = downAndUpPosition.offsetX;
    const downPageY = downAndUpPosition.offsetY;
    const movePageX = movePosition.offsetX;
    const movePageY = movePosition.offsetY;
    if (downPageX >= movePageX && downPageY >= movePageY) {
      return 1;
    }
    if (downPageX <= movePageX && downPageY >= movePageY) {
      return 2;
    }
    if (downPageX >= movePageX && downPageY <= movePageY) {
      return 3;
    }
    if (downPageX <= movePageX && downPageY <= movePageY) {
      return 4;
    }
 };
const offsetSize = useMemo(() => {
    if (downAndUpPosition && movePosition) {
      return {
        width: Math.abs(downAndUpPosition.offsetX - movePosition.offsetX),
        height: Math.abs(downAndUpPosition.offsetY - movePosition.offsetY),
      };
    }
    return {
      width: 0,
      height: 0,
    };
  }, [downAndUpPosition, movePosition]);
  const offsetPosition = useMemo(() => {
    if (downAndUpPosition && movePosition) {
      const quadrant = returnDivPosition(downAndUpPosition, movePosition);
      switch (quadrant) {
        case 1:
          return {
            top: movePosition.offsetY,
            left: movePosition.offsetX,
          };
        case 2:
          return {
            top: movePosition.offsetY,
            left: downAndUpPosition.offsetX,
          };
        case 3:
          return {
            top: downAndUpPosition.offsetY,
            left: movePosition.offsetX,
          };
        case 4:
          return {
            top: downAndUpPosition.offsetY,
            left: downAndUpPosition.offsetX,
          };
      }
    }
    return {
      top: 0,
      left: 0,
    };
  }, [downAndUpPosition, movePosition]);
  return (
    <div
      onMouseDown={handleMouseDown}
      onMouseMove={handleMouseMove}
      onMouseUp={handleMouseUp}
      style={boardStyle}
    >
        <Electorate
          top={offsetPosition.top}
          left={offsetPosition.left}
          width={offsetSize.width}
          height={offsetSize.height}
        />
    </div>
  );
}
type Props = {
  top: number;
  left: number;
  width: number;
  height: number;
};
const Electorate: FC<Props> = ({ top, left, width, height }) => {
  return (
    <div
      style={{
        top: `${top}px`,
        left: `${left}px`,
        width: `${Math.abs(width)}px`,
        height: `${Math.abs(height)}px`,
      }}
      className="electorate"
    />
  );
};
//electorate樣式
.electorate {
    position: absolute;
    border: 1px solid rgba(33, 127, 235, 0.534);
    background-color: rgba(33, 127, 235, 0.3);
}

到此這篇關(guān)于React實(shí)現(xiàn)前端選區(qū)的示例代碼的文章就介紹到這了,更多相關(guān)React 前端選區(qū)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Taro?React自定義TabBar使用useContext解決底部選中異常

    Taro?React自定義TabBar使用useContext解決底部選中異常

    這篇文章主要為大家介紹了Taro?React底部自定義TabBar使用React?useContext解決底部選中異常(需要點(diǎn)兩次才能選中的問題)示例詳解,有需要的朋友可以借鑒參考下
    2023-08-08
  • React-Router如何進(jìn)行頁面權(quán)限管理的方法

    React-Router如何進(jìn)行頁面權(quán)限管理的方法

    本篇文章主要介紹了React-Router如何進(jìn)行頁面權(quán)限管理的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-12-12
  • 路由react-router-dom的基本使用教程

    路由react-router-dom的基本使用教程

    在React中,路由是一套映射規(guī)則,是URL路徑與組件的對應(yīng)關(guān)系。使用React路由,就是配置路徑和組件的對應(yīng)關(guān)系,這篇文章主要介紹了路由react-router-dom的使用,需要的朋友可以參考下
    2023-02-02
  • React如何使用refresh_token實(shí)現(xiàn)無感刷新頁面

    React如何使用refresh_token實(shí)現(xiàn)無感刷新頁面

    本文主要介紹了React如何使用refresh_token實(shí)現(xiàn)無感刷新頁面,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • React中閉包陷阱的幾種情及解決方案

    React中閉包陷阱的幾種情及解決方案

    在react中我們使用其提供的Hooks中的useState,useEffect,useCallback 時(shí),可能會造成閉包陷阱,下面我們來看一下出現(xiàn)的情況以及如何解決,感興趣的小伙伴跟著小編一起來看看吧
    2024-07-07
  • 理解react中受控組件和非受控組件及應(yīng)用場景

    理解react中受控組件和非受控組件及應(yīng)用場景

    當(dāng)涉及到React框架時(shí),了解受控組件和非受控組件是非常重要的概念,本文主要介紹了理解react中受控組件和非受控組件及應(yīng)用場景,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • react中實(shí)現(xiàn)將一個(gè)視頻流為m3u8格式的轉(zhuǎn)換

    react中實(shí)現(xiàn)將一個(gè)視頻流為m3u8格式的轉(zhuǎn)換

    這篇文章主要介紹了react中實(shí)現(xiàn)將一個(gè)視頻流為m3u8格式的轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • 更強(qiáng)大的React 狀態(tài)管理庫Zustand使用詳解

    更強(qiáng)大的React 狀態(tài)管理庫Zustand使用詳解

    這篇文章主要為大家介紹了更強(qiáng)大的React 狀態(tài)管理庫Zustand使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • 淺談React多個(gè)setState會調(diào)用幾次

    淺談React多個(gè)setState會調(diào)用幾次

    在React的生命周期鉤子和合成事件中,多次執(zhí)行setState,會被調(diào)用幾次,本文就詳細(xì)的介紹一下,感興趣的可以了解一下
    2021-11-11
  • React Native從類組件到函數(shù)組件詳解

    React Native從類組件到函數(shù)組件詳解

    這篇文章主要介紹了React Native從類組件到函數(shù)組件方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03

最新評論

旅游| 金秀| 梅州市| 周宁县| 兰考县| 天全县| 富宁县| 玛沁县| 延长县| 沿河| 平利县| 彰化市| 凤翔县| 呈贡县| 荃湾区| 什邡市| 兰州市| 新龙县| 襄樊市| 滁州市| 缙云县| 尼勒克县| 秀山| 凌云县| 贵州省| 利津县| 徐水县| 增城市| 涿鹿县| 甘洛县| 凉城县| 隆昌县| 锡林郭勒盟| 林甸县| 岳池县| 沈阳市| 广东省| 桃园县| 浙江省| 台江县| 林西县|