10 JS 實(shí)現(xiàn) Checkbox 中 Shift 批量多選功能

作者:?緝熙Soyaine
簡介:JavaScript30Wes Bos 推出的一個(gè) 30 天挑戰(zhàn)奸绷。項(xiàng)目免費(fèi)提供了 30 個(gè)視頻教程躏筏、30 個(gè)挑戰(zhàn)的起始文檔和 30 個(gè)挑戰(zhàn)解決方案源代碼。目的是幫助人們用純 JavaScript 來寫東西赊瞬,不借助框架和庫,也不使用編譯器和引用。現(xiàn)在你看到的是這系列指南的第 10 篇豹障。完整指南在 GitHub,喜歡請(qǐng) Star 哦?(?*)

創(chuàng)建時(shí)間:2017-01-07
最后更新:2017-01-07

實(shí)現(xiàn)效果

shift 多選效果示例

初始文檔中提供了一組 checkbox 類型的 input 元素焦匈,選中某個(gè)復(fù)選框時(shí)血公,其 <p> 標(biāo)簽中的文字會(huì)顯示刪除線。最終效果是缓熟,提供按下 Shift 鍵后進(jìn)行多選操作的功能累魔。 在線體驗(yàn)請(qǐng)點(diǎn)這里摔笤。

過程指南

  1. 獲取所有的 <input> 元素,并添加事件監(jiān)聽
    const boxs = document.querySelectorAll('.inbox input[type="checkbox"]');
    boxs.forEach(box => box.addEventListener('click', handleCheck));
    
  2. 編寫 handleCheck 內(nèi)部的處理邏輯(細(xì)節(jié)請(qǐng)看下一部分)

解決思路

在談具體的代碼時(shí)垦写,先講講思路吕世。首先來復(fù)現(xiàn)一下,當(dāng)你按下 Shift 鍵進(jìn)行多選時(shí)梯投,發(fā)生了什么命辖?

  1. 選中 A 項(xiàng)
  2. 按下 Shift
  3. 再選中 B 項(xiàng)
  4. A-B 之間的所有項(xiàng)都被選中

關(guān)鍵點(diǎn)就在于 A、B 劃出了一個(gè)范圍分蓖,在這個(gè)范圍之內(nèi)的元素狀態(tài)發(fā)生了改變尔艇。A 是上一次操作選中的對(duì)象,B 是此次操作對(duì)象么鹤,之后的內(nèi)容將會(huì)用這兩個(gè)單詞來敘述终娃。下面的方案就依據(jù)劃定范圍的方法不同來進(jìn)行區(qū)分。

方法一

Wes Bos 在文檔里提供了一種解決辦法:用一個(gè)變量蒸甜,來標(biāo)記這個(gè)范圍棠耕。

變量初始值為 false,當(dāng)按下 Shift 鍵且同時(shí)選中了某個(gè)元素的時(shí)候迅皇,遍歷所有項(xiàng)昧辽,遍歷過程中,若遇到 A 或 B登颓,則將標(biāo)記值取反搅荞。同時(shí),將所有標(biāo)記為 true 的項(xiàng)設(shè)置為選中框咙。

let lastChecked;

//  處理方法一:用變量 inBetween 對(duì)需要選中的元素進(jìn)行標(biāo)記
function handleCheck0(e) {
    let inBetween = false;
    if(e.shiftKey && this.checked){
        boxs.forEach(input => {
            console.log(input);
            if(input === lastChecked || input ===this) {
                inBetween = !inBetween;
            }
            if(inBetween) {
                console.log("on");
                input.checked = true;
            }
    });
    }
    lastChecked = this;
}

延伸思考

上面會(huì)出現(xiàn)一個(gè)問題咕痛,初次加載頁面時(shí),按住 Shift 再點(diǎn)擊某一項(xiàng)喇嘱,此項(xiàng)之后的元素都會(huì)被選中茉贡。此外,對(duì)于取消選中者铜,無法批量操作腔丧。所以我參照了 Stack Overflow 的一個(gè)答案: How can I shift-select multiple checkboxes like GMail? 改進(jìn)得到第二種解決方案。

方法二

方法一中的 inBetween 僅僅表示此項(xiàng)是否在被選中的范圍中作烟,此處會(huì)賦給它更多的意義愉粤,用它來表示此項(xiàng)是選中還是未選中,而范圍劃定則由數(shù)組來解決拿撩。

