小程序使用 picker-view 自定义封装省市区三级联动组件

区域的 省市区 json 数据请前往 点击这里获取

效果图

在这里插入图片描述

代码如下

子组件中
  • wxml 中
<view>
    <view bindtap="handleShowCityAreaPicker">{{provice.name}}-{{city.name}}-{{area.name}}</view>
</view>
<view class="city-area-picker-container {{isShow ? 'active' : 'display-none'}}">
    <view class="city-area-picker-title">区域选择器</view>
    <picker-view indicator-style="height: 50px;" style="width: 100%; height: 200px;text-align:center;margin-bottom: 40px;" value="{{currentValue}}" bindpickstart="bindpickstart" bindpickend="bindpickend" bindchange="bindChange">
        <picker-view-column>
            <view wx:for="{{proviceList}}" wx:key="*this" style="line-height: 50px">{{item.name}}</view>
        </picker-view-column>
        <picker-view-column>
            <view wx:for="{{cityList}}" wx:key="*this" style="line-height: 50px">{{item.name}}</view>
        </picker-view-column>
        <picker-view-column>
            <view wx:for="{{areaList}}" wx:key="*this" style="line-height: 50px">{{item.name}}</view>
        </picker-view-column>
    </picker-view>
    <view class="city-area-picker-btn-box">
      <view bindtap="cancel" class="city-area-picker-cancel-btn">取消</view>
      <view bindtap="confirm" class="city-area-picker-confirm-btn">确定</view>
    </view>
</view>
<view class='mask' wx:if="{{isShow}}" bindtap='closeModal'></view>
  • wxss 中
.mask{
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 99999;
  background-color: rgba(0, 0, 0, .5);
}

.city-area-picker-container {
  width: 100%;
  position: absolute;
  bottom: 0; 
  left: 0;
  z-index: 100000;
  padding: 40rpx 60rpx;
  transition: ease .3s;
  transform: translateY(100%);  
  background-color: #fff;
  box-sizing: border-box;
  border-radius: 30rpx 30rpx 0 0;
}
.display-none{
  display: none;
}
.city-area-picker-container.active{
  transform: translateY(0);
  display: block;
}
.city-area-picker-title {
  text-align: center;
}
.city-area-picker-btn-box {
  display: flex;
  font-weight: 600;
  margin-top: 40rpx;
  color: var(--themeColor);
  justify-content: space-around;
}
.city-area-picker-btn-box .city-area-picker-cancel-btn, 
.city-area-picker-btn-box .city-area-picker-confirm-btn {
  text-align: center;
  font-size: 32rpx;
  padding: 0 96rpx;
  height: 88rpx;
  line-height: 88rpx;
  border-radius: 12rpx;
  color: var(--themeColor);
  border: 2rpx solid var(--themeColor);
}
.city-area-picker-btn-box .city-area-picker-confirm-btn{
  color: #fff;
  background-color: var(--themeColor);
}
page {
  --themeColor: #3399ff;
}
  • js 中
