微信小程序实现城市选择效果(超详细)

本文详细介绍了一款用于微信小程序的区域选择组件的创建过程,包括组件的结构、样式及交互逻辑,适用于需要用户选择省市区的应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

直接进入正题

首先在项目中同级创建一个components文件夹,在文件夹下创建region-picker文件夹,在该文件夹点击右键新建Component就会创建名为

region-picker.js

region-picker.json

region-picker.wxml

region-picker.wxss

下面我们来写我们的组件

region-picker.wxml

<view class="mask-layer" hidden="{{isShowToast}}"></view>
<view class="goodsdetail" hidden="{{isShowToast}}">
  <view class="seclection-title">请选择所在地区</view>
  <image class="close" src="../../img/icon/icon-cancel.png" bindtap="hideGoodsDetail"></image>
  <view class="state">
    <view>中国大陆</view>
    <view class="state-active"></view>
  </view>
  <view class="hot-city" hidden="{{!isClick}}">
    <view class="hot-title">热门城市</view>
    <view class="hot-city-list">
      <view wx:for="{{hotcityList}}" wx:key='item' data-item='{{item.city}}' data-index='{{item.id}}' bindtap='provinceChange'>{{item.city}}</view>
    </view>
  </view>
  <!-- <view class='goodsdetail-title'></view> -->
  <view class='goodsdetail-top' hidden="{{isClick}}">
    <view wx:for='{{nameArr}}' wx:key="index" class='{{currentTab == index ? "goodsdetail-top-l-o":"goodsdetail-top-l"}}' style='{{item == "" ? "display: none;":""}}' bindtap="navbarTap" data-index='{{index}}'>
      <view>{{item}}</view>
    </view>
  </view>
  <swiper class="swiper-box">
    <swiper-item wx:if='{{currentTab == 0}}' catchtouchmove='catchTouchMove'>
      <scroll-view scroll-y class="swiper-box-scr">
        <view class='swiper-box-item {{nameArr[0] == item ? "active":""}}' wx:for='{{provinceArr}}' wx:key='item' data-item='{{item}}' data-index='{{index}}' bindtap='provinceChange'>
          <block wx:if="{{nameArr[0] == item}}">
            <image class="select" src="{{nameArr[0] == item? '../../img/icon/icon-select.png': ''}}"></image>
          </block>
          <view>{{item}}</view>
        </view>
      </scroll-view>
    </swiper-item>

    <swiper-item wx:if='{{currentTab == 1}}' catchtouchmove='catchTouchMove'>
      <scroll-view scroll-y class="swiper-box-scr">
        <view class='swiper-box-item {{nameArr[1] == item ? "active":""}}' wx:for='{{cityArr}}' wx:key='item' data-item='{{item}}' data-index='{{index}}' bindtap='cityChange'>
          <block wx:if="{{nameArr[1] == item}}">
            <image class="select" src="{{nameArr[1] == item? '../../img/icon/icon-select.png': ''}}"></image>
          </block>
          <view>{{item}}</view>
        </view>
      </scroll-view>
    </swiper-item>

    <swiper-item wx:if='{{currentTab == 2}}' catchtouchmove='catchTouchMove'>
      <scroll-view scroll-y class="swiper-box-scr">
        <view class='swiper-box-item {{nameArr[2] == item ? "active":""}}' wx:for='{{countryArr}}' wx:key='item' data-item='{{item}}' data-index='{{index}}' bindtap='districtChange'>
          <block wx:if="{{nameArr[2] == item}}">
            <image class="select" src="{{nameArr[2] == item? '../../img/icon/icon-select.png': ''}}"></image>
          </block>
          <view>{{item}}</view>
        </view>
      </scroll-view>
    </swiper-item>
  </swiper>
</view>

region-picker.wxss

/*弹窗*/

.goodsdetail {
  position: fixed;
  left: 5rpx;
  bottom: 10rpx;
  width: 740rpx;
  height: 1000rpx;
  background: #fff;
  z-index: 99;
  overflow: hidden;
  border-radius: 20rpx;
}

