微信小程序实现按首字母检索城市列表

时间:2024-01-23 15:13:39

不说废话,上效果图

 

因为我有多处要用到,所以我这里是写成自定义组件的,你也可以直接改成在page页面编写:

布局左边一个scroll-view,显示城市列表,右边一个view显示字母列表,城市列表这边有首字母显示,给这个添加这个字母的ID,然后给右边的26个字母添加点击事件,点击的时候获取到点击的是哪个字母,给scroll-view的scroll-into-view赋值相应的字母,它左边就可以跳到相应的地方,再给scroll-view 加一个scroll-with-animation,让它跳转的时候有动画效果;

 

首先,我们来看看wxml

<view class=\'city_box\' style=\'{{styles}}\'>
      <view class=\'city_left\'>
          <scroll-view scroll-y style=\'width:100%;height:100%;\' scroll-with-animation scroll-into-view=\'{{cityListId}}\'>
              <view class=\'city_locate\' data-types=\'locate\' catchtap=\'cityTap\'>
                  <text class=\'city_locate_title\'>自动定位</text>
                  <text class=\'city_locate_text\' style=\'{{!locateCity&&"color:#33b9ff;"}}\'>{{locateCity||\'点击定位\'}}</text>
              </view>
              <view class=\'national\' data-types=\'national\' catchtap=\'cityTap\'>全国</view>
              <view class=\'new_city\'>
                  <view class=\'new_city_title\'>热门城市</view>
                  <view class=\'new_city_box\'>
                      <text class=\'new_city_text\' wx:for=\'{{newcity}}\' wx:key=\'this\' data-types=\'new\' catchtap=\'cityTap\' data-val=\'{{item}}\'>{{item}}</text>
                  </view>
              </view>
              <view class=\'city_list_box\'>
                <block wx:for=\'{{citylist}}\' wx:key=\'this\' wx:for-item=\'letterItem\' wx:for-index=\'letterIndex\'>
                  <view class=\'city_first_letter\' id=\'{{letterItem.letter}}\'>{{letterItem.letter}}</view>
                  <text class=\'city_name\' wx:for=\'{{letterItem.data}}\' wx:key=\'this\' data-types=\'list\' catchtap=\'cityTap\' data-index=\'{{index}}\' data-val=\'{{item}}\'>{{item.cityName}}</text>
                </block>
              </view>
          </scroll-view>
      </view>
      <view class=\'city_right\'>
          <text class=\'letter_item\' wx:for=\'{{letter}}\' wx:key=\'this\' catchtap=\'letterTap\' data-item=\'{{item}}\'>{{item}}</text>
      </view>
  </view>

然后wxss

.city_box{
  height:100%;
  background: #fff;
  display: flex;
}
.city_left{
  flex: 1;
}
.city_right{
  width: 60rpx;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
}
.letter_item{
  flex: 1;
  display: block;
  font-size: 24rpx;
  color: #33B9FF;
  text-align: center;
}
.city_locate,.national{
  height: 80rpx;
  line-height: 80rpx;
  border-bottom: 1px solid #efefef;
  font-size: 28rpx;
  color: #333;
  padding-left: 25rpx;
}
.city_locate_title{
  color: #999;
  margin-right: 20rpx;
}
.new_city{
  background: #efefef;
  font-size: 28rpx;
}
.new_city_title{
  line-height: 50rpx;
  color: #999;
  padding-left: 25rpx;
  margin-bottom: 20rpx;
}
.new_city_box{
  display: flex;
  flex-wrap: wrap;
}
.new_city_text{
  width: 200rpx;
  text-align: center;
  line-height: 70rpx;
  background: #fff;
  border-radius: 35rpx;
  margin:0 0 22rpx 22rpx;
}
.city_first_letter{
  line-height: 40rpx;
  height: 40rpx;
  padding-left: 25rpx;
  font-size: 28rpx;
  background: #eee;
  color: #999;
}
.city_name{
  display: block;
  line-height: 80rpx;
  height: 80rpx;
  border-bottom: 1px solid #efefef;
  font-size: 28rpx;
  color: #333;
  padding-left: 25rpx;
}

