城市选择,城市联动

涉及到一些TARO,但是不多,类似微信小程序。 

方法一:

前置条件:

        1、每个字母下的城市列表使用一个容器包着,容器带有id,方便后续锚点跳转。

        2、navigatorBar里的字母高定死,知道navigatorBa总高度,方便知道滑动到哪个字母。

方法:

        锚点跳转

        监听navigatorBar的滑动距离,计算出所滑动的点是在哪个字母的范围(比如我知道一共有10个字母,一个字母定高10px,我滑动了30px,30px在第三个字母的范围内,所以我就知道了我滑到了第三个字母。)取出这个字母,使用scroll View的锚点跳转。

ScrollView代码:主要是列表使用容器,容器id为字母

// ScrollView左边城市列表
<ScrollView
scrollY
className="scroll-view"
scrollTop={scrollToY}
style={{ height: `${isH5 ? `${phoneHeight - 100}px` : `${phoneHeight - headTop - 100}px`}` }}
>
{
  Object.keys(cityList).length
    ? <>
      {
        Object.keys(cityList).map((letter) => <View 
        id={letter}    // 使用字母作为id,方便锚点跳转
        key={letter} 
        className="letter-container"
        >
          <View key={letter} className="city-list-letter">{letter}</View>
          {
            cityList[letter].map((item) => <View
              className="city-list-name"
              onClick={selectCity}
              data-city={item}
              key={item.cityCode}
            >{item.cityName}</View>)
          }
        </View>)
      }
    </>
    : <SelectCitySkeleton />
}
</ScrollView>

navigation-bar代码:主要是监听滑动距离、以及使用data-key,方便后续取字母 

//  右边navigation-bar
{
    Object.keys(cityList).length
      ? <>
        <View 
            className="navigation-bar" 
            onTouchMove={handleTouchMove}  //  监听滑动距离
            style={{ top: `${isH5 ? 0 : `${headTop + 100}px`}` }}
        >
          <View className="bar-item" data-key="hotCity" onClick={clickBar}>#</View>
          {
            Object.keys(cityList).map((item, index) => <View 
            key={index} 
            data-key={item} 
            onClick={clickBar} 
            className="bar-item"
            >
                {item}
            </View>)
          }
        </View> </>
      : skeletonLetter()     // 骨架屏
}

处理函数代码:

// 滑动bar
  const handleTouchMove = (e) => {
    const barHeight = (40 * (Object.keys(cityList).length + 1)) / 2 // bar的高度
    const touchClientY = e.changedTouches[0].clientY // 自顶滑动距离
    const touchDistance = touchClientY - headTop - 100 // bar内滑动距离
    const letterArr = Object.keys(cityList)     // 字母列表
    let currentLetter = 'hotCity' // 默认热门城市
    let toastText = '热门城市'
    let touchBarItemIndex = -1 // 默认#号

    if (touchDistance >= 0) {
      touchBarItemIndex = Math.floor(touchDistance / 20) - 1
    }
    // 滑动距离超过bar的高度
    if (touchDistance >= barHeight) {
      touchBarItemIndex = letterArr.length - 1 // 定位到最后一位
    }

    //  锚点跳转
    if (touchBarItemIndex === -1) {
      setLetter('hotCity')
      scrollIntoView('hot-city') // 锚点跳转
    } else {
      const letter = letterArr[touchBarItemIndex]
      setLetter(letter)
      toastText = letter
      scrollIntoView(letter) // 锚点跳转
    }

    if (letter !== currentLetter) {
      Taro.vibrateShort() //  短暂震动
      Taro.showToast({
        title: `${toastText}`,
        icon: 'none',
        duration: 500,
      })
    }
  }

思想二:

前置条件:

        1、城市列表中的每个城市Item也需要定死高,为方便使用srollView的setScrollToY功能跳转,

        2、拿到城市列表数据处理时需计算好高度以及需要滑动的高度。(后面讲处理的方法

方法:

        和前面一样,监听navigatorBar的滑动距离,计算出所滑动的点是在哪个字母的范围(比如我知道一共有10个字母,一个字母定高10px,我滑动了30px,30px在第三个字母的范围内,所以我就知道了我滑到了第三个字母。)计算好跳哪个字母后,直接拿这个字母里的数据处理好的里的Y。

处理数据

        数据处理大概就是,

        高度:知道一个字母里有多少个城市,然后乘一个城市Item的高,算到这个字母里所有城市的总高。

        需要滑动的距离一个字母需要滚动的距离就是它前几个字母的高相加。

        1、首先需要定义一个最外层变量,用于存储字母的累加置,即下个字母需要滚动的高度

 let lastItemScrollHeight = 0 

        2、计算一个字母以及它下面城市的总高度 

/*一个字母容器的高**/
formatList[item].height = Object.keys(formatList[item]).length * 42 + 30 // 字母容器高度

           比如B字母下有10个城市,每个城市高为40px,字母高30px那他的高就是 10*40+30px 

 计算这个字母需要滚动的距离

        3、由于我们已经定义了一个外层变量,在每处理完一个字母容器的高度后,就把高度累加到这个变量上,作为下一个字母需要滚动距离。

/*这个字母需要滚动的距离**/
 Object.keys(formatList).forEach((item) => {
    formatList[item].scrollHeight = lastItemScrollHeight
    lastItemScrollHeight += formatList[item].height // 距离顶部高度
  })

          假如我们已经算到A和B字母的高度,现在需要知道我滑动带C字母需要滑动多少距离,那就是需要滑动A+B字母高度加起来的高度 

数据处理后长这样。

 最后的处理函数:

// 滑动bar
  const handleTouchMove = (e) => {
    const barHeight = (40 * (Object.keys(cityList).length + 1)) / 2 // bar的高度
    const touchClientY = e.changedTouches[0].clientY // 自顶滑动距离
    const touchDistance = touchClientY - headTop - 100 // bar内滑动距离
    const letterArr = Object.keys(cityList)
    let currentY = 0 // 默认热门城市
    let toastText = '热门城市'
    let touchBarItemIndex = -1 // 默认#号

    if (touchDistance >= 0) {
      touchBarItemIndex = Math.floor(touchDistance / 20) - 1
    }
    // 滑动距离超过bar的高度
    if (touchDistance >= barHeight) {
      touchBarItemIndex = letterArr.length - 1 // 定位到最后一位
    }

    //  计算需要scroll的距离
    if (touchBarItemIndex === -1) {
      currentY = 0
    } else {
      const letter = letterArr[touchBarItemIndex]
      toastText = letter
      currentY = cityList[letter].scrollHeight + 127
    }

    if (scrollToY !== currentY) {
      setScrollToY(currentY)
      Taro.vibrateShort()

      Taro.showToast({
        title: `${toastText}`,
        icon: 'none',
        duration: 500,
      })
    }
  }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值