.goodsdetail-top {
  width: 750rpx;
  box-sizing: border-box;
  display: flex;
  position: relative;
  margin: 81rpx 34rpx;
}

.goodsdetail-top-l {
  box-sizing: border-box;
  font-size: 28rpx;
  font-weight: bold;
  font-family: "PingFang-SC-Bold";
  color: #f73c41;
  margin-right: 74rpx;
}

.goodsdetail-top-l-o {
  box-sizing: border-box;
  font-size: 28rpx;
  font-weight: bold;
  font-family: "PingFang-SC-Bold";
  margin-right: 74rpx;
}

.goodsdetail-top-c {
  height: 80rpx;
  padding: 0 20rpx 0 20rpx;
  line-height: 80rpx;
  box-sizing: border-box;
  font-size: 26rpx;
}

.goodsdetail-top-c-o {
  height: 80rpx;
  padding: 0 20rpx 0 20rpx;
  line-height: 80rpx;
  box-sizing: border-box;
  font-size: 26rpx;
  border-bottom: 1rpx solid #e22e1f;
}

.goodsdetail-top-r {
  height: 80rpx;
  padding: 0 20rpx 0 20rpx;
  line-height: 80rpx;
  box-sizing: border-box;
  font-size: 26rpx;
}

.goodsdetail-top-r-o {
  height: 80rpx;
  padding: 0 20rpx 0 20rpx;
  line-height: 80rpx;
  box-sizing: border-box;
  font-size: 26rpx;
  border-bottom: 1rpx solid #e22e1f;
}

.goodsdetail-top-cancel {
  position: absolute;
  right: 0;
  top: 0;
  color: #aaa;
  height: 80rpx;
  padding: 0 40rpx 0 20rpx;
  line-height: 80rpx;
  box-sizing: border-box;
  font-size: 26rpx;
}

.swiper-box {
  width: 740rpx;
  height: 620rpx;
  box-sizing: border-box;
}

.swiper-box-scr {
  width: 740rpx;
  height: 620rpx;
  box-sizing: border-box;
}

.swiper-box-item {
  height: 85rpx;
  line-height: 85rpx;
  font-size: 28rpx;
  font-weight: Medium;
  font-family: "PingFang-SC-Medium";
  border-bottom: 1rpx solid #EEEEEE;
  box-sizing: border-box;
  display: flex;
  position: relative;
  margin: 0 30rpx;
  padding: 0 5rpx;
  align-items: center;
}

.seclection-title {
  text-align: center;
  margin-top: 40rpx; 
  font-size: 32rpx;
  font-weight: bold;
  font-family: "PingFang-SC-Bold";
  color: #000000;
  margin-bottom: 83rpx;
}
.state {
  font-size: 30rpx;
  color: #f73c41;
  font-weight: bold;
  font-family: "PingFang-SC-Bold";
  margin-left: 35rpx;
  margin-right: 35rpx;
}
.state view:nth-child(1) {
  margin-bottom: 11rpx;
}
.close {
  width: 32rpx;
  height: 31rpx;
  position: absolute;
  right: 39rpx;
  top: 41rpx;
}
.state-active {
  height: 6rpx;
  width: 20.4rpx;
  background: #f73c41;
  border-radius: 2.5rpx;
  margin-left: 48rpx;
}
.hot-city {
  margin: 68rpx 35rpx 64rpx;
}
.hot-city .hot-title {
  font-size: 28rpx;
  color: #999999;
}
.hot-city .hot-city-list {
  display: flex;
  font-size: 28rpx;
  color: #000000; 
  justify-content: space-between;
  margin-top: 42rpx;
}
.hot-city view:nth-child(2) view:nth-child(1) {
  margin-left: 28rpx;
}
.hot-city view:nth-child(2) view:last-child {
  margin-right: 28rpx;
}
.active {
  font-size: 28rpx;
  font-weight: bold;
  font-family: "PingFang-SC-Bold";
  color: #f73c41;
}
.mask-layer {
  width: 100%;
  height: 100%;
  background: #000;
  opacity: 0.5;
  position: fixed;
  z-index: 99;
  top: 0;
  left: 0;
  overflow: hidden;
}
.swiper-box-item image {
  width: 35rpx;
  height: 27rpx;
  margin-right: 22rpx;
}

