手把手教你如何用Vue实现拖动右侧导航选择联系人--V-UI之QuickIndex

先上图

手把手教你如何用Vue实现拖动右侧导航选择联系人--V-UI之QuickIndex_第1张图片

是不是有种浓浓的原生联系人应用的赶脚,下面我们来看看如何实现

》先看看如何使用

let data = ["河北省石家庄市", "河北省唐山市", "山西省太原市", "内蒙包头市",
                    "辽宁省大连市", "辽宁省鞍山市", "辽宁省抚顺市", "吉林省吉林市",
                    "黑龙江省齐齐哈尔市", "江苏省徐州市", "浙江省杭州市", "福建省福州市",
                    "江西省南昌市", "山东省济南市", "山东省青岛市", "山东省淄博市",
                    "河南省郑州市", "$我是随意加的","!哈哈哈","@哇哇哇","湖南省长沙市", "贵州省贵阳市", "云南省昆明市",
                    "甘肃省兰州市", "新疆乌鲁木齐市"]
this.$refs.quickIndexHook.init(data);

从代码中我们可以看出,数据为一个数组。然后将数组以参数的形式调用QuickIndex的init方法,在QuickIndex中重要数据有两部分,一部分是右侧A-Z为固定部分,另一部分为列表数据,列表数据为传入的数据和相应的拼音首字母组成。这里有个疑问,这里传入数组我们如何获取数组中元素对应的拼音首字母呢?这里推荐看一篇我前期的文章javascript实现根据汉字获取拼音或者获取拼音首字母,因为QuickIndex是在获取到拼音的背景下开发的。

》进入正题

    布局部分

手把手教你如何用Vue实现拖动右侧导航选择联系人--V-UI之QuickIndex_第2张图片

通过布局可以看到我们的页面为分为三部分,列表数据部分、触控区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(使用浏览器时请调整到手机模式下体验)

扫码预览(推荐)手把手教你如何用Vue实现拖动右侧导航选择联系人--V-UI之QuickIndex_第3张图片


你可能感兴趣的:(前端开发,javascript,vue,v-ui,QuickIndex)