1. 程式人生 > >手把手教你如何用Vue實現拖動右側導航選擇聯絡人--V-UI之QuickIndex

手把手教你如何用Vue實現拖動右側導航選擇聯絡人--V-UI之QuickIndex

先上圖


是不是有種濃濃的原生聯絡人應用的趕腳,下面我們來看看如何實現

》先看看如何使用

let data = ["河北省石家莊市", "河北省唐山市", "山西省太原市", "內蒙包頭市",
                    "遼寧省大連市", "遼寧省鞍山市", "遼寧省撫順市", "吉林省吉林市",
                    "黑龍江省齊齊哈爾市", "江蘇省徐州市", "浙江省杭州市", "福建省福州市",
                    "江西省南昌市", "山東省濟南市", "山東省青島市", "山東省淄博市",
                    "河南省鄭州市", "$我是隨意加的","!哈哈哈","@哇哇哇","湖南省長沙市", "貴州省貴陽市", "雲南省昆明市",
                    "甘肅省蘭州市", "新疆烏魯木齊市"]
this.$refs.quickIndexHook.init(data);

從程式碼中我們可以看出,資料為一個數組。然後將陣列以引數的形式呼叫QuickIndex的init方法,在QuickIndex中重要資料有兩部分,一部分是右側A-Z為固定部分,另一部分為列表資料,列表資料為傳入的資料和相應的拼音首字母組成。這裡有個疑問,這裡傳入陣列我們如何獲取陣列中元素對應的拼音首字母呢?這裡推薦看一篇我前期的文章javascript實現根據漢字獲取拼音或者獲取拼音首字母,因為QuickIndex是在獲取到拼音的背景下開發的。

》進入正題

    佈局部分


通過佈局可以看到我們的頁面為分為三部分,列表資料部分、觸控區A-Z、當前觸控位置提示部分。我們通過監聽觸控區的觸控事件,從而實現列表部分相應滾動。下面我們分別看看初始化部分和對應的touch事件

init

             // 根據key 比較大小進行排序
            compare(propertyName) {
                return function (object1, object2) {
                    var value1 = object1[propertyName];
                    var value2 = object2[propertyName];
                    if (value2 < value1) {
                        return 1;
                    } else if (value2 > value1) {
                        return -1;
                    } else {
                        return 0;
                    }
                }
            },
            // 初始化
            init(data) {
                this.index = -1;
                // 一、處理資料
                let tempData = data || [];
                // 排序
                tempData = tempData.sort();
                let preCharacter = "";
                let key = "";
                let temp = [];
                //二、生成key和是否顯示key
                for (let i = 0; i < tempData.length; i++) {
                    // 呼叫pinyin.js裡面的方法獲取首個漢字拼音首字母
                    key = getPinYinFirstCharacter(tempData[i], "", true).substring(0, 1)
                    temp.push({
                        key: key,
                        value: tempData[i],
                        showKey: preCharacter != key
                    })
                    preCharacter = key;
                }
                // 三、按key排序
                temp = temp.sort(this.compare("key"))
                // 四、key還有重複 去掉重複key
                for (let i = temp.length - 1; i >= 1; i--) {
                    if (temp[i].key === temp[i - 1].key) {
                        temp[i].showKey = false;
                    } else {
                        temp[i].showKey = true;
                    }
                }
                this.quickIndexDatas = temp;
                this.refresh();
            }

init程式碼邏輯:由於傳入的資料可能是無序的資料,所以我們需要將傳入的資料進行一次排序,排序完成之後我們就可以得到相對有序的資料了,然後通過遍歷獲取文字拼音首字母,拼接成一個物件放入到一個臨時陣列中。key為A-Z,value為對應的文字,由於存在同一個key多個value,所以我們需要控制顯示同一個key值顯示一次,所以在物件中添加了一個showKey用於區分。通過這一步我們可以得到一個臨時陣列,其中元素為{key:"A",value:"阿拉斯加",showKey:true/false}這樣的形式,由於不同漢字可能開頭的首字母是一樣的,所以我們需要針對key進行排序(compare函式)。到了這一步之後陣列排序的問題已經完成,仍然有一個待解決的問題是showKey可能存在相同的key,showKey兩個或者多個都為true的情況,也就是說列表會顯示兩個或多個key。這裡我們就需要對key進行排查去掉重複的showKey=true的情況,只讓列表資料擁有相同key的物件中只有第一個物件的showKey為true,其他統統為false。

整過初始化過程主要分為四步:

一、傳入的陣列進行首次排序。

二、遍歷獲取首字母並組成一個物件放入臨時陣列

三、根據key排序

四、去掉重複顯示的key

處理觸控部分

touchstart:

 touchstart(e) {
     this.showIndicator = true;
     this.getMoveY(e);
}

touchstart程式碼邏輯相對比較簡單,觸控開始的時候顯示A-Z提示,並設定提示所在的位置

touchmove:

touchmove(e) {
     this.getMoveY(e);
     // 計算當前位置
     this.index = this.currentIndex(moveY);
}

touchmove部分一是獲取噹噹前觸控位置進行相應的換算得到moveY值,設定A-Z提示位置,然後呼叫currentIndex傳入移動的moveY,計算出當前移動到A-Z的中某個元素的索引。

獲取moveY並設定提示位置和獲取索引

getMoveY(e) {
     moveY = e.touches[0].clientY - this.top;
     moveY = moveY <= this.width / 2 ? this.width / 2 : moveY;
     moveY = moveY >= this.height - this.width / 2 ? this.height - this.width / 2 : moveY;
     this.indicator.style.top = this.top + moveY - 28 + 'px';
}
currentIndex(scrollY) {
                let height1;
                let height2;
                for (let i = 0; i < this.keys.length; i++) {
                    height1 = i * this.width;
                    height2 = (i + 1) * this.width;
                    if (i === this.keys.length - 1 || (scrollY >= height1 && scrollY <= height2)) {
                        return i;
                    }
                }
                return 0;
}

touchend:

  touchend() {
        this.showIndicator = false;
        this.index = this.currentIndex(moveY)
        moveY = 0;
}

觸控結束之後,隱藏A-Z提示,獲取當前位置對應的索引值(這一步使用者點選滾動到相應位置),將moveY重置為0。

監聽索引值的變化列表資料進行相應的滾動

watch: {
            // 根據索引值判斷是否滾動
            index(val) {
                if (this.keys[val] === "☆") {
                    let tip = this.$refs.quickIndexHook.getElementsByClassName("quick_index_item_tips")[0]
                    if (tip) {
                        this.scroll.scrollToElement(tip)
                    }
                    return;
                }
                for (let i = 0; i < this.keyLocations.length; i++) {
                    if (this.keys[val] === this.keyLocations[i].key) {
                        let tip = this.$refs.quickIndexHook.getElementsByClassName("quick_index_item_tips")[i]
                        if (tip) {
                            this.scroll.scrollToElement(tip)
                        }
                        break;
                    }
                }
            }
        }

以上部分即為QuickIndex的核心程式碼,部分較為簡單就不一一解釋了,若有不明白的可在評論區提出。

注:滾動部分使用了處理效果比較好的better-scroll庫進行滾動

最後個人通過vue開發了一套前端h5 ui(v-ui),實現了44個類似原生效果的控制元件,皆以vue元件形式提供,有興趣的可以看一看,說不一定就有你需要的。

專案github地址v-ui

預覽地址:v-ui(使用瀏覽器時請調整到手機模式下體驗)

掃碼預覽(推薦)