region-picker.js

var city = require('../../utils/city.js')
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    locationArr: {
      type: Array,
      value: '',
      observer: function(newVal, oldVal) {
        console.log('我是传递进入的省', newVal)
      }
    },
  },

  /**
   * 组件的初始数据
   */
  data: {
    // 弹窗显示控制
    isShowToast: true,
    isShowToasts: false,
    isClick: true,
    nameArr: ['请选择', '', ''],
    currentTab: 0, // tab切换 
    provinceArr: [],
    provinceIndex: 0,
    cityArr: [],
    cityIndex: 0,
    countryArr: [],
    countryIndex: 0,
    hotcityList: [{
      id: 0,
      city: '北京'
    }, {
      id: 8,
      city: '上海'
    }, {
      id: 1,
      city: '天津'
    }, {
      id: 18,
      city: '广东'
    }]
  },
  /**
   * 组件的方法列表
   */
  methods: {
    //隐藏
    hideGoodsDetail: function() {
      var that = this
      that.setData({
        isShowToast: true
      })
    },

    //显示
    showsGoodsDetail: function() {
      var that = this
      var tempLocalArr = that.properties.locationArr //传入的省市区
      var tempNameArr = that.data.nameArr //顶部省市区
      that.setData({
        isShowToast: false
      })
      // console.log('我是传入的值')
      // console.log(tempLocalArr)
      this.setData({
        provinceArr: city.getProvince()
      });
      // console.log(city.getProvince())
      //是否传入地址 传入则显示当前地址   为传入则显示之前地址
      if (tempLocalArr[0] == '' || tempLocalArr[1] == '' || tempLocalArr[2] == '') {
        console.log('我是未传入地址')
      } else {
        // console.log('我是传入了地址')
        tempNameArr[0] = tempLocalArr[0]
        tempNameArr[1] = tempLocalArr[1]
        tempNameArr[2] = tempLocalArr[2]
        var tempProvinceIndex = that.data.provinceArr.indexOf(tempLocalArr[0]) //省索引
        //在这里对不存在的地址进行兼容
        if (tempProvinceIndex == -1) {
          // console.log('我是省没有 找到')
          tempProvinceIndex = 0
          tempNameArr[0] = that.data.provinceArr[0]
        }
        var tempCityArr = city.getCity(that.data.provinceArr[tempProvinceIndex]) //市
        var tempCityIndex = tempCityArr.indexOf(tempLocalArr[1]) //市索引
        //在这里对不存在的地址进行兼容
        if (tempCityIndex == -1) {
          // console.log('我是市没有 找到')
          tempCityIndex = 0
          tempNameArr[1] = tempCityArr[0]
        }
        var tempCountryArr = city.getArea(that.data.provinceArr[tempProvinceIndex], tempCityArr[tempCityIndex]) //区
        var tempCountryIndex = tempCountryArr.indexOf(tempLocalArr[2]) //区索引
        //在这里对不存在的地址进行兼容
        if (tempCountryIndex == -1) {
          // console.log('我是区没有 找到')
          tempCountryIndex = 0
          tempNameArr[2] = tempCountryArr[0]
        }
        that.setData({
          nameArr: tempNameArr,
          provinceIndex: tempProvinceIndex,
          cityArr: tempCityArr,
          cityIndex: tempCityIndex,
          countryArr: tempCountryArr,
          countryIndex: tempCountryIndex,
          currentTab: 0,
        })

      }
    },

    //改变省
    provinceChange: function(e) {
      var that = this
      var tempNameArr = that.data.nameArr

      console.log(e.currentTarget.dataset.index)
      console.log(e.currentTarget.dataset.item)
      tempNameArr[0] = that.data.provinceArr[e.currentTarget.dataset.index]
      tempNameArr[1] = '请选择'
      tempNameArr[2] = ''
      that.setData({
        provinceIndex: e.currentTarget.dataset.index,
        nameArr: tempNameArr,
        countryArr: [],
        countryIndex: 0,
      })
      //获取市
      this.setData({
        cityArr: city.getCity(that.data.provinceArr[that.data.provinceIndex]),
        currentTab: 1,
        isClick: false,
      });
      console.log(that.data.cityArr)
    },

    //改变市
    cityChange: function(e) {
      var that = this
      var tempNameArr = that.data.nameArr

      tempNameArr[0] = that.data.provinceArr[that.data.provinceIndex]
      tempNameArr[1] = that.data.cityArr[e.currentTarget.dataset.index]
      tempNameArr[2] = '请选择'
      that.setData({
        cityIndex: e.currentTarget.dataset.index,
        nameArr: tempNameArr
      })
      //获取区
      this.setData({
        countryArr: city.getArea(that.data.provinceArr[that.data.provinceIndex], that.data.cityArr[that.data.cityIndex]),
        currentTab: 2
      });
    },


    //改变区区/县
    districtChange: function(e) {
      var that = this
      var tempNameArr = that.data.nameArr

      tempNameArr[0] = that.data.provinceArr[that.data.provinceIndex]
      tempNameArr[1] = that.data.cityArr[that.data.cityIndex]
      tempNameArr[2] = that.data.countryArr[e.currentTarget.dataset.index]
      that.setData({
        countryIndex: e.currentTarget.dataset.index,
        nameArr: tempNameArr,
        isShowToast: true,
        currentTab: 0
      })
      //关闭并返回
      this.triggerEvent('resultEvent', {
        nameArr: that.properties.nameArr
      })
      console.log(that.data.provinceArr[that.data.provinceIndex])
      // console.log(that.data.cityArr[that.data.cityIndex])
      // console.log(that.data.countryArr[that.data.countryIndex])
      //关闭并返回  省市区
    },

    // 截获竖向滑动  2018年7月5日19:55:40  刘宣亮
    catchTouchMove: function(res) {
      return false
    },

    // 点击tab切换   2018年7月5日19:59:30 刘宣亮
    navbarTap: function(e) {
      var that = this

      that.setData({
        currentTab: e.currentTarget.dataset.index,
      })
      console.log(e.currentTarget.dataset.index)
    },
  }
})