首先將獲取到的 <input> 組轉(zhuǎn)化為數(shù)組衣厘,針對(duì)每次操作,獲取 A 和 B,利用 indexOf() 來獲得 A 和 B 在數(shù)組中的索引值影暴,由此即可確定范圍错邦,并能通過 slice() 來直接截取 A-B 的所有 DOM 元素,并進(jìn)行狀態(tài)改變的操作型宙,而變量 onOff 表示 A-B 范圍內(nèi)的狀態(tài)撬呢,true 表示選中,false 表示取消選中早歇。

  1. 轉(zhuǎn)換 Nodelist 為數(shù)組
    const boxs = document.querySelectorAll('.inbox input[type="checkbox"]');
    const boxArr = Array.from(boxs);
    
  2. 針對(duì)按下了 Shift 鍵的情況倾芝,獲取 A-B 范圍
    let start = boxArr.indexOf(this);
    let end = boxArr.indexOf(lastChecked);
    
  3. 截取該范圍內(nèi)的數(shù)組元素讨勤,并改變選中狀態(tài)
    boxArr.slice(Math.min(start, end), Math.max(start, end) + 1)
                       .forEach(input => input.checked = onOff);
    
  4. 確定選中 or 取消選中
    onOff = lastChecked.checked ? true : false;
    
  5. 標(biāo)記 A 值
    if(!lastChecked) lastChecked = this;
    /* ... */
    lastChecked = this;
    

注意箭跳,以上幾點(diǎn)是按點(diǎn)抽出的分塊代碼,整合起來的解決辦法如下:

const boxArr = Array.from(boxs);
let lastChecked;
let onOff = false;

// 處理方法二:利用數(shù)組索引獲取需要選中的范圍
function handleCheck1(e) {
    if(!lastChecked) lastChecked = this;
    onOff = lastChecked.checked ? true : false;
    if(e.shiftKey) {
        let start = boxArr.indexOf(this);
        let end = boxArr.indexOf(lastChecked);
        boxArr.slice(Math.min(start, end), Math.max(start, end) + 1)
                   .forEach(input => input.checked = onOff);
        console.log(start + "+" + end);
    }
    lastChecked = this;
}

這樣一來潭千,挑戰(zhàn) 10 就完谱姓!成!啦刨晴!恭喜走完了 1/3 的路程(o)/~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末屉来,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子狈癞,更是在濱河造成了極大的恐慌茄靠,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝶桶,死亡現(xiàn)場離奇詭異慨绳,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)真竖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門脐雪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人恢共,你說我怎么就攤上這事战秋。” “怎么了讨韭?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵脂信,是天一觀的道長。 經(jīng)常有香客問我透硝,道長狰闪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任蹬铺,我火速辦了婚禮尝哆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘甜攀。我一直安慰自己秋泄,他們只是感情好琐馆,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著恒序,像睡著了一般瘦麸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上歧胁,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天滋饲,我揣著相機(jī)與錄音,去河邊找鬼喊巍。 笑死屠缭,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的崭参。 我是一名探鬼主播呵曹,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼何暮!你這毒婦竟也來了奄喂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤海洼,失蹤者是張志新(化名)和其女友劉穎跨新,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坏逢,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡域帐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了词疼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俯树。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖贰盗,靈堂內(nèi)的尸體忽然破棺而出许饿,到底是詐尸還是另有隱情,我是刑警寧澤舵盈,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布陋率,位于F島的核電站,受9級(jí)特大地震影響秽晚,放射性物質(zhì)發(fā)生泄漏瓦糟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一赴蝇、第九天 我趴在偏房一處隱蔽的房頂上張望菩浙。 院中可真熱鬧,春花似錦、人聲如沸劲蜻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽先嬉。三九已至轧苫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間疫蔓,已是汗流浹背含懊。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留衅胀,地道東北人岔乔。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像拗小,于是被迫代替她去往敵國和親重罪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子樱哼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 《ilua》速成開發(fā)手冊(cè)3.0 官方用戶交流:iApp開發(fā)交流(1) 239547050iApp開發(fā)交流(2) 1...
    葉染柒丶閱讀 10,533評(píng)論 0 11
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理哀九,服務(wù)發(fā)現(xiàn),斷路器搅幅,智...
    卡卡羅2017閱讀 134,599評(píng)論 18 139
  • 《ijs》速成開發(fā)手冊(cè)3.0 官方用戶交流:iApp開發(fā)交流(1) 239547050iApp開發(fā)交流(2) 10...
    葉染柒丶閱讀 5,073評(píng)論 0 7
  • “知道了那么多道理茄唐,卻依然過不好這一生”息裸。我們常常說:很多道理我都懂啊,可是我就是做不到沪编。 是啊知道...
    二歡_笑8閱讀 260評(píng)論 0 0
  • 前幾天呼盆,受一位圈友的影響,他給我發(fā)了一個(gè)小和尚的公眾號(hào)蚁廓,我看了里面的文章访圃,說的確實(shí)很有理,同時(shí)文章中的小和尚萌到我...
    五點(diǎn)人家閱讀 367評(píng)論 2 7