123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- const throttle = function (func, wait, options) {
- let context
- let args
- let result
- let timeout = null
- // 上次执行时间点
- let previous = 0
- if (!options) options = {}
- // 延迟执行函数
- const later = function () {
- // 若设定了开始边界不执行选项,上次执行时间始终为0
- previous = options.leading === false ? 0 : Date.now()
- timeout = null
- result = func.apply(context, args)
- if (!timeout) context = args = null
- }
- return function () {
- const now = Date.now()
- // 首次执行时,如果设定了开始边界不执行选项,将上次执行时间设定为当前时间。
- if (!previous && options.leading === false) previous = now
- // 延迟执行时间间隔
- const remaining = wait - (now - previous)
- context = this
- args = arguments
- // 延迟时间间隔remaining小于等于0,表示上次执行至此所间隔时间已经超过一个时间窗口
- // remaining大于时间窗口wait,表示客户端系统时间被调整过
- if (remaining <= 0 || remaining > wait) {
- clearTimeout(timeout)
- timeout = null
- previous = now
- result = func.apply(context, args)
- if (!timeout) context = args = null
- // 如果延迟执行不存在,且没有设定结尾边界不执行选项
- } else if (!timeout && options.trailing !== false) {
- timeout = setTimeout(later, remaining)
- }
- return result
- }
- }
- Component({
- options: {
- addGlobalClass: true,
- pureDataPattern: /^_/ // 指定所有 _ 开头的数据字段为纯数据字段
- },
- properties: {
- list: {
- type: Array,
- value: [],
- observer: function (newVal) {
- if (newVal.length === 0) return
- const data = this.data
- const alphabet = data.list.map(item => item.alpha)
- this.setData({
- alphabet,
- current: alphabet[0]
- }, () => {
- this.computedSize()
- })
- }
- },
- vibrated: {
- type: Boolean,
- value: true
- }
- },
- data: {
- windowHeight: 612,
- current: 'A',
- intoView: '',
- touching: false,
- alphabet: [],
- _tops: [],
- _anchorItemH: 0,
- _anchorItemW: 0,
- _anchorTop: 0,
- _listUpperBound: 0
- },
- lifetimes: {
- created() {
- },
- attached() {
- this.__scrollTo = throttle(this._scrollTo, 100, {})
- this.__onScroll = throttle(this._onScroll, 100, {})
- const { windowHeight } = wx.getSystemInfoSync()
- this.setData({ windowHeight })
- }
- },
- methods: {
- handleSelectAlpha(current) {
- this.setData({ current, intoView: current })
- },
- choose(e) {
- const item = e.target.dataset.item
- this.triggerEvent('choose', { item })
- },
- scrollTo(e) {
- this.__scrollTo(e)
- },
- _scrollTo(e) {
- const data = this.data
- const clientY = e.changedTouches[0].clientY
- const index = Math.floor((clientY - data._anchorTop) / data._anchorItemH)
- const current = data.alphabet[index]
- this.setData({ current, intoView: current, touching: true })
- // 振动效果
- if (data.vibrated) wx.vibrateShort()
- },
- computedSize() {
- const data = this.data
- // 计算列表每个区块的高度等信息
- const query = this.createSelectorQuery()
- query.selectAll('.index_list_item').boundingClientRect(rects => {
- const result = rects
- data._tops = result.map(item => item.top)
- }).exec()
- // 计算右侧字母栏小区块的高度等信息
- query.select('.anchor-list').boundingClientRect(rect => {
- data._anchorItemH = rect.height / data.alphabet.length
- data._anchorItemW = rect.width
- data._anchorTop = rect.top
- }).exec()
- // 计算滚动区域的上边界
- query.select('.page-select-index').boundingClientRect(rect => {
- data._listUpperBound = rect.top
- })
- },
- // throttle 的延迟
- removeTouching() {
- setTimeout(() => {
- this.setData({ touching: false })
- }, 150)
- },
- onScroll(e) {
- this.__onScroll(e)
- },
- _onScroll(e) {
- const data = this.data
- const { _tops, alphabet } = data
- const scrollTop = e.detail.scrollTop
- let current = ''
- if (scrollTop < _tops[0]) {
- current = alphabet[0]
- } else {
- for (let i = 0, len = _tops.length; i < len - 1; i++) {
- if (scrollTop >= _tops[i] && scrollTop < _tops[i + 1]) {
- current = alphabet[i]
- }
- }
- }
- if (!current) current = alphabet[alphabet.length - 1]
- this.setData({ current })
- }
- }
- })
|