亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

徒手?jǐn)]UI之Cascader

junnplus / 2126人閱讀

摘要:但是如果一剎那我不想選江疏影了,我想選張雨綺因?yàn)樾卮螅紫任乙獜幕羲佳鄵Q到高圓圓,然后轉(zhuǎn)到張雨綺,選中展示出來,這時(shí)候就要先刪除霍思燕,然后把高圓圓和張雨綺進(jìn)來。

QingUI是一個(gè)UI組件庫
目前擁有的組件:DatePicker, TimePicker, Paginator, Tree, Cascader, Checkbox, Radio, Switch, InputNumber, Input
ES6語法編寫,無依賴
原生模塊化,Chrome63以上支持,請(qǐng)開啟靜態(tài)服務(wù)器預(yù)覽效果,靜態(tài)服務(wù)器傳送門
采用CSS變量配置樣式
辛苦造輪子,歡迎來github倉庫star:QingUI
寫在前面

去年年底項(xiàng)目中嘗試著寫過一個(gè)分頁的Angular組件,然后就有了寫QingUI的想法

過程還是非常有意思的

接下來我會(huì)用幾篇文章分別介紹每個(gè)組件的大概思路,請(qǐng)大家耐心等待

這一篇介紹Cascader級(jí)聯(lián)選擇器

點(diǎn)個(gè)star就是對(duì)我最好的支持

repo: QingUI
少廢話,先上圖

數(shù)據(jù)

既然是級(jí)聯(lián)選擇器,數(shù)據(jù)肯定是樹形結(jié)構(gòu),像這樣

const data = [
    {
        label: "霍思燕",
        sub: [
            {
                label: "江疏影",
            },
            {
                label: "倪妮",
            },
        ],
    },
    {
        label: "高圓圓",
        sub: [
            {
                label: "張雨綺",
            },
            {
                label: "宋佳",
            },
        ],
    },
];

你猜我最喜歡哪位女明星 :)

而且用戶點(diǎn)到哪一個(gè)label上,就呼出下一級(jí)列表

那么問題來了,我怎么知道我當(dāng)前在哪一級(jí),又在哪一個(gè)分支?

所以我需要給每一個(gè)分支做標(biāo)記,點(diǎn)到哪一個(gè)label上,就取出標(biāo)記,該標(biāo)記能指引我找到對(duì)應(yīng)的數(shù)據(jù)分支

我的方法是這樣的,新建一個(gè)字段queue,字段值是一個(gè)字符串形式的數(shù)字,位數(shù)表示當(dāng)前是第幾級(jí),數(shù)字表示當(dāng)前是第幾個(gè)分支

比如說queue = 131;,表示當(dāng)前在第一個(gè)分支下面的第三個(gè)分支下面的第一個(gè)分支

buildQueue(data, queue = "") {
    for (let i = 0; i < data.length; i++) {
        const item = data[i];
        const sub = item.sub;
        const newQueue = `${queue}${i}`;
        item[this.queue] = newQueue;
        if (sub) {
            this.buildQueue(sub, newQueue);
        }
    }
}

字段名其實(shí)我并沒有用queue,因?yàn)橛锌赡芤呀?jīng)被占用,我用的是時(shí)間戳組成的hash值,所以賦值的時(shí)候要寫成item[this.queue] = newQueue;

渲染的時(shí)候給DOM元素加一個(gè)data-v="${item[this.queue]}就行了

那么怎么讀呢?

這些數(shù)字其實(shí)就是數(shù)組的索引,加一個(gè)遞歸搞定

findSubByQueue(data, queue) {
    const n = Number.parseInt(queue.charAt(0));
    for (let i = 0; i < data.length; i++) {
        if (i === n) {
            if (queue.length > 1) {
                return this.findSubByQueue(data[i].sub, queue.slice(1));
            } else {
                return data[i].sub;
            }
        }
    }
}
事件

級(jí)聯(lián)肯定要支持點(diǎn)擊和懸浮兩種事件觸發(fā)機(jī)制

所以我用this.eventType來保存事件類型,其實(shí)兩種事件大部分代碼是可以復(fù)用的

for (let i = 0; i < $trunks.length; i++) {
    const $trunk = $trunks[i];
    const v = $trunk.dataset.v;
    const label = $trunk.querySelector(".label").innerHTML;
    const CL = $trunk.classList;
    $trunk.addEventListener(this.eventType, function(event) {
        event.stopPropagation();
        // 遍歷清除trunk的active
        self.removeTrunkActive($trunks);
        // 當(dāng)前trunk變成active
        CL.add("active");
        // 構(gòu)建路徑
        self.buildPath(v.length, label, false);
        // 找到子數(shù)據(jù)
        const sub = self.findSubByQueue(self.data, v);
        // 填充子board
        $subBoard.innerHTML = self.renderCascade(sub);
        // 添加事件
        self.$rowEvent($subBoard);
    });
}