region-picker.json

{
  "component": true,
  "usingComponents": {}
}

以上就完成了组件

下面来看看怎么来调用吧

在需要调用的页面添加

"usingComponents": {

"region-picker": "../../components/region-picker/region-picker"

}

顺便补充一点吧,我添加页面调用的效果

这样没什么问题吧,my-add-address就是一个文件夹,index是我的习惯,你也可以直接my-add-address.wxml,最后会给大家看一下我的目录结构

my-add-address/index.wxml       

<view class="redact-address">
  <view class="possess-layout">
    <view class="mains">
      <view class="address-msg">
        <view class="item-msg">收货人</view>
        <view class="section">
          <input type="text" placeholder="请填写收货人姓名" value="{{consigneeName}}" bindblur="consigneeNameInput" placeholder-class="phcolor"></input>
        </view>
        <view class="address-right">
          <image src="../../../img/icon/icon-add-address-user.png"></image>
        </view>
      </view>
      <view class="address-msg">
        <view class="item-msg">手机号码</view>
        <view class="section">
          <input type="number" placeholder="请填写收货人手机号码" value="{{phone}}" maxlength="11" bindblur="phoneInput" placeholder-class="phcolor"></input>
        </view>
      </view>
      <view class="address-msg" bindtap='chooseAddress'>
        <view class="item-msg">所在地区</view>
        <view class="section" bindtap='select'>
          <input disabled="disabled" placeholder="省市区县、乡镇等" value="{{locationArr[0] + locationArr[1] + locationArr[2]}}" bindblur="consigneeRegionInput" placeholder-class="phcolor"></input>
        </view>
        <view class="address-rights" bindtap='select'>
          <image src="../../../img/icon/icon-site-location.png"></image>
          <view>定位</view>
        </view>
      </view>
      <view class="address-msg">
        <view class="item-msg">详细地址</view>
        <view class="section">
          <input type="text" placeholder="街道、楼牌号等" value="{{detailedAddress}}" bindblur="detailedAddressInput" placeholder-class="phcolor"></input>
        </view>
      </view>
      <view class="label">
        <view class="label-title">标签</view>
        <view class="label-list">
          <block wx:for="{{labelList}}" wx:key="index">
            <view class="labels {{labelDefault==index? 'labels-active': ''}}" data-index="{{index}}" bindtap="chooseLabelSelect">{{item}}</view>
          </block>
        </view>
      </view>
      <view class="default-setting">
        <view class="defaul-setting-left">
          <view>设置默认地址</view>
          <view>提醒:每次下单会默认推荐使用该地址</view>
        </view>
        <image class="defaul-setting-right" src="{{defaults? '../../../img/icon/icon-off-by-default.png': '../../../img/icon/icon-off-by-default-red.png'}}" bindtap="chooseDefault"></image>
      </view>
    </view>
  </view>
