微信小程序实现城市索引选择+搜索

1.实现效果

 2.实现原理

scroll-view:可滚动视图区域。使用竖向滚动时,需要给scroll-view一个固定高度,通过 WXSS 设置 height。组件属性的长度单位默认为px,2.4.0起支持传入单位(rpx/px)。

scroll-into-view:值应为某子元素id(id不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素

1.为列表中的字母索引添加相应id,当触摸右侧固定侧边栏时候,动态设置当前id值,实现锚点定位。
2.搜索城市时,隐藏其他数据,根据搜索值去匹配(indexOf)去匹配关键字,将结果push到一个新的数组中,展示该数组数据。
3.catchtouchstart,catchtouchmove,catchtouchend,catchtouchcancel实现触摸滑动一系列过程。


 

1. 当触摸开始,移动时,拿到pageY,距离左上角的高度。
2. 当前选中位置高度Height=pageY-侧边栏本身距离左上角高度(res.windowWidth / 750 * 180     (rpx,该高度为top:180rpx))
3. 当前选中索引位置为Index=Math.floor(Height/(每一项字母的高度))
4. 每一项字母的高度=res.windowHeight- res.windowWidth / 750 * 300(300为侧边栏页面空余高度)/总共字母数

 3.主要代码

<view class="head {{search&&'r_head'}}">
  <!-- 搜索框 -->
  <view class="flex-row">
    <view class="head_input">
      <image src="/img/search_icon.png" class="search_icon"></image>
      <input type="text" placeholder="搜索" placeholder-class="place_holder" bindinput="getValue" value="{{search}}"></input>
    </view>
    <view class="sha_icon" catchtap="clear_input">取消</view>
  </view>
  <view class="flex-row head_curr" wx:if="{{!search}}">
    <image src="/img/add_icon.png" class="h_c_icon" />
    <view>当前定位城市:{{current_city}}</view>
  </view>
</view>
<scroll-view wx:if="{{!search}}" scroll-y="true" class="sy_container" scroll-into-view="{{scrollViewId}}">
  <view class="hot_city">
    <view class="title">热门城市</view>
    <view class="flex-row flex-wrap box">
      <block wx:for="{{hot_city}}" wx:key="hot">
        <view class="name" hover-class="sel_city" hover-stay-time="150">{{item.name}}</view>
      </block>
    </view>
  </view>
  <view class="all_city">
    <view wx:for="{{city_list}}" wx:key="city_list" wx:if="{{item.data.length>0}}">
      <view class="letter_name" id="{{item.letter}}">{{item.letter}}</view>
      <view class="city">
        <block wx:for="{{item.data}}" wx:key="data" wx:for-index="index0" wx:for-item="item0">
          <view class="name flex-row" hover-class="city_hover" hover-stay-time='150'>{{item0.cityName}}</view>
        </block>
      </view>
    </view>
  </view>
</scroll-view>
<!-- 侧边选择索引 -->
<view wx:if="{{!search}}">
  <view class="fixed_bar" style="height: {{barHeight}}px;" catchtouchstart="touchStart" catchtouchmove="touchMove" catchtouchend="touchEnd" catchtouchcancel="touchCancel">
    <view wx:for="{{city_list}}" wx:key="index" style="height: {{barHeight/22}}px;">
      <view class="bar_item flex-column j_c {{curr==index&&'bar_item_active'}}" style="width: {{barHeight/22*0.75}}px;height: {{barHeight/22*0.75}}px;">{{item.letter}}</view>
    </view>
  </view>
  <view wx:if="{{showLetter &&city_list[curr].letter}}" class="fixed_letter">{{city_list[curr].letter}}</view>
</view>
<view wx:if="{{search}}" class="result_list">
  <view wx:if="{{result.length>0}}">
    <block wx:for="{{result}}" wx:key="result">
      <view class="r_item" hover-stay-time='150' hover-class="r_item_hover">{{item.name}}</view>
    </block>
  </view>
  <view wx:else class="flex-column no_data">
    <image src="https://i.postimg.cc/7P00ckMG/image.png" />
    <view>请输入正确的城市名称呢</view>
  </view>
</view>
/* pages/jsCase/citySel/index.wxss */
page {
  height: 100%;
  background: #f2f5f7;
}

.head {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 170rpx;
  box-sizing: border-box;
  padding: 3rpx 20rpx 0;
  background: #fff;
  z-index: 9999;
}

.r_head {
  height: 90rpx;
}

.head_input {
  position: relative;
  flex: 1;
}

.search_icon {
  position: absolute;
  top: 50%;
  left: 0;
  margin-top: -15rpx;
  width: 28rpx;
  height: 30rpx;
  padding-left: 23rpx;
}

.head input {
  height: 60rpx;
  padding-left: 75rpx;
  font-size: 28rpx;
  border-radius: 30rpx;
  background: #f2f5f7;
}

.place_holder {
  font-size: 28rpx;
  color: #999999;
}

.sha_icon {
  margin-left: 18rpx;
  font-size: 28rpx;
  color: #333333;
}

.head_curr {
  height: 100rpx;
  color: #333;
  font-size: 28rpx;
  padding-top: 20rpx;
  box-sizing: border-box;
}

.h_c_icon {
  flex-shrink: 0;
  margin-right: 15rpx;
  width: 40rpx;
  height: 40rpx;
}

.sy_container {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  padding-top: 170rpx;
}

.hot_city .title {
  padding: 10rpx 30rpx;
  color: #999;
  font-size: 26rpx;
}

.hot_city .box {
  background-color: #fff;
  padding: 5rpx 30rpx 15rpx 40rpx;
  box-sizing: border-box;
}

.hot_city .box .name {
  vertical-align: top;
  display: inline-block;
  min-width: 140rpx;
  line-height: 56rpx;
  height: 56rpx;
  border-radius: 28rpx;
  font-size: 28rpx;
  color: #333;
  text-align: center;
  padding: 0 20rpx;
  box-sizing: border-box;
  margin-top: 10rpx;
  margin-right: 20rpx;
  position: relative;
}

.hot_city .box .name::after {
  content: '';
  position: absolute;
  width: 200%;
  height: 200%;
  -webkit-transform-origin: 0 0;
  transform-origin: 0 0;
  -webkit-transform: scale(0.5, 0.5);
  transform: scale(0.5, 0.5);
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  left: 0;
  top: 0;
  border-radius: 56rpx;
  border: 1rpx solid rgb(235, 225, 225);
}

.sel_city {
  color: #fff !important;
  background: pink;
}

.all_city .letter_name {
  height: 48rpx;
  font-size: 24rpx;
  color: #999;
  background: #f2f5f7;
  padding: 0 30rpx;
  line-height: 48rpx;
}

.all_city .city {
  background-color: #fff;
}

.all_city .city .name {
  width: 100%;
  padding: 30rpx;
  font-size: 28rpx;
  color: #333;
  position: relative;
  overflow: hidden;
}


.all_city .city .name::after {
  content: '';
  position: absolute;
  border-bottom: 1rpx solid #eaeef1;
  -webkit-transform: scaleY(0.5);
  transform: scaleY(0.5);
  bottom: 0;
  right: 0;
  left: 30rpx;
}

.city_hover {
  background-color: #eee !important;
}

.fixed_bar {
  position: fixed;
  z-index: 999;
  top: 180rpx;
  right: 0px;
  padding-right: 10rpx;
  width: 50rpx;
  font-size: 22rpx;
  text-align: center;
}

.bar_item {
  background-color: rgb(233, 228, 220);
  border-radius: 50%;
}

@media screen and (max-width: 320px) {
  .fixed_bar {
    font-size: 20rpx;
  }
}

.bar_item_active {
  background-color: #fff;
  box-shadow: 5rpx 5rpx 5rpx #f7c3ee;
}

.fixed_letter {
  position: absolute;
  z-index: 20;
  width: 160rpx;
  height: 160rpx;
  left: 50%;
  top: 50%;
  margin-left: -80rpx;
  margin-top: -80rpx;
  border-radius: 80rpx;
  text-align: center;
  line-height: 160rpx;
  font-size: 70rpx;
  color: #fff;
  background-color: rgba(0, 0, 0, 0.5);
  box-shadow: 5rpx 5rpx 5rpx #f7c3ee;
}

/* 搜索结果 */
.result_list {
  padding-top: 90rpx;
  background: #fff;
  width: 100%;
}

.r_item {
  width: 100%;
  position: relative;
  padding: 30rpx 0 30rpx 30rpx;
  font-size: 28rpx;
  color: #333;
  box-sizing: border-box;
}

.r_item::after {
  content: '';
  position: absolute;
  border-bottom: 1rpx solid #eaeef1;
  -webkit-transform: scaleY(0.5);
  transform: scaleY(0.5);
  bottom: 0;
  right: 0;
  left: 30rpx;
}

.r_item_hover {
  background-color: #eee !important;
}

.no_data {
  height: 500rpx;
  justify-content: center;
  font-size: 27rpx;
  color: #999;
}

.no_data image {
  width: 250rpx;
  height: 162rpx;
  margin-bottom: 30rpx;
}
const { cityData } = require('./city.js')
Page({
  data: {
    current_city: "",
    search: "",
    hot_city: [
      {
        name: "北京"
      }, {
        name: "上海"
      }, {
        name: "广州"
      }, {
        name: "长沙"
      }, {
        name: "张家口"
      }, {
        name: "杭州"
      }, {
        name: "西安"
      }, {
        name: "南京"
      }, {
        name: "苏州"
      },

    ],
    city_list: [],
    barHeight: 0,
    curr: -1,
    scrollViewId: "",
    barTop: 0,
    showLetter: false,
    result: [],//搜索结果
  },
  onLoad: function (options) {
    this.setData({
      current_city: options.currentCity || "南京",
      city_list: cityData
    })
    wx.getSystemInfo({
      success: (res) => {
        let winHeight = res.windowHeight
        let barHeight = winHeight - res.windowWidth / 750 * 300;
        this.setData({
          barHeight: barHeight,
          barTop: res.windowWidth / 750 * 180,
        })
      }
    })
  },
  /**
   * 获取value值
   * @param {*} e 
   */
  getValue(e) {
    this.setData({
      search: e.detail.value
    }, () => {
      this.search(e.detail.value)
    })
  },
  /**
   * 搜索成功
   */
  search(e) {
    let result = [], { city_list } = this.data;
    city_list.forEach((item1) => {
      item1.data.forEach((item2) => {
        if (item2.keyword.indexOf(e.toLocaleUpperCase()) !== -1) {
          result.push({ name: item2.cityName })
        }
      })
    })
    this.setData({
      result,
    })
  },
  /**
   * 清空验证码
   */
  clear_input() {
    this.setData({
      search: ""
    })
  },
  ......
})

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值