微信和通訊錄經常(chang)看到這(zhe)種,那么在小程序(xu)如何實現呢(等(deng)下我(wo)們需要用到小程序(xu)的一個(ge)(ge)(ge)官方組件),這(zhe)個(ge)(ge)(ge)功能可(ke)以拆分兩塊,一個(ge)(ge)(ge)是滾動(dong)區域(yu),一個(ge)(ge)(ge)是滑動(dong)定位區域(yu)。
小程序里面實現滾動(dong)到指定位置,可以用 scroll-view 組件. (點擊我即可查(cha)看小程序文檔)
<scroll-view class="goup_list" scroll-with-animation="true" scroll-y="true" style="height: 300rpx;" scroll-into-view="{{toView}}">
<具(ju)體業務界面代碼(ma) />
</scroll-view>
復制代碼
最后面是我剛剛錄gif的代碼。可以看到 scroll-view 組件,有一個屬性 scroll-into-view ,這個屬性可以實現轉跳(tiao)到指定位(wei)置。值是(shi)id,也就(jiu)是(shi)Gif看到的 B、C、D的ID。
(最后會(hui)有完整代碼)
滑動我們會想到 touchmove 事件(jian),我們需(xu)要依靠這個(ge)判斷滑動(dong)到了(le)哪個(ge)索引(字母)。
但是(shi)滑動里(li)面沒(mei)有直接(jie)告(gao)訴你,是(shi)哪個組件,所(suo)以我們需要根據(ju)現有的(de)信息(xi)進行(xing)利用,這里(li)用的(de)是(shi)y,x的(de)信息(xi)。
拿到x,y之后(hou)的邏輯如(ru)下
用文字不好(hao)描(miao)述(shu)清楚,看下面圖,可以這樣求偏差值,然后除(chu)以每項(xiang)的高(gao)度,就拿到了滑動到了第幾項(xiang)。 這里(li)又(you)涉及一個問題(ti)就是,怎么求單個項(xiang)的高(gao)度。 height / 個數(shu)。
var y = e.touches[0].pageY;
var itemLen = this.data.list.length
var height = letterDomRes.height
var top = letterDomRes.top
// 滑動的偏移量(偏差值)
var offsetTop = (height + top - y)
var itemHeight = height / itemLen
var index = itemLen - ((offsetTop / itemHeight)|0) - 1
if(index < 0 || index >= itemLen){
return
}
復制代碼
還有就是上面數據(ju)從哪里來(lai),也就是小程序如何(he)拿下圖中的top值和(he)height。
//創建節點選擇器
var query = wx.createSelectorQuery()
query.select('.letter-index').boundingClientRect()
query.exec(function (res) {
letterDomRes = res[0]
console.log(letterDomRes);
})
復制代碼
letterDomRes.height letterDomRes.top 就(jiu)是我(wo)們需要的數據(ju)了。
到這里就都完成了(le)。然后(hou)加一個優化,超(chao)出滑(hua)動范圍就return,上面代碼(ma)也(ye)有了(le),然后(hou)設(she)置的(de)時候判(pan)斷(duan)是否在滑(hua)動期間,是的(de)話過(guo)濾相同的(de)設(she)置。
// pages/word/strange.js
var letterDomRes = {}
var moveing_word = ''
Page({
/**
* 頁面的初始數據
*/
data: {
toView: '',
list: [
{
word: 'B',
children: [
{word: 'Ban', translation: 'vt. 禁(jin)止(zhi),查(cha)禁(jin);n. 禁(jin)止(zhi),禁(jin)令'},
{word: 'Ban', translation: 'vt. 禁(jin)止,查禁(jin);n. 禁(jin)止,禁(jin)令'},
{word: 'Ban', translation: 'vt. 禁(jin)(jin)(jin)止,查禁(jin)(jin)(jin);n. 禁(jin)(jin)(jin)止,禁(jin)(jin)(jin)令'},
]
},
{
word: 'C',
children: [
{word: 'Ban', translation: 'vt. 禁(jin)(jin)止,查禁(jin)(jin);n. 禁(jin)(jin)止,禁(jin)(jin)令'},
{word: 'Ban', translation: 'vt. 禁(jin)止,查禁(jin);n. 禁(jin)止,禁(jin)令'},
{word: 'Ban', translation: 'vt. 禁(jin)(jin)止(zhi),查禁(jin)(jin);n. 禁(jin)(jin)止(zhi),禁(jin)(jin)令'},
]
},
{
word: 'D',
children: [
{word: 'Ban', translation: 'vt. 禁止,查禁;n. 禁止,禁令'},
{word: 'Ban', translation: 'vt. 禁(jin)(jin)止(zhi),查(cha)禁(jin)(jin);n. 禁(jin)(jin)止(zhi),禁(jin)(jin)令'},
{word: 'Ban', translation: 'vt. 禁(jin)止(zhi),查禁(jin);n. 禁(jin)止(zhi),禁(jin)令'},
]
},
]
},
// ---- methods
letterTap(e){
var id = e.target.id
// console.log(id)
this.setListSite(id)
},
letterMove(e){
var y = e.touches[0].pageY;
var itemLen = this.data.list.length
var height = letterDomRes.height
var top = letterDomRes.top
// 滑動的偏移量(偏差值)
var offsetTop = (height + top - y)
var itemHeight = height / itemLen
var index = itemLen - ((offsetTop / itemHeight)|0) - 1
if(index < 0 || index >= itemLen){
return
}
var letter = this.data.list[index].word
// console.log(index, letter)
// [優化] 過(guo)濾(lv)相同的(de)
if(moveing_word == letter){
return
}
moveing_word = letter
this.setListSite('word_' + letter)
// console.log(height / this.data.list.length)
// / this.data.list.length
// console.log(letterDomRes.top)
},
letterEnd(e){
// 重(zhong)置(zhi)
moveing_word = ''
},
/**
* 設置(zhi)滾動位置(zhi)
* @param {String} id 前綴(zhui) + 字(zi)母
*/
setListSite(id){
wx.showToast({
title: id.split('_')[1],
icon: 'none',
})
this.setData({
toView: id,
duration: 500,
})
},
/**
* 生(sheng)命周期函(han)數--監聽(ting)頁(ye)面加載
*/
onLoad: function (options) {
},
/**
* 生命(ming)周期函(han)數--監(jian)聽頁(ye)面初次渲(xuan)染(ran)完成
*/
onReady: function () {
//onshow中(zhong)獲取索引條高度
var query = wx.createSelectorQuery();//創建節點選擇器(qi)
query.select('.letter-index').boundingClientRect()
query.exec(function (res) {
//res就是 所有標簽為mjltest的(de)元(yuan)素的(de)信息 的(de)數組
letterDomRes = res[0]
console.log(letterDomRes);
//取高度
console.log("height : "+res[0].height);
})
},
/**
* 生命周期(qi)函數--監(jian)聽(ting)頁面顯示
*/
onShow: function () {
},
/**
* 生(sheng)命(ming)周期函數--監聽(ting)頁面隱藏(zang)
*/
onHide: function () {
},
/**
* 生命周期(qi)函(han)數--監聽(ting)頁面卸(xie)載
*/
onUnload: function () {
},
/**
* 頁面相關(guan)事件(jian)處理函(han)數--監聽用戶下拉動作
*/
onPullDownRefresh: function () {
},
/**
* 頁面(mian)上拉觸底(di)事件(jian)的處理函(han)數(shu)
*/
onReachBottom: function () {
},
})
復制代碼
<!--pages/word/strange.wxml-->
<view class="container">
<scroll-view class="goup_list" scroll-with-animation="true" scroll-y="true" style="height: 300rpx;" scroll-into-view="{{toView}}">
<view class="">
<view class="group_item" wx:for="{{list}}" wx:key="{{index}}">
<view class="group">
<view class="title" id="word_{{item.word}}">{{item.word}}</view>
<view class="word_list">
<view class="word_list_item" wx:for="{{item.children}}" wx:key="{{index}}">
<view class="e">
<view>{{item.word}}</view>
<view class="">{{item.translation}}</view>
</view>
<image mode="widthFix" src="/image/right.png" class="right-image" />
</view>
</view>
</view>
</view>
</view>
</scroll-view>
<view class="letter-index" bind:touchmove="letterMove" bindtap="letterTap" bind:touchend="letterEnd">
<view class="item" id="word_{{item.word}}" wx:for="{{list}}" wx:key="index">{{item.word}}</view>
</view>
</view>
復制代碼