</view>

<view class="btn" bindtap="submit">保存</view>


<!-- 城市选择 S -->
<scroll-view scroll-y style="height: {{windowHeight}}px;width: 100%;" class='body'>
  <region-picker id='getAddress' locationArr="{{locationArr}}" bind:resultEvent="resultEvent">
  </region-picker>
</scroll-view>
<!-- 城市选择 E -->

my-add-address/index.wxss

.redact-address {
  background: white;
  margin-bottom: 20rpx;
}

.address-msg {
  height: 128rpx;
  display: flex;
  align-items: center;
  background: #fff;
  border-top: 2rpx solid #efefef;
  font-size: 28.68rpx;
  color: #333;
  padding: 0 20rpx;
}

.address-right image {
  width: 32rpx;
  height: 32rpx;
}

.address-rights {
  display: flex;
  align-items: center;
}

.address-rights image {
  width: 26rpx;
  height: 32rpx;
  margin-right: 13rpx;
}

.address-rights view {
  font-size: 28.68rpx;
}

.address-msg:last-child {
  border-bottom: none;
}

.section {
  width: 58%;
}

.phcolor {
  color: #999;
}

.item-msg {
  width: 25%;
  margin-right: 25rpx;
}

.img {
  width: 35rpx;
  height: 35rpx;
  align-self: center;
}

.address-right {
  width: 100rpx;
  display: flex;
  flex-direction: row-reverse;
}

/* 标签 */

.label {
  display: flex;
  height: 128rpx;
  align-items: center;
  margin-top: 73rpx;
  border-top: 1px solid #eee;
  border-bottom: 1px solid #eee;
  padding: 0 20rpx;
}

.label-title {
  font-size: 28.68rpx;
  color: #333;
  margin-right: 83rpx;
}

.label .label-list {
  display: flex;
}

.label .label-list .labels {
  height: 40rpx;
  width: 96rpx;
  border: 1px solid #eee;
  margin-right: 37rpx;
  text-align: center;
  line-height: 40rpx;
  font-size: 24rpx;
  color: #000;
  border-radius: 20rpx;
}

.labels-active {
  background: #f73c41 !important;
  color: #fff !important;
}

/* 默认设置 */

.default-setting {
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: 160rpx;
  padding: 0 20rpx;
}

.defaul-setting-left view:nth-child(1) {
  font-size: 28.68rpx;
  color: #333;
  margin-bottom: 25rpx;
}

.defaul-setting-left view:nth-child(2) {
  font-size: 20rpx;
  color: #333;
}

.defaul-setting-right {
  height: 64rpx;
  width: 105rpx;
}

.btn {
  width: 680rpx;
  height: 88rpx;
  background: #f73c41;
  color: #fff;
  position: fixed;
  bottom: 55rpx;
  left: 35rpx;
  border-radius: 41.5rpx;
  font-size: 36rpx;
  text-align: center;
  line-height: 88rpx;
}

/* 城市选择 */
.body {
  display: block;
  /* border: 1rpx solid #000; */
  box-sizing: border-box;
}
 
