vue 通過 Ctrl 、Shift 鍵 + 點擊鼠標實現 div 多選操作
前言
我在做東西的時候有這樣一個需求,就是有一個div的列表,想通過按住Ctrl鍵后點擊div實現多選的功能,在一個是按住 Shift鍵都點擊前后兩個div選中區域的效果。
就是選擇下面圖片,每個圖片包含在一個div下面。
邏輯
其實大體的邏輯就是:
- 進入頁面,開啟鍵盤監聽事件,監聽 Ctrl 鍵和 Shift 鍵的按下和抬起事件,因為需要在按住這兩個鍵的時候才可以實現多選功能。
- 在div上添加一個點擊事件,將div設置成一個選中的樣式,當然,在點擊事件里面得判斷一下,判斷鍵盤是不是被按下了,沒有按下的話,不做任何處理。
就是這么簡單的問題。
接下來就是相關主要代碼的編寫問題,因為每個人的項目和需求是不一樣的,所以我就簡單分享一下自己的主要代碼邏輯。
代碼
首先在vue項目里面定義幾個變量哈。
data() {
return {
tableData: [], // 假設這個是上邊小div的列表,后台數據請求回來的嗎,假設已經有數據了哈,里面有唯一標識符id
isshift: false, // 快捷鍵 shift 是否被按下
isctrl: false, // 快捷鍵 ctrl 是否被按下
selectedState: [], // 上方div圖切是否被多選中,如果多選了就把他的id放到這個列表里面,當然可以不用,直接在相應的列表對象加一個參數isSelected也行,具體看項目和個人編碼習慣哈。
shiftNum: '', // shift 按下后選擇的第一個div下標,因為shift的時候要點兩個div都中間包裹的都要切換為被選中狀態
}
}
其次有一個鍵盤監聽事件
// 監聽鍵盤
keyDown() {
// 鍵盤按下事件
document.onkeydown = (e) => {
// 取消默認事件
e.preventDefault();
//事件對象兼容
let e1 = e || event || window.event || arguments.callee.caller.arguments[0]
//鍵盤按鍵判斷:左箭頭-37;上箭頭-38;右箭頭-39;下箭頭-40 回車:13 ctrl:17 shift:16
switch (e1.keyCode) {
case 16:
this.isshift = true; // 如果shift按下就讓他按下的標識符變為true
break;
case 17:
this.isctrl = true; // 如果ctrl按下就讓他按下的標識符變為true
break;
}
}
// 鍵盤抬起事件
document.onkeyup = (e) => {
// 取消默認事件
e.preventDefault();
//事件對象兼容
let e1 = e || event || window.event || arguments.callee.caller.arguments[0]
switch (e.keyCode) {
case 16:
this.shiftNum = ''
this.isshift = false; // 如果shift抬起下就讓他按下的標識符變為false
break;
case 17:
this.isctrl = false; // 如果ctrl抬起下就讓他按下的標識符變為false
break;
}
}
},
這樣ctrl和shift鍵的監聽事件就完成了,上面的方法在頁面初始化完成的時候調用一下子哈,別忘了。
activated() {
this.keyDown()
}
接下來就是點擊小div的邏輯了。
給小div一個點擊事件,我還寫嗎?都知道哈,寫一下子吧, 不寫樣式了,當然循環的時候不要用index,我這瞎寫的,不要計較哈,分享一下,主要是說多選功能。
<div v-for="(item, index) in tableData" :key="index">
<div @click="selectImage(item, index)">
</div>
</div>
好了,大體就是這個意思,然后點擊的時候把這個數據對象傳進去,里面包含着一個表示這個div的唯一標識符id。
然后就是最重要的多選的邏輯處理。
selectImage(item, index) {
if (this.isctrl) { // 如果按下的是ctrl
let str = item.id // 這行代碼沒必要,但是案例是根據我項目改的,就懶得刪了
let i = this.selectedState.indexOf(str) // 判斷選中列表中是否包含這個點擊的div
if (i < 0) {
this.selectedState.push(str) // 如果不包含就加進去
} else {
this.selectedState.splice(i, 1); // 如果包含就刪,表示按下ctrl鍵點一下選中,在點一下取消選中
}
} else if (this.isshift) { // 如果按下的是shift
if (this.shiftNum === '') { // 如果還沒點下第一個div
this.shiftNum = index // 讓第一個div的下標賦值給shiftNum
let str = item.id
let i = this.selectedState.indexOf(str)
if (i < 0) {
this.selectedState.push(str)
} else {
this.selectedState.splice(i, 1);
}
} else { // 如果點擊第一個了
if (this.shiftNum > index) { // 選中第一個的索引大於當前點擊的索引
for (let j = index; j <= this.shiftNum; j++) { // 把中間的都選中
let str = this.tableData[j].id
let i = this.selectedState.indexOf(str)
if (i < 0) {
this.selectedState.push(str)
}
}
} else {
for (let j = this.shiftNum; j <= index; j++) {
let str = this.tableData[j].id
let i = this.selectedState.indexOf(str)
if (i < 0) {
this.selectedState.push(str)
}
}
}
}
}
},
ok,這樣就可以了。
選中樣式的話我就不寫了,根據自己的喜好自己寫就可以了,可以根據div的id是否包含在selectedState數組里面進行判斷是否被選中。
太厲害了我!哈哈哈哈!!!
下面是我做的項目的大體樣式,主要就是上邊的邏輯。