注釋也寫的很清楚,首先是一個(gè)高亮的處理,然后要把當(dāng)前路徑保存下來,通過queue找到子數(shù)據(jù),然后渲染出來,最后給子節(jié)點(diǎn)添加事件

要知道,分支可以分為兩種,一種是下面還有分支,我把它稱作trunk,另一種是末梢,下面沒有分支了,我把它稱作leaf

點(diǎn)擊很容易,只給trunk添加事件就可以了

但是懸浮,leaf也要有事件,就是把之前的高亮和子數(shù)據(jù)清空

if (this.trigger === "hover") {
    for (let i = 0; i < $leafs.length; i++) {
        $leafs[i].addEventListener("mouseenter", function() {
            self.removeTrunkActive($trunks);
            $subBoard.innerHTML = "";
        });
    }
    // 離開curtain
    this.$curtain.addEventListener("mouseleave", function() {
        self.removeTrunkActive(self.$trunks);
        self.$subBoard.innerHTML = "";
    });
}

那么怎么選中呢?

到leaf才是一個(gè)完整的路徑,所以leaf特殊處理,無論是什么事件,點(diǎn)擊leaf選中,把路徑渲染出來

路徑

保存路徑是一個(gè)動(dòng)態(tài)的過程

因?yàn)槲铱赡懿榭戳四骋粋€(gè)分支,然后又查看另一個(gè)分支,最終選中了別的分支

所以保存路徑要根據(jù)路徑的長(zhǎng)度和當(dāng)前級(jí)別來確定是添加還是刪除

比如我現(xiàn)在在江疏影這里,還沒有選中,那么當(dāng)前是第二級(jí),路徑里只保存了霍思燕,如果我選中,那么簡(jiǎn)單,直接把江疏影push到數(shù)組里,展示出來。但是如果一剎那我不想選江疏影了,我想選張雨綺(因?yàn)樾卮螅紫任乙獜幕羲佳鄵Q到高圓圓,然后轉(zhuǎn)到張雨綺,選中展示出來,這時(shí)候就要先刪除霍思燕,然后把高圓圓和張雨綺push進(jìn)來。

buildPath(level, label, render) {
    if (this.path.length < level) {
        // 往下選擇,直接push
        this.path.push(label);
    } else {
        // 退回選擇,根據(jù)退回長(zhǎng)度刪除path元素,再push
        this.path = [...this.path.slice(0, level - 1), label];
    }
    if (render) {
        this.renderPath();
    }
}
搜索

突發(fā)奇想,我又想加一個(gè)搜索功能

比如說我現(xiàn)在搜集了好幾千個(gè)女明星,打亂格式化成樹形數(shù)據(jù),那我選擇起來可就困難了,難道每一個(gè)分支都查看一遍嗎?如果有搜索,我只要搜張雨綺,所有包含張雨綺的級(jí)聯(lián)都展示出來,是不是方便很多!

看起來很復(fù)雜的樣子

其實(shí),換一個(gè)思路,初始化的時(shí)候就把所有的路徑都遍歷出來,緩存在一個(gè)數(shù)組里,搜索的時(shí)候只要檢索這些字符串有沒有張雨綺,是不是回到我們熟悉的字符串操作上來了?

遍歷所有路徑

iterateAllPath() {
    const self = this;
    let temp = [];
    const data = pathPush([...this.data]);
    function pathPush(data, arr = []) {
        for (const item of data) {
            item.path = [];
            // 將路徑存入item中的數(shù)組
            item.path.push(...arr, item.label);
        }
        return data;
    }
    function recursive(data) {
        for (const item of data) {
            const sub = item.sub;
            if (sub) {
                // 將下一層放入temp
                temp.push(...pathPush(sub, item.path));
            } else {
                // 沒有下一層則路徑結(jié)束
                self.pathPool.push(item.path.join(self.seperator));
            }
        }
        if (temp.length) {
            // 重新初始化
            data = temp;
            temp = [];
            recursive(data);
        }
    }
    recursive(data);
}
for (const item of this.pathPool) {
    const match = item.match(reg);
    if (!match) {
        continue;
    }
    result.push(item);
}

別急,還有需求,我想把關(guān)鍵詞高亮

比如說我搜張雨綺,所有結(jié)果中張雨綺都要高亮

我搜張雨,所有結(jié)果中張雨都要高亮

這個(gè)也不復(fù)雜,用關(guān)鍵詞把路徑截成三段,如果關(guān)鍵詞在首尾那就截成兩段

這里有一個(gè)小問題,如果分隔符與關(guān)鍵詞之間有空格,展示結(jié)果總是不符合預(yù)期

后來才發(fā)現(xiàn),如果標(biāo)簽內(nèi)第一個(gè)字符是空格,空格會(huì)被忽略

所以還需要小小的處理一下