.choose_address{
  height: 90rpx;
  width: 750rpx;
  box-sizing: border-box;
  padding: 0 40rpx 0 40rpx;
  font-size: 32rpx;
  line-height: 90rpx;
  border-bottom: 1rpx solid #aaa;
}

my-add-address/index.js

var app = getApp()
Page({
  /**
   * 页面的初始数据
   */
  data: {
    addressMenuIsShow: false,
    consigneeName: "",
    phone: "",
    detailedAddress: "",
    labelList: ["家", "公司", "学校"], //标签
    labelDefault: 0, // 标签默认,
    defaults: 0,        // 默认
    // 城市选择
    windowHeight: 0,
    // locationArr: ['山东省', '青岛市', '黄岛区']
    locationArr: ['', '', '']
  },
  consigneeNameInput: function(e) { //获取收货人
    this.setData({
      consigneeName: e.detail.value
    })
  },
  phoneInput: function(e) { //获取手机号
    this.setData({
      phone: e.detail.value
    })
  },
  consigneeRegionInput: function(e) { //获取所在地址

    this.setData({
      consigneeRegion: e.detail.value
    })
  },
  detailedAddressInput: function(e) { //获取详细地址
    this.setData({
      detailedAddress: e.detail.value
    })
  },
  chooseLabelSelect: function(e) { //获取标签
    var index = e.currentTarget.dataset.index;
    this.setData({
      labelDefault: index
    })
  },
  submit: function() {
    var consigneeName = this.data.consigneeName;
    var phone = this.data.phone;
    var consigneeRegion = this.data.consigneeRegion;
    var detailedAddress = this.data.detailedAddress
    if (consigneeName == "") {
      wx: wx.showToast({
        title: '请输入姓名',
        image: "../../../img/icon/icon-reminder.png"
      })
      return false
    }
    else if (phone == "") {
      wx: wx.showToast({
        title: '请输入手机号码',
        image: "../../../img/icon/icon-reminder.png"
      })
      return false
    }
    else if (consigneeRegion == "") {
      wx: wx.showToast({
        title: '请选择所在地区',
        image: "../../../img/icon/icon-reminder.png"
      })
      return false
    }
    else if (detailedAddress == "") {
      wx: wx.showToast({
        title: '请输入详细地址',
        image: "../../../img/icon/icon-reminder.png"
      })
      return false
    }
    else {
      wx.navigateTo({
        url: '../../my/my-delivery-address/index',
      })
    }
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function(options) {
    var _this = this
    //获得dialog组件
    this.getAddress = this.selectComponent("#getAddress");
    wx.getSystemInfo({
      success: function (res) {
        // console.log(res.pixelRatio) //设备像素比
        // console.log(res.windowWidth) //可使用窗口宽度
        // console.log(res.windowHeight) //可使用窗口高度
        _this.setData({
          windowWidth: res.windowWidth, //可使用窗口宽度
          windowHeight: res.windowHeight, //可使用窗口高度
        })
      }
    })
  },
  /**
   * 是否选择默认
   */
  chooseDefault: function() {
    this.setData({
      defaults: this.data.defaults
    })
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function() {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function() {

  },
  //选择地址     点击所在地区弹出选择框
  chooseAddress: function (e) {
   
    var _this = this
    _this.getAddress.showsGoodsDetail();
  },

  //组件回调
  resultEvent: function (e) {
    var _this = this
    // console.log(e)
    // console.log(e.detail.nameArr)
    _this.setData({
      locationArr: e.detail.nameArr
    })
  },
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function() {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function() {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function() {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function() {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function() {

  }
})

my-add-address/index.json

{
  "navigationBarTitleText": "添加收货地址",
  "usingComponents": {
    "region-picker": "../../components/region-picker/region-picker"
  }
}

 以上就是所有代码

上图

目录结构

最后来张效果图

可扫码自行下载city.js文件

 

city.js文件可自行下载:微信小程序实现城市选择效果city.js文件_微信小程序城市选择器-互联网文档类资源-CSDN下载

评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值