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

基于Vue3+TypeScript實現(xiàn)鼠標框選功能

 更新時間:2024年07月05日 08:42:39   作者:廣島原子  
這篇文章主要介紹了基于Vue3+TypeScript實現(xiàn)鼠標框選功能,文中通過代碼示例給大家講解的非常纖細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下

實現(xiàn)功能:

  • 選擇、取消選擇單個元素、同時選擇多個元素。
  • 鼠標懸浮變色。
  • 框選、滾動框選區(qū)域。
  • 同時選擇多個區(qū)域。

最終實現(xiàn)效果

1. HTML代碼

 <div class="right-bottom">
    <<img src="div" alt="" width="70%" />
      class="page"
      ref="pageRef"
      @scroll="handleScroll"
      @mouseup="handleMouseUp"
    >
      <table class="table" @mousemove="handleMouseMove">
        <tr v-for="(row, rowIndex) in tableData" :key="rowIndex">
          <td
            id="td"
            v-for="(col, colIndex) in row"
            :key="colIndex"
            :class="{
              'table-item-active': selectedCells.has(rowIndex + '-' + colIndex),
            }"
            :style="{
              backgroundColor: selectedCells.has(rowIndex + '-' + colIndex)
                ? 'skyblue'
                : col.color,
            }"
            @mousedown.prevent="startSelect(rowIndex, colIndex)"
          >
            <div
              class="table-item"
              :class="{
                'item-hover': hoverPosition == `${rowIndex}-${colIndex}`,
              }"
              @click="handleItemClick(rowIndex, colIndex)"
              @mouseenter="handleMouseEnter(rowIndex, colIndex)"
              @mouseleave="handleMouseLeave(rowIndex, colIndex)"
            >
              {{ col.hole }}
            </div>
          </td>
        </tr>
      </table>
    </div>
  </div>

2. 定義全局變量

// 已選擇的單元格。因為可能出現(xiàn)重復框選單元格的情況,所以這里最好使用Set類型。
const selectedCells = reactive(new Set([]));
// 矩陣起始坐標位置??蜻x矩陣在頁面上的位置,使用時請根據(jù)實際情況計算
let tableStartX = 0;
let tableStartY = 0;
// 單元格寬高
let cellWidth = 63;
let cellHeight = 63;
// 是否按住ctrl
let isClickCtrl = false;
// 當前懸浮單元格坐標
let hoverPosition = ref('');

3. 實現(xiàn)單個元素選擇、取消選擇、按ctrl同時選擇多個元素

/**
 * @description: 點擊單元格事件
 * @param row 當前單元格X坐標
 * @param column 當前單元格Y坐標
 */
const handleItemClick = (row: number, column: number) => {
  // 按下ctrl
  document.onkeydown = (e: KeyboardEvent) => {
    if (e.key === 'Control') isClickCtrl = true;
  };
  // 松開ctrl
  document.onkeyup = (e: KeyboardEvent) => {
    if (e.key === 'Control') isClickCtrl = false;
  };
  // 如果按住ctrl鍵
  if (isClickCtrl) {
    // 點擊了已經(jīng)選中的元素,取消選中; 否則選中
    if (selectedCells.has(`${row}-${column}`)) {
      selectedCells.delete(`${row}-${column}`);
    }else {
     selectedCells.add(`${row}-${column}`);
    }
  }
  // 如果沒有點擊ctrl鍵,則先清空所有選中的元素,然后選中當前元素
  else {
    selectedCells.clear();
    selectedCells.add(`${row}-${column}`);
  }
};

4. 鼠標懸浮變色

/**
 * @description: 鼠標懸浮單元格變色
 * @param row 當前單元格X坐標
 * @param column 當前單元格Y坐標
 */
// 鼠標進入單元格,使用防抖降低代碼重復執(zhí)行次數(shù),提高性能
const handleMouseEnter = _.debounce((row: number, column: number) => {
  hoverPosition = `${row}-${column}`;
}, 100);
// 鼠標離開單元格
const handleMouseLeave = _.debounce(() => {
  hoverPosition = '';
}, 50);