var isScroll = false;
const cityData = require('../../utils/area.js')
// console.log(cityData)
Component({
  properties: {
    /**
     * 日期选择器默认值 
     * 1. 这里设置无效 (暂时不知道什么原因)  --- 问题
     * 2. 所以由父组件传值过来,(* 父组件中,在 onShow() 这个生命周期中就 setData()) --- 解决
     */
    // currentValue: {
    //   type: Array,
    //   value: [0,0,0]
    // },
    bindArr: {
      type: Array,
      value: [110000,110100,110111]
    }
  },
  observers: {
    'bindArr': function() {
      this.initDatePicker();
    }
  },
  data: {
      isShow: false,
      proviceList: [],
      cityList: [],
      areaList: [],
      provice: null,
      city: null,
      area: null,
      currentValue: [0,0,0]
  },
  lifetimes: {
      attached: function () {
       
        this.formatCityData(cityData)
      },
      moved: function () {},
      detached: function () {},
  },
  methods: {
    // 格式化全国省市区数据
    formatCityData(cityData = []) {
      const currentValue = this.data.currentValue
      const proviceList = this.filterData(cityData)
      // console.log('动态更新 currentValue', currentValue)
      // console.log('当前省份下的省市区:', cityData[currentValue[0]])
      const cityList = this.filterData(cityData[currentValue[0]].children)
      const areaList = this.filterData(cityData[currentValue[0]].children[currentValue[1]].children)
      const provice = proviceList[currentValue[0]]
      const city = cityList[currentValue[1]]
      const area = areaList[currentValue[2]]
      this.setData({ proviceList, cityList, areaList, provice, city, area })
    },
    // 格式化全国省市区数据 辅助函数
    filterData(arr = []) {
      const list = []
      if (!arr) return []
      arr.forEach(v => {
        let obj = {}
        obj.name = v.name
        obj.code = v.code
        list.push(obj)
      })
      return list
    },
    /***
     * 滚动选择时触发change事件,
     * 可以查看小程序官方文档了解
     */
    bindChange(e) {
      console.log(e)
      const val = e.detail.value;
      let { currentValue } = this.data
      console.log('val:', val)
      console.log('currentValue:',currentValue)
      if (val[0] !== currentValue[0]) {
        currentValue = [val[0], 0, 0]
        this.setData({ currentValue })
      } else if (val[1] !== currentValue[1]) {
          currentValue = [val[0], val[1], 0]
          this.setData({ currentValue })
      } else if (val[2] !== currentValue[2]) {
          currentValue = val
          this.setData({ currentValue })
      }
      this.formatCityData(cityData)
    },
    // 滚动开始
    bindpickstart(){
      isScroll = true
    },
    //滚动结束
    bindpickend(){
      isScroll = false
    },
    // 打开 省市区三级联动 选择器
    handleShowCityAreaPicker() {
      this.setData({isShow: true})
      const pIndex = this.data.proviceList.findIndex(v => v.code == this.data.bindArr[0])
      const cityList = cityData[pIndex].children
      const cIndex = cityList.findIndex(v => v.code == this.data.bindArr[1])
      const areaList = cityList[cIndex].children
      const aIndex = areaList.findIndex(v => v.code == this.data.bindArr[2])
      this.setData({ cityList, areaList })
      this.setData({ currentValue: [pIndex, cIndex, aIndex] })
    },
    // 点击取消按钮,关闭日期选择器
    cancel() {
      this.setData({isShow: false})
    },
    // 点击确定按钮
    confirm() {
      let { provice, city, area } = this.data
      // 判断用户选择时间滚动是否结束,解决 picker-view bindChange 延迟问题
      if (isScroll) return
      this.triggerEvent('handleSelectDate', { provice, city, area })
      this.setData({isShow: false})
    },
    // 点击遮罩层,关闭日期选择器
    closeModal() {
      this.setData({isShow: false})
    },
    // 初始化 picker 日期数据 
    initDatePicker() {
      if (this.data.bindArr.length !== 0) {
        console.log(this.data.bindArr)
        const pItem = this.data.proviceList.find(v => v.code == this.data.bindArr[0])
        const pIndex = this.data.proviceList.findIndex(v => v.code == this.data.bindArr[0])
        let cItem = cityData[pIndex].children.find(v => v.code == this.data.bindArr[1])
        let aItem = cItem.children.find(v => v.code == this.data.bindArr[2])
        cItem = this.filterData([cItem])[0]
        aItem = this.filterData([aItem])[0]
        this.setData({ provice: pItem, city: cItem, area: aItem})
      }
    },
  },
});
父组件中
  • wxml 中
<view>
  <picker-city-area-pro bind:handleSelectDate="handleSelectDate" bindArr="{{bindArr}}"></picker-city-area-pro>
</view>
  • json 中
{
  "navigationBarTitleText": "省市区联动",
  "usingComponents": {
      "picker-city-area-pro": "/components/picker-city-area-pro"
  }
}
  • js 中
Page({
    data: {
        proviceId: '', // 省 code 
        cityId: '', // 省 code
        areaId: '', // 省 code
        bindArr: [] //用于回显 省市区 
    },
    handleSelectDate(e) {
        console.log(e.detail);
        const { provice, city, area } = e.detail
        this.setData({
            proviceId: provice.code,
            cityId: city.code,
            areaId: area.code
        })
    },
    // 页面初始化事件
    onLoad: function () {
        // 设置默认城市,不设置的默认会是  北京市-北京市-房山区
        this.setData({
            bindArr: ['420000', '420100', '420111']
        })
    },
    onShow: function () {}
});
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
微信小程序的原生 picker-view 是一种可以进行滚动选择的组件。它可以在小程序中展示一个滚动的选择器,用户可以通过上下滑动来选择需要的选项。 使用 picker-view 的步骤如下: 1. 在 wxml 文件中,通过<picker-view>标签来定义一个 picker-view 组件,可以通过style属性来设置它的样式。 2. 在 js 文件中,首先需要通过页面的setData()方法来初始化 picker-view 组件的数据源,使用数组的形式来表示选项。 3. 在 wxml 文件中,通过<picker-view-column>标签来定义 picker-view 中的每一列。可以使用wx:for属性来循环渲染每一列的选项。 4. 在 js 文件中,可以通过 onLoad()或者onShow()等生命周期方法来初始化 picker-view 组件的选中项。可以通过setData()方法更新 selected 属性的值来改变选中项。 5. 在 wxml 文件中,通过<view>标签来定义一个按钮或者其他交互元素,通过bindtap属性来绑定事件处理函数。 6. 在 js 文件中,实现事件处理函数,并通过setData()方法更新 selected 值以改变选中项。 7. 可以通过onPickerChange()等事件来监听 picker-view 的选中项改变的事件,并实现相应的逻辑。 需要注意的是,picker-view 组件的数组类型数据源,每一项都需要有value和text两个属性,分别表示选项的值和显示文本。 通过以上步骤,就可以在微信小程序使用原生 picker-view 组件实现选择器的功能。用户可以滚动选择选项,并通过自定义的事件处理函数来获取选中项的值。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值