const reg = new RegExp(value, "i");
for (const item of this.pathPool) {
    const match = item.match(reg);
    if (!match) {
        continue;
    }
    result.push(item);
    const index = match.index;
    let [left, center, right] = [item.slice(0, index), match[0], item.slice(index + value.length)];
    // 如果標(biāo)簽內(nèi)第一個(gè)字符是空格,空格會(huì)被忽略
    if (right && right.startsWith(" ")) {
        right = ` ${right.trimLeft()}`;
    }
    tpl += `
        
${left ? `${left}` : ""} ${center} ${right ? `${right}` : ""}
`; } if (!tpl) { tpl = "
No Result
"; }
寫在后面

Cascader比較核心的邏輯就在這里了

相較前幾篇文檔,隔的時(shí)間有點(diǎn)長(zhǎng),不過Cascader不會(huì)讓你失望的

如果覺得QingUI還不錯(cuò),點(diǎn)個(gè)star激勵(lì)一下老夫

repo: QingUI

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/95316.html

相關(guān)文章

  • 徒手UIDatePicker

    摘要:是一個(gè)組件庫目前擁有的組件語法編寫,無依賴原生模塊化,以上支持,請(qǐng)開啟靜態(tài)服務(wù)器預(yù)覽效果,靜態(tài)服務(wù)器傳送門采用變量配置樣式辛苦造輪子,歡迎來倉庫四月份找工作,求內(nèi)推,坐標(biāo)深圳寫在前面去年年底項(xiàng)目中嘗試著寫過一個(gè)分頁的組件,然后就有了寫的想法 QingUI是一個(gè)UI組件庫目前擁有的組件:DatePicker, TimePicker, Paginator, Tree, Cascader, ...

    zilu 評(píng)論0 收藏0
  • 徒手UIPaginator

    摘要:是一個(gè)組件庫目前擁有的組件語法編寫,無依賴原生模塊化,以上支持,請(qǐng)開啟靜態(tài)服務(wù)器預(yù)覽效果,靜態(tài)服務(wù)器傳送門采用變量配置樣式辛苦造輪子,歡迎來倉庫四月份找工作,求內(nèi)推,坐標(biāo)深圳寫在前面去年年底項(xiàng)目中嘗試著寫過一個(gè)分頁的組件,然后就有了寫的想法 QingUI是一個(gè)UI組件庫目前擁有的組件:DatePicker, TimePicker, Paginator, Tree, Cascader, ...

    liuhh 評(píng)論0 收藏0
  • 徒手UITimePicker

    摘要:是一個(gè)組件庫目前擁有的組件語法編寫,無依賴原生模塊化,以上支持,請(qǐng)開啟靜態(tài)服務(wù)器預(yù)覽效果,靜態(tài)服務(wù)器傳送門采用變量配置樣式辛苦造輪子,歡迎來倉庫四月份找工作,求內(nèi)推,坐標(biāo)深圳寫在前面去年年底項(xiàng)目中嘗試著寫過一個(gè)分頁的組件,然后就有了寫的想法 QingUI是一個(gè)UI組件庫目前擁有的組件:DatePicker, TimePicker, Paginator, Tree, Cascader, ...

    Codeing_ls 評(píng)論0 收藏0
  • 徒手UITree

    摘要:是一個(gè)組件庫目前擁有的組件語法編寫,無依賴原生模塊化,以上支持,請(qǐng)開啟靜態(tài)服務(wù)器預(yù)覽效果,靜態(tài)服務(wù)器傳送門采用變量配置樣式辛苦造輪子,歡迎來倉庫四月份找工作,求內(nèi)推,坐標(biāo)深圳寫在前面去年年底項(xiàng)目中嘗試著寫過一個(gè)分頁的組件,然后就有了寫的想法 QingUI是一個(gè)UI組件庫目前擁有的組件:DatePicker, TimePicker, Paginator, Tree, Cascader, ...

    2i18ns 評(píng)論0 收藏0
  • 徒手框架--高并發(fā)環(huán)境下的請(qǐng)求合并

    摘要:我們就可以將這些請(qǐng)求合并,達(dá)到一定數(shù)量我們統(tǒng)一提交??偨Y(jié)一個(gè)比較生動(dòng)的例子給大家講解了一些多線程的具體運(yùn)用。學(xué)習(xí)多線程應(yīng)該多思考多動(dòng)手,才會(huì)有比較好的效果。地址徒手?jǐn)]框架系列文章地址徒手?jǐn)]框架實(shí)現(xiàn)徒手?jǐn)]框架實(shí)現(xiàn) 原文地址:https://www.xilidou.com/2018/01/22/merge-request/ 在高并發(fā)系統(tǒng)中,我們經(jīng)常遇到這樣的需求:系統(tǒng)產(chǎn)生大量的請(qǐng)求,但是這...

    劉東 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<