5. 框選、滾動框選元素功能實現(xiàn)

5.1 獲取框選區(qū)域內的所有元素

實現(xiàn)步驟:

  • 拿到起始單元格坐標以及結束單元格坐標。
  • 根據(jù)起始結束坐標計算出框選區(qū)域內的所有單元格。

實現(xiàn)原理:例1. 如起始坐標為 startCell = [0, 0],結束坐標 endCell = [2, 2]
則當前區(qū)域的元素包括:

0,00,10,2
1,01,11,2
2,02,12,2

例2. 如起始坐標為 startCell = [3, 4],結束坐標 endCell = [1, 2]
則當前區(qū)域的元素包括:

1,21,31,4
2,22,32,4
3,23,33,4

以此類推。。。

結論: 根據(jù)以上實例可得,我們只需要拿到起止位置X坐標和Y坐標,然后用雙重for循環(huán)即可得到當前框選區(qū)域內的所有元素

獲取框選區(qū)域內的所有元素方法:

/**
 * @description: 根據(jù)起始坐標和結束坐標,設置選中區(qū)域
 * @param startX 起始坐標x
 * @param startY 起始坐標y
 * @param endX 結束坐標x
 * @param endY 結束坐標y
 */
const selectRange = (
  startX: number,
  startY: number,
  endX: number,
  endY: number
) => {
  for (
    let rowIndex = Math.min(startX, endX);
    rowIndex <= Math.max(startX, endX);
    rowIndex++
  ) {
    for (
      let cellIndex = Math.min(startY, endY);
      cellIndex <= Math.max(startY, endY);
      cellIndex++
    ) {
      selectedCells.add(`${rowIndex}-${cellIndex}`);
    }
  }
};

5.2 計算框選結束坐標

實現(xiàn)原理:首先分別計算出鼠標距離矩陣原點left距離和top距離,然后再用這個距離除單個單元格的寬高就能得到結束坐標。

如果矩陣框選有滾動操作,只要再加上滾動距離即可。

5.3 鼠標移動事件

// 起始單元格坐標
let startCell: [number, number] | null = null;
// 鼠標點擊事件,設置起始坐標
function startSelect(rowIndex: number, cellIndex: number) {
  startCell = [rowIndex, cellIndex];
}
// 鼠標抬起事件,將起始坐標設置為null
const handleMouseUp = () => {
  startCell = null;
};
// 鼠標移動事件
const handleMouseMove = (e: MouseEvent) => {
  debounceFun1(e);
};
const debounceFun1 = _.debounce((e: MouseEvent) => {
  // 如果沒有起始坐標,則不執(zhí)行
  if (!startCell) return;
  // 按下ctrl鍵
  document.onkeydown = (e: KeyboardEvent) => {
    if (e.key === 'Control') isClickCtrl = true;
  };
  // 松開ctrl鍵
  document.onkeyup = (e: KeyboardEvent) => {
    if (e.key === 'Control') isClickCtrl = false;
  };
  endXY.x = e.clientX;
  endXY.y = e.clientY;
  
  // 獲取鼠標移動的當前單元格坐標,并設置為框選結束坐標
  let endCell: [number, number] | null = null;
  endCell = [
    Math.floor((e.clientY  + scrollXY.y - tableStartY) / cellHeight),
    Math.floor((e.clientX  + scrollXY.x - tableStartX) / cellWidth),
  ];
  // 如果鼠標位置發(fā)生變化,則清空已選擇的單元格,并重新設置選中區(qū)域
  if (!isClickCtrl) {
    selectedCells.clear()
  }
  // 根據(jù)起始坐標和結束坐標,設置選中區(qū)域
  selectRange(...startCell, ...endCell);
}, 50);

5.4 滾輪滾動事件

const scrollXY = reactive({ x: 0, y: 0 });
const handleScroll = (e: any) => {
  scrollXY.x = e.target.scrollLeft;
  scrollXY.y = e.target.scrollTop;
  if (!startCell) return;
  const endCell: [number, number] = [
    Math.floor((endXY.y + e.target.scrollTop - tableStartY) / cellHeight),
    Math.floor((endXY.x + e.target.scrollLeft - tableStartX) / cellWidth),
  ];
  selectRange(...startCell, ...endCell);
};