然后是json文件,因为我这里是组件,所以是下面这样,如果你不是的组件,那么不要这句

{
"component": true
}

 

最后JS,因为我这里是写的一个组件,所以是Component而不是Page

import qqmap from \'../../utils/map.js\';
Component({
  properties: {
    styles:{//这个是可以自定义最外层的view的样式
      type:String,
      value:\'\',
      observer: function (newval, oldval) {
        // 监听改变
        console.log(newval, oldval);
      }
    }
  },
  data: {
    //下面是字母排序
    letter: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"],
    cityListId: \'\',
    //下面是城市列表信息,这里只是模拟数据
    citylist: [{ "letter": "A", "data": [{ "id": "v7", "cityName": "安徽" }] }, { "letter": "B", "data": [{ "id": "v10", "cityName": "巴中" }, { "id": "v4", "cityName": "包头" }, { "id": "v1", "cityName": "北京" }] }, { "letter": "C", "data": [{ "id": "v15", "cityName": "成都" }] }, { "letter": "D", "data": [{ "id": "v21", "cityName": "稻城" }] }, { "letter": "G", "data": [{ "id": "v17", "cityName": "广州" }, { "id": "v29", "cityName": "桂林" }] }, { "letter": "H", "data": [{ "id": "v9", "cityName": "海南" }, { "id": "v3", "cityName": "呼和浩特" }] }, { "letter": "L", "data": [{ "id": "v24", "cityName": "洛阳" }, { "id": "v20", "cityName": "拉萨" }, { "id": "v14", "cityName": "丽江" }] }, { "letter": "M", "data": [{ "id": "v13", "cityName": "眉山" }] }, { "letter": "N", "data": [{ "id": "v27", "cityName": "南京" }] }, { "letter": "S", "data": [{ "id": "v18", "cityName": "三亚" }, { "id": "v2", "cityName": "上海" }] }, { "letter": "T", "data": [{ "id": "v5", "cityName": "天津" }] }, { "letter": "W", "data": [{ "id": "v12", "cityName": "乌鲁木齐" }, { "id": "v25", "cityName": "武汉" }] }, { "letter": "X", "data": [{ "id": "v23", "cityName": "西安" }, { "id": "v28", "cityName": "香港" }, { "id": "v19", "cityName": "厦门" }] }, { "letter": "Z", "data": [{ "id": "v8", "cityName": "张家口" }] }],
    //下面是热门城市数据,模拟数据
    newcity: [\'北京\', \'上海\', \'广州\', \'深圳\', \'成都\', \'杭州\'],
    // citySel: \'全国\',
    locateCity: \'\'
  },
  methods: {
    //点击城市
    cityTap(e) {
      const val = e.currentTarget.dataset.val || \'\',
        types = e.currentTarget.dataset.types || \'\',
        Index = e.currentTarget.dataset.index || \'\',
        that=this;
      let city = this.data.citySel;
      switch (types) {
        case \'locate\':
          //定位内容
          city = this.data.locateCity;
          break;
        case \'national\':
          //全国
          city = \'全国\';
          break;
        case \'new\':
          //热门城市
          city = val;
          break;
        case \'list\':
          //城市列表
          city = val.cityName;
          break;
      }
      if(city){
        wx.setStorage({
          key: \'city\',
          data: city
        })
    //点击后给父组件可以通过bindcitytap事件,获取到cityname的值,这是子组件给父组件传值和触发事件的方法
this.triggerEvent(\'citytap\', { cityname: city }); }else{ console.log(\'还没有\'); this.getLocate(); } }, //点击城市字母 letterTap(e) { const Item = e.currentTarget.dataset.item; this.setData({ cityListId: Item }); console.log(this.data.cityListId); }, //调用定位 getLocate(){ let that=this; new qqmap().getLocateInfo().then(function (val) {//这个方法在另一个文件里,下面有贴出代码 console.log(val); if (val.indexOf(\'市\') !== -1) {//这里是去掉“市”这个字 console.log(val.indexOf(\'市\') - 1); val = val.slice(0, val.indexOf(\'市\')); console.log(val); } that.setData({ locateCity: val }); //把获取的定位和获取的时间放到本地存储 wx.setStorageSync(\'locatecity\', { city: val, time: new Date().getTime() }); }); } }, ready(){ console.log(getApp()); let that = this, cityOrTime = wx.getStorageSync(\'locatecity\')||{}, time = new Date().getTime(), city=\'\'; if (!cityOrTime.time||(time - cityOrTime.time > 1800000)){//每隔30分钟请求一次定位 this.getLocate(); }else{//如果未满30分钟,那么直接从本地缓存里取值 that.setData({ locateCity: cityOrTime.city }) } } })

 

然后是引用的map.js,这里需要用到腾讯地图的微信小程序sdk获取当前经纬度的详情信息,然后取到当前城市,这是腾讯地图微信小程序JavaScript SDK,可以去查看教程,这里用到的是地址解析功能;

const wxqqmap = require(\'../libs/qqmap-wx-jssdk.min.js\'),
      qqwxmap = new wxqqmap({
        key: \'GTDBZ-WFSRX-JOT4W-7WYBD-Z2CTO-7QBEM\' // 必填,这里最好填自己申请的的
      }); 
import util from \'./util.js\';
const qq=\'sdfsdf\';
export default class qqmap{//获取定位信息
  getLocateInfo(){
    let that=this;
    return new Promise(function (resolve, reject) {
            that.location().then(function(val){
              //如果通过授权,那么直接使用腾讯的微信小程序sdk获取当前定位城市
              qqwxmap.reverseGeocoder({
                location: {
                  latitude: val.latitude,
                  longitude: val.longitude
                },
                success: function (res) {
                  console.log(res.result.address_component.city);
                  resolve(res.result.address_component.city);//返回城市
                },
                fail: function (res) {
                  reject(res);
                },
                complete: function (res) {
                  console.log(res);
                }
              });
                
              },function(error) {
                //如果用户拒绝了授权,那么这里会提醒他,去授权后再定位
                console.log(\'shibai\');
                wx.showModal({
                  title: \'\',
                  content: \'自动定位需要授权地理定位选项\',
                  confirmText: \'去授权\',
                  success(res) {
                    if (res.confirm) {
                      wx.openSetting({
                        success(res) {
                          console.log(res);
                          that.getLocateInfo();
                        }
                      })
                    }
                  }
                })

              })
          
    })
  }
  
//定位,获取当前经纬度
  location(){   
    return new Promise(function (resolve, reject) {  
      wx.getLocation({
        altitude: true,
        success: function (res) {
          resolve(res);
        },fail(res){
          reject(res);
        }
      })
    });
    
  }  

  
}

然后在引用这个组件的时候,在引用的页面的json文件里要添加这一句

{
  "usingComponents":{
    "citylist":"../../component/cityListCom/cityListCom"
  }
}

然后在引用的wxml界面添加组件,styles是设置的组件的变量,我这里是可以改变组件最外层的样式,bindcitytap是上面组件js里的点击城市方法里提到的事件

<citylist styles=\'max-height:100%;\' bindcitytap=\'cityTap\'></citylist>

然后在引用的界面的js里,写个cityTap事件,获取传过来的值

// pages/cityList/cityList.js
Page({
  data: {
    winHeight:0
  },
//监听传值,后面自己做处理了 cityTap(e){ console.log(
\'fasdfsdfsdfds\'); console.log(e); const cityName=e.detail.cityname; wx.navigateBack(); }, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { const win = wx.getSystemInfoSync(); console.log(win); this.setData({ winHeight: win.windowHeight }); } })

这样就可以了。

 

如果不想写成组件的,想直接写在一个页面里面,需要改一下

 

首先wxml里面去掉圈起来的这句

 

 

WXSS里面添加page{height:100%;}

 

JS里面改成这样

import qqmap from \'../../utils/map.js\';//这里的路径看你自己的文件路径
Page({
  data: {
    //下面是字母排序
    letter: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"],
    cityListId: \'\',
    //下面是城市列表信息,这里只是模拟数据
    citylist: [{ "letter": "A", "data": [{ "id": "v7", "cityName": "安徽" }] }, { "letter": "B", "data": [{ "id": "v10", "cityName": "巴中" }, { "id": "v4", "cityName": "包头" }, { "id": "v1", "cityName": "北京" }] }, { "letter": "C", "data": [{ "id": "v15", "cityName": "成都" }] }, { "letter": "D", "data": [{ "id": "v21", "cityName": "稻城" }] }, { "letter": "G", "data": [{ "id": "v17", "cityName": "广州" }, { "id": "v29", "cityName": "桂林" }] }, { "letter": "H", "data": [{ "id": "v9", "cityName": "海南" }, { "id": "v3", "cityName": "呼和浩特" }] }, { "letter": "L", "data": [{ "id": "v24", "cityName": "洛阳" }, { "id": "v20", "cityName": "拉萨" }, { "id": "v14", "cityName": "丽江" }] }, { "letter": "M", "data": [{ "id": "v13", "cityName": "眉山" }] }, { "letter": "N", "data": [{ "id": "v27", "cityName": "南京" }] }, { "letter": "S", "data": [{ "id": "v18", "cityName": "三亚" }, { "id": "v2", "cityName": "上海" }] }, { "letter": "T", "data": [{ "id": "v5", "cityName": "天津" }] }, { "letter": "W", "data": [{ "id": "v12", "cityName": "乌鲁木齐" }, { "id": "v25", "cityName": "武汉" }] }, { "letter": "X", "data": [{ "id": "v23", "cityName": "西安" }, { "id": "v28", "cityName": "香港" }, { "id": "v19", "cityName": "厦门" }] }, { "letter": "Z", "data": [{ "id": "v8", "cityName": "张家口" }] }],
    //下面是热门城市数据,模拟数据
    newcity: [\'北京\', \'上海\', \'广州\', \'深圳\', \'成都\', \'杭州\'],
    // citySel: \'全国\',
    locateCity: \'\'
  },

    //点击城市
    cityTap(e) {
      console.log(e)
      const val = e.currentTarget.dataset.val || \'\',
        types = e.currentTarget.dataset.types || \'\',
        Index = e.currentTarget.dataset.index || \'\',
        that = this;
      let city = this.data.citySel;
      switch (types) {
        case \'locate\':
          //定位内容
          city = this.data.locateCity;
          break;
        case \'national\':
          //全国
          city = \'全国\';
          break;
        case \'new\':
          //热门城市
          city = val;
          break;
        case \'list\':
          //城市列表
          city = val.cityName;
          break;
      }
      if (city) {
        wx.setStorage({
          key: \'city\',
          data: city
        })
            //点击后给父组件可以通过bindcitytap事件,获取到cityname的值,这是子组件给父组件传值和触发事件的方法
        this.triggerEvent(\'citytap\', { cityname: city });
      } else {
        console.log(\'还没有\');
        this.getLocate();
      }

    },
    //点击城市字母
    letterTap(e) {
      const Item = e.currentTarget.dataset.item;
      this.setData({
        cityListId: Item
      });
      console.log("..............."+this.data.cityListId);
    },
    //调用定位
    getLocate() {
      let that = this;
      new qqmap().getLocateInfo().then(function (val) {//这个方法在另一个文件里,下面有贴出代码
        console.log(val);
        if (val.indexOf(\'市\') !== -1) {//这里是去掉“市”这个字
          console.log(val.indexOf(\'市\') - 1);
          val = val.slice(0, val.indexOf(\'市\'));
          console.log(val);
        }
        that.setData({
          locateCity: val
        });
        //把获取的定位和获取的时间放到本地存储
        wx.setStorageSync(\'locatecity\', { city: val, time: new Date().getTime() });
      });
    },

  onShow() {
    console.log(getApp());
    let that = this,
      cityOrTime = wx.getStorageSync(\'locatecity\') || {},
      time = new Date().getTime(),
      city = \'\';
    if (!cityOrTime.time || (time - cityOrTime.time > 1800000)) {//每隔30分钟请求一次定位
      this.getLocate();
    } else {//如果未满30分钟,那么直接从本地缓存里取值
      that.setData({
        locateCity: cityOrTime.city
      })
    }


  }
})

然后运行就可以了

完结

 想了解更多的小程序的知识请添加微信小程序开发交流群:368506119