欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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)擊和移動(dòng)來創(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)在移動(dòng)過程中的偏移量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)移動(dòng)事件來獲取鼠標(biāo)移動(dòng)的范圍,在這里我們需要先獲取鼠標(biāo)初始位置,通過movedown事件確定鼠標(biāo)起始位置,通過isMove來判斷是否鼠標(biāo)落下并開始移動(dòng),記錄鼠標(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)移動(dòng)坐標(biāo)點(diǎn),如果鼠標(biāo)未落下則不觸發(fā)移動(dòng)事件,避免重復(fù)渲染,最后在moveup事件中取消移動(dòng)標(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)移動(dòng)坐標(biāo)后,我們需要去計(jì)算鼠標(biāo)移動(dòng)坐標(biāo)與起始位置的坐標(biāo)象限,如果起始位置的left與top均小于鼠標(biāo)移動(dòng)后坐標(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)移動(dòng)的最終位置就是元素偏移量,如果為第二象限則鼠標(biāo)移動(dòng)最終位置的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)移動(dòng)后最終位置的差值可獲取寬高。代碼如下:

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)文章

  • antd?upload上傳如何獲取文件寬高

    antd?upload上傳如何獲取文件寬高

    這篇文章主要介紹了antd?upload上傳如何獲取文件寬高問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • react-router-dom 嵌套路由的實(shí)現(xiàn)

    react-router-dom 嵌套路由的實(shí)現(xiàn)

    這篇文章主要介紹了react-router-dom 嵌套路由的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • 基于React封裝組件的實(shí)現(xiàn)步驟

    基于React封裝組件的實(shí)現(xiàn)步驟

    很多小伙伴在第一次嘗試封裝組件時(shí)會和我一樣碰到許多問題,本文主要介紹了基于React封裝組件的實(shí)現(xiàn)步驟,感興趣的可以了解一下
    2021-11-11
  • 使用react+redux實(shí)現(xiàn)彈出框案例

    使用react+redux實(shí)現(xiàn)彈出框案例

    這篇文章主要為大家詳細(xì)介紹了使用react+redux實(shí)現(xiàn)彈出框案例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • react?redux及redux持久化示例詳解

    react?redux及redux持久化示例詳解

    這篇文章主要為大家介紹了react?redux及redux持久化示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • react源碼層探究setState作用

    react源碼層探究setState作用

    寫react的時(shí)候,踩了幾次坑發(fā)現(xiàn)setstate之后state不會立刻更新,于是判定setstate就是異步的方法,但是直到有一天,我想立刻拿到更新的state去傳參另一個(gè)方法的時(shí)候,才問自己,為什么setstate是異步的?準(zhǔn)確地說,在React內(nèi)部機(jī)制能檢測到的地方,setState就是異步的
    2022-10-10
  • React動(dòng)畫實(shí)現(xiàn)方案Framer Motion讓頁面自己動(dòng)起來

    React動(dòng)畫實(shí)現(xiàn)方案Framer Motion讓頁面自己動(dòng)起來

    這篇文章主要為大家介紹了React動(dòng)畫實(shí)現(xiàn)方案Framer Motion讓頁面自己動(dòng)起來,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • react中使用echarts,并實(shí)現(xiàn)tooltip循環(huán)輪播方式

    react中使用echarts,并實(shí)現(xiàn)tooltip循環(huán)輪播方式

    這篇文章主要介紹了react中使用echarts,并實(shí)現(xiàn)tooltip循環(huán)輪播方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • React路由中的redux和redux知識點(diǎn)拓展

    React路由中的redux和redux知識點(diǎn)拓展

    這篇文章主要介紹了React路由中的redux和redux知識點(diǎn)拓展,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的朋友可以參考學(xué)習(xí)一下
    2022-08-08
  • react-native ListView下拉刷新上拉加載實(shí)現(xiàn)代碼

    react-native ListView下拉刷新上拉加載實(shí)現(xiàn)代碼

    本篇文章主要介紹了react-native ListView下拉刷新上拉加載實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08

最新評論