6. 樣式相關代碼

.item-hover {
  background-color: #bae0ff !important;
}
th,
td {
  border: 1px solid black;
  border-collapse: collapse;
}
.right-bottom {
  margin-left: 200px;
  height: 800px;
  width: 800px;
  .page {
    width: 100%;
    height: 100%;
    overflow: scroll;
    margin: 0 auto;
    .table {
      overflow-x: auto;
      overflow-y: auto;
      .table-item {
        position: relative;
        font-size: 13px;
        display: flex;
        justify-content: center;
        align-items: center;
        width: 60px;
        height: 60px;
        .coordinates {
          position: absolute;
          left: 0;
          top: 0;
          font-size: 10px;
        }
      }
      .table-item-active {
        background-color: skyblue;
      }
    }
  }
  .page ::selection {
    background-color: transparent;
  }
}

7. 總結

實際開發(fā)中,矩陣原點坐標可能會因為各種情況發(fā)生改變(這里默認是[0,0]),需要根據(jù)實際情況計算,否則框選區(qū)域會出現(xiàn)錯位的情況。最后希望這個組件能幫助到有需要的人,歡迎大家提出建議!

以上就是基于Vue3+TypeScript實現(xiàn)鼠標框選功能的詳細內容,更多關于Vue3 TypeScript鼠標框選的資料請關注腳本之家其它相關文章!

相關文章

  • vue組件 keep-alive 和 transition 使用詳解

    vue組件 keep-alive 和 transition 使用詳解

    這篇文章主要介紹了vue組件 keep-alive 和 transition 使用詳解,需要的朋友可以參考下
    2019-10-10
  • Vue的底層原理你了解多少

    Vue的底層原理你了解多少

    這篇文章主要為大家詳細介紹了Vue的底層原理,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • Vue常用的修飾符及應用場景解讀

    Vue常用的修飾符及應用場景解讀

    這篇文章主要介紹了Vue常用的修飾符及應用場景解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • element-ui?el-upload實現(xiàn)上傳文件及簡單的上傳文件格式驗證功能

    element-ui?el-upload實現(xiàn)上傳文件及簡單的上傳文件格式驗證功能

    前端上傳文件后,后端接受文件進行處理后直接返回處理后的文件,前端直接再將文件下載下來,下面這篇文章主要給大家介紹了關于element-ui?el-upload實現(xiàn)上傳文件及簡單的上傳文件格式驗證功能的相關資料,需要的朋友可以參考下
    2022-11-11
  • Vue.js 動態(tài)為img的src賦值方法

    Vue.js 動態(tài)為img的src賦值方法

    下面小編就為大家分享一篇Vue.js 動態(tài)為img的src賦值方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03
  • vue使用highcharts自定義儀表盤圖表

    vue使用highcharts自定義儀表盤圖表

    這篇文章主要為大家詳細介紹了vue使用highcharts自定義儀表盤圖表,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Vue.js開發(fā)環(huán)境快速搭建教程

    Vue.js開發(fā)環(huán)境快速搭建教程

    這篇文章主要為大家詳細介紹了Vue.js開發(fā)環(huán)境快速搭建教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • vue購物車插件編寫代碼

    vue購物車插件編寫代碼

    這篇文章主要為大家詳細介紹了vue購物車插件的編寫代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • vue中provide、inject的使用方法案例詳解

    vue中provide、inject的使用方法案例詳解

    本教程是介紹如何在vue中使用provide和inject,在 Vue 中,provide 和 inject 是用于實現(xiàn)祖先組件向后代組件傳遞數(shù)據(jù)的一種方式,對vue中provide、inject的使用方法感興趣的朋友一起看看吧
    2024-02-02
  • vue中的按鈕綁定事件小案例

    vue中的按鈕綁定事件小案例

    這篇文章主要介紹了vue中的按鈕綁定事件小案例,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11

最新評論