uni.app的uni-popup:this.popup.disableMask is not a function

文章指出在popup.js中由于uniPopup和UniPopup的大小写不一致导致getParent方法返回false,从而影响uni-popup-dialog组件的正常工作。解决方案是将name参数修改为UniPopup,并调整组件内部对this.popup的调用方式,以避免报错。

 出现这个错误是因为popup.js中getParent()方法中name是'uniPopup',u是小写的,而下面parent.$options.name获取到的是的是'UniPopup',而所有返回的是false,this.popup是false,里面什么都没有

	
//这个时popup.js文件,uni-popup-dialog就是引入的这个
created(){
        //this.popup为false
		this.popup = this.getParent()
	},
	methods:{
		/**
		 * 获取父元素实例
		 */
		getParent(name = 'uniPopup') {
			// debugger
			let parent = this.$parent;
			let parentName = parent.$options.name;
            
			while (parentName !== name) {
				parent = parent.$parent;
                //这里的判断是parent为空时直接返回了false,所有无法执行到return 
				if (!parent) return false
				parentName = parent.$options.name;
			}
			// debugger
            //无法运行到这里,所有return无法执行
			return parent;
		},
	}
}
//所以uni-popup-dialog内无法访问到this.popup数据

看详情

 

//只需要将name = 'uniPopup'修改为name = 'UniPopup'
//另外可在uni-popup-dialog.vue文件中将
//"this.popup.disableMask()"和"this.popup.closeMask()"
//替换为"this.popup.mkclick = false;"和"this.popup.maskShow = false;"
//就不会报错了

<template> <!-- 蒙层 --> <view v-if="visible" class="zy-popup-select-mask-layer" @click="handleMaskClick"> <view :class="{ 'zy-popup-select-mask-false': !mask, 'zy-popup-select-mask': mask }" style="height: 100%" /> </view> <!-- 弹窗 --> <view v-if="visible" class="zy-popup-select-popup-wrapper"> <view class="zy-popup-select-popup" :style="{ 'min-height': optionsHeight + optionsHeightPx }"> <!-- 滚动区域 --> <scroll-view class="zy-popup-select-options" :class="{ 'zy-popup-select-options-scrollable': options.length > maxVisibleItems }" scroll-y :style="{ '--max-visible-height': maxVisibleHeight }" > <!-- 🔹 插槽:header - 滚动区域内顶部 --> <view v-if="$slots.header" class="zy-popup-select-slot-header"> <slot name="header" :selected-count="selectedValues.length" :total-count="options.length" :clear-selection="clearSelection" :select-all="selectAll" /> </view> <!-- 渲染选项 --> <view v-for="(item, index) in options" :key="getValue(item)" class="zy-popup-select-option-item" :class="{ 'zy-popup-select-option-selected': isSelected(item) }" :style="{ height: optionsHeight + optionsHeightPx }" @click="toggleOption(item)" > <!-- 🔹 插槽:option - 自定义每个选项 --> <slot name="option" :item="item" :index="index" :value="getValue(item)" :label="getLabel(item)" :selected="isSelected(item)" > <!-- 默认选项 --> <text class="zy-popup-select-option-text" :class="{ 'zy-popup-select-option-text-selected': isSelected(item) }" > {{ getLabel(item) }} </text> <uni-icons v-if="isSelected(item)" class="zy-popup-select-checkmark" type="checkmarkempty" color="#0f56d5" /> </slot> </view> <!-- 🔹 插槽:footer - 滚动区底部 --> <view v-if="$slots.footer && options.length > 0" class="zy-popup-select-slot-footer"> <slot name="footer" :selected-values="selectedValues" :options="options" :clear="clearSelection" :select-all="selectAll" /> </view> <!-- 🔹 插槽:empty - 数据为空时展示 --> <view v-if="options.length === 0" class="zy-popup-select-slot-empty"> <slot name="empty"> <text class="zy-popup-select-empty-text">暂无可用选项</text> </slot> </view> </scroll-view> <!-- 分割线 --> <view class="zy-popup-select-divider" /> <!-- 🔹 插槽:cancel - 可替换取消按钮 --> <view class="zy-popup-select-cancel" :style="{ height: optionsHeight + optionsHeightPx }" @click="handleCancel"> <slot name="cancel"> <text class="zy-popup-select-cancel-text">取消</text> </slot> </view> </view> </view> </template> <script> export default { name: 'ZySelect', props: { modelValue: { type: Boolean, default: false }, options: { type: Array, required: true }, labelKey: { type: String, default: 'label' }, valueKey: { type: String, default: 'value' }, maxSelected: { type: Number, default: 1 }, defaultSelected: { type: Array, default: () => [] }, mask: { type: Boolean, default: true }, optionsHeight: { type: Number, default: 57 }, optionsHeightPx: { type: String, default: 'px' }, maxVisibleItems: { type: Number, default: 3 } }, emits: ['update:modelValue', 'change', 'confirm'], data() { return { selectedValues: [...this.defaultSelected] } }, computed: { visible() { return this.modelValue }, maxVisibleHeight() { return `${this.maxVisibleItems * this.optionsHeight}${this.optionsHeightPx}` } }, mounted() {}, methods: { // 清空所有选择 clearSelection() { this.selectedValues = [] this.$emit('change', { item: null, selected: false }) }, // 全选功能(受 maxSelected 限制) selectAll() { if (this.maxSelected === 1) return const restCount = this.maxSelected - this.selectedValues.length if (restCount <= 0) { uni.showToast({ title: `已达上限${this.maxSelected}项`, icon: 'none' }) return } const newValues = this.options .map(this.getValue) .filter(val => !this.selectedValues.includes(val)) .slice(0, restCount) this.selectedValues.push(...newValues) this.$emit('change', { item: null, selected: true }) }, getLabel(item) { return item[this.labelKey] }, getValue(item) { return item[this.valueKey] }, isSelected(item) { return this.selectedValues.includes(this.getValue(item)) }, toggleOption(item) { const value = this.getValue(item) const index = this.selectedValues.indexOf(value) if (index > -1) { this.selectedValues.splice(index, 1) this.$emit('change', { item, selected: false }) } else { if (this.selectedValues.length >= this.maxSelected) { uni.showToast({ title: `最多选中 ${this.maxSelected} 项`, icon: 'none', duration: 1500 }) return } this.selectedValues.push(value) this.$emit('change', { item, selected: true }) } }, handleCancel() { this.selectedValues = [...this.defaultSelected] // 恢复默认 this.close(true) }, handleMaskClick() { this.close(false) // 点击蒙层视为非取消关闭 }, close(fromCancel) { this.$emit('update:modelValue', false) this.$emit('confirm', { selected: this.selectedValues.map(val => this.options.find(opt => this.getValue(opt) === val)).filter(Boolean), fromCancel }) } } } </script> <style lang="scss"> /* 蒙层外层:覆盖全屏,但只显示上半部分 */ .zy-popup-select-mask-layer { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 998; /* 蒙层层级 */ pointer-events: auto; } .zy-popup-select-mask { width: 100%; background-color: #000000; opacity: 0.5; } .zy-popup-select-mask-false { opacity: 0; width: 100%; } /* 弹窗外层:固定在底部,浮在蒙层之上 */ .zy-popup-select-popup-wrapper { position: fixed; bottom: 0; left: 0; width: 100%; z-index: 999; /* 高于蒙层 */ background-color: #fff; /* 确保不侵入底部安全区 */ padding-bottom: env(safe-area-inset-bottom); /* ✅ 关键:顶部圆角 */ border-radius: 8px 8px 0 0; /* ✅ 确保子元素不溢出圆角边界 */ overflow: hidden; } /* 弹窗整体布局改为 flex 列布局 */ .zy-popup-select-popup { background-color: #ffffff; width: 100%; box-sizing: border-box; display: flex; flex-direction: column; } /* 滚动区域:允许纵向滚动,限制最大高度 */ .zy-popup-select-options { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; max-height: var(--max-visible-height); /* 使用 CSS 变量 */ } .zy-popup-select-options-scrollable { overflow-y: auto; } /* 单个选项保持居中等样式不变 */ .zy-popup-select-option-item { position: relative; display: flex; align-items: center; justify-content: center; /* 主轴居中:X 轴居中 */ padding: 0 60rpx; box-sizing: border-box; } .zy-popup-select-option-item::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; /* 先设成 1px */ background-color: #eeeeee; transform: scaleY(0.5); /* 缩小一半 → 视觉上就是 0.5px */ transform-origin: bottom; pointer-events: none; } .zy-popup-select-option-item:last-child::after { display: none; } /* 文本:完全居中,不受对号影响 */ .zy-popup-select-option-text { font-size: $uni-font-size-18; color: $uni-text-color; font-weight: 400; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: calc(100% - 100rpx); /* 防止太长碰到右边 */ text-align: center; z-index: 1; /* 确保在上层 */ } /* 选中状态文字颜色 */ .zy-popup-select-option-selected .zy-popup-select-option-text { color: $uni-primary; } .zy-popup-select-option-text-selected { transform: translate(8px, 0px); } /* ✅ 对号:绝对定位,脱离文档流 */ .zy-popup-select-checkmark { transform: translate(22px, 0px); color: $uni-primary; font-weight: bold; font-size: $uni-font-size-18; width: auto; height: auto; z-index: 2; /* 确保显示在上面 */ } /* 分割线:固定在取消按钮上方 */ .zy-popup-select-divider { height: 8px; background-color: $uni-bg-color; /* 不再随内容滚动 */ } /* 取消按钮 */ .zy-popup-select-cancel { display: flex; align-items: center; justify-content: center; } .zy-popup-select-cancel-text { font-size: $uni-font-size-18; color: $uni-text-color; text-align: center; font-weight: 400; } /* 插槽容器通用样式 */ .zy-popup-select-slot-header, .zy-popup-select-slot-footer, .zy-popup-select-slot-empty { width: 100%; padding: 12px 0; display: flex; justify-content: center; align-items: center; position: relative; /* 添加顶部分隔线 */ &::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px; background-color: #eee; transform: scaleY(0.5); transform-origin: top; } } /* 空状态文本 */ .zy-popup-select-empty-text { font-size: $uni-font-size-14; color: #999; } </style> scroll-view希望小程序中一直展示滚动条
最新发布
09-20
<template> <!-- 蒙层(全屏层级,仅覆盖非操作区) --> <view v-if="visible" class="zy-select-mask-layer" @click="handleMaskClick"> <view :class="{ 'zy-select-mask-false': !mask, 'zy-select-mask': mask }" :style="{ height: '100%' }" /> </view> <!-- 弹窗(独立层级,浮在蒙层之上) --> <view v-if="visible" class="zy-select-popup-wrapper"> <view class="zy-select-popup"> <!-- 可选项滚动区域 --> <scroll-view class="zy-select-options" :class="{ 'zy-select-options-scrollable': options.length > maxVisibleItems }" scroll-y :style="{ '--max-visible-height': maxVisibleHeight }" > <view v-for="(item, index) in options" :key="getValue(item)" class="zy-select-option-item" :class="{ 'zy-select-option-selected': isSelected(item) }" @click="toggleOption(item)" > <text class="zy-select-option-text" :class="{ 'zy-select-option-text-selected': isSelected(item) }"> {{ getLabel(item) }} </text> <uni-icons v-if="isSelected(item)" class="zy-select-checkmark" type="checkmarkempty" color="#0f56d5" /> </view> </scroll-view> <!-- 分割线 --> <view class="zy-select-divider" /> <!-- 取消按钮 --> <view class="zy-select-cancel" @click="handleCancel"> <text class="zy-select-cancel-text">取消</text> </view> </view> </view> </template> <script> export default { name: 'ZySelect', props: { modelValue: { type: Boolean, default: false }, options: { type: Array, required: true }, labelKey: { type: String, default: 'label' }, valueKey: { type: String, default: 'value' }, maxSelected: { type: Number, default: 1 }, defaultSelected: { type: Array, default: () => [] }, mask: { type: Boolean, default: true }, maxVisibleItems: { type: Number, default: 3 } }, emits: ['update:modelValue', 'change', 'confirm'], data() { return { selectedValues: [...this.defaultSelected] } }, computed: { visible() { return this.modelValue }, maxVisibleHeight() { return `${this.maxVisibleItems * 57}px` } }, mounted() {}, methods: { getLabel(item) { return item[this.labelKey] }, getValue(item) { return item[this.valueKey] }, isSelected(item) { return this.selectedValues.includes(this.getValue(item)) }, toggleOption(item) { const value = this.getValue(item) const index = this.selectedValues.indexOf(value) if (index > -1) { this.selectedValues.splice(index, 1) this.$emit('change', { item, selected: false }) } else { if (this.selectedValues.length >= this.maxSelected) { uni.showToast({ title: `最多选中 ${this.maxSelected} 项`, icon: 'none', duration: 1500 }) return } this.selectedValues.push(value) this.$emit('change', { item, selected: true }) } }, handleCancel() { this.selectedValues = [...this.defaultSelected] // 恢复默认 this.close(true) }, handleMaskClick() { this.close(false) // 点击蒙层视为非取消关闭 }, close(fromCancel) { this.$emit('update:modelValue', false) this.$emit('confirm', { selected: this.selectedValues.map(val => this.options.find(opt => this.getValue(opt) === val)).filter(Boolean), fromCancel }) } } } </script> <style lang="scss"> /* 蒙层外层:覆盖全屏,但只显示上半部分 */ .zy-select-mask-layer { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 998; /* 蒙层层级 */ pointer-events: auto; } .zy-select-mask { width: 100%; background-color: #000000; opacity: 0.5; } .zy-select-mask-false { opacity: 0; width: 100%; } /* 弹窗外层:固定在底部,浮在蒙层之上 */ .zy-select-popup-wrapper { position: fixed; bottom: 0; left: 0; width: 100%; z-index: 999; /* 高于蒙层 */ background-color: #fff; /* 确保不侵入底部安全区 */ padding-bottom: env(safe-area-inset-bottom); /* ✅ 关键:顶部圆角 */ border-radius: 8px 8px 0 0; /* ✅ 确保子元素不溢出圆角边界 */ overflow: hidden; } /* 弹窗整体布局改为 flex 列布局 */ .zy-select-popup { background-color: #ffffff; width: 100%; box-sizing: border-box; display: flex; flex-direction: column; min-height: 57px; /* 防止空内容塌陷 */ } /* 滚动区域:允许纵向滚动,限制最大高度 */ .zy-select-options { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; max-height: var(--max-visible-height); /* 使用 CSS 变量 */ } .zy-select-options-scrollable { overflow-y: auto; } /* 单个选项保持居中等样式不变 */ .zy-select-option-item { position: relative; height: 57px; display: flex; align-items: center; justify-content: center; /* 主轴居中:X 轴居中 */ padding: 0 60rpx; box-sizing: border-box; } .zy-select-option-item::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; /* 先设成 1px */ background-color: #eeeeee; transform: scaleY(0.5); /* 缩小一半 → 视觉上就是 0.5px */ transform-origin: bottom; pointer-events: none; } .zy-select-option-item:last-child::after { display: none; } /* 文本:完全居中,不受对号影响 */ .zy-select-option-text { font-size: $uni-font-size-18; color: $uni-text-color; font-weight: 400; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: calc(100% - 100rpx); /* 防止太长碰到右边 */ text-align: center; z-index: 1; /* 确保在上层 */ } /* 选中状态文字颜色 */ .zy-select-option-selected .zy-select-option-text { color: $uni-primary; } .zy-select-option-text-selected { transform: translate(8px, 0px); } /* ✅ 对号:绝对定位,脱离文档流 */ .zy-select-checkmark { transform: translate(22px, 0px); color: $uni-primary; font-weight: bold; font-size: $uni-font-size-18; width: auto; height: auto; z-index: 2; /* 确保显示在上面 */ } /* 分割线:固定在取消按钮上方 */ .zy-select-divider { height: 8px; background-color: $uni-bg-color; /* 不再随内容滚动 */ } /* 取消按钮 */ .zy-select-cancel { height: 57px; display: flex; align-items: center; justify-content: center; } .zy-select-cancel-text { font-size: $uni-font-size-18; color: $uni-text-color; text-align: center; font-weight: 400; } </style> 请你为当前组件设计插槽,注意这个组件是vue3小程序的项目使用的
09-19
<template> <view class='container'> <navbar class='navbar' title='选择充电'></navbar> <view class='header'> <text class='staion-name f-db'>{{form.stationName}}</text> <text class='address'>{{form.address || '暂无'}}</text> </view> <view class='main'> <view class="charge code-wrapper"> <view class='code'>桩编码:<text class='f-fwb'>{{form.pileId}}</text></view> <van-tag color="#E3E8FF" text-color="#5F7DF9" class='type'> <text class='type-label'>{{form.pileType == 1 ? '快充' : '慢充'}}</text> </van-tag> </view> <view class='charge'> <text class='port-title f-fwb f-db'>选择设备端口</text> <van-row class='f-tac' gutter="20"> <van-col :span='12' v-for='(item, index) in form.list' v-bind:key='index'> <van-button v-bind:plain='selected === index ? false : true' round v-bind:type="item.state == 'Y' ? 'default' : 'primary'" v-bind:disabled='item.state == "Y" || item.state == "F"' v-bind:class='selected === index ? "selected" : ""' class='port f-fwb' v-on:click='setport(index)'> <text class='port-num f-ib'>{{item.name}} </text> <text v-bind:class='item.state == "Y" ? "busy" : ""'>{{item.state == 'N' ? '空闲' : item.state == 'Y' ? '使用中' : '故障'}}</text> </van-button> </van-col> </van-row> </view> <view class='charge'> <text class='f-fwb f-db'>选择充电度数</text> <van-row gutter='20' class='f-tac'> <van-col :span='8' v-for='(item, index) in times' v-bind:key='index'> <view v-on:click='setime(index)'> <van-tag class='time' v-bind:class='activetime === index ? "active" : "default"' v-bind:color="activetime === index ? '#EEF1FF' : 'white'" v-bind:text-color="activetime === index ? '#5F7DF9' : '#666'">{{item}}{{'度'}}</van-tag> </view> </van-col> </van-row> </view> <view class='charge'> <text class='port-title f-fwb f-db'>计费标准</text> <text class='price-label f-db'>[尖] 13:00-24:00 电费:1.0044元/度,服务费:0.1元/度</text> <text class='price-label f-db'>[峰] 10:00-13:00 电费:1.0044元/度,服务费:0.1元/度</text> <text class='price-label f-db'>[平] 08:00-10:00 电费:0.695元/度,服务费:0.1元/度</text> <text class='price-label f-db'>[谷] 00:00-08:00 电费:0.3946元/度,服务费:0.1元/度</text> </view> </view> <view class='footer'> <van-button type='primary' v-on:click='start'>开始充电</van-button> </view> </view> </template> <style scoped> .container{ background: linear-gradient(-42deg, #E7FFFA, #EFF5FF, #FCFDEF); padding-top: 160rpx; min-height: calc(100vh - 80rpx); padding-bottom: 80rpx; } .main{ margin-left: 20rpx; margin-right: 20rpx; } .header{ margin-left: 20rpx; margin-right: 20rpx; padding: 20rpx; } .staion-name{ font-family: Microsoft YaHei; font-weight: bold; font-size: 36rpx; color: #17141B; line-height: 60rpx; margin-bottom: 20rpx; } .address{ color: #666; } .charge{ background-color: white; padding: 20rpx; border-radius: 20rpx; margin-top: 20rpx; } .code-wrapper{ display: flex; } .code{ flex: 1; font-size: 32rpx; margin-top: 6rpx; } .type-label{ height: 52rpx; line-height: 52rpx; padding-left: 20rpx; padding-right: 20rpx; } .port-title{ font-size: 32rpx; margin-bottom: 20rpx; } .port /deep/ .van-button--primary, .port /deep/ .van-button--default{ width: 100%; height: 80rpx; } .port-num{ font-size: 32rpx; margin-right: 4rpx; } .busy{ color: #F16A19; } .selected /deep/ .van-button--primary { background: linear-gradient(96deg, #569AFF, #5A8CFF); } .port /deep/ .van-button--primary { border: 2rpx solid #5F7DF9; color: white; } .port /deep/ .van-button--default { border: 2rpx solid #999; } .port /deep/ .van-button--plain.van-button--primary { background-color: white; color: #569AFF; } .time /deep/ .van-tag{ width: calc(100% - 20rpx); height: 80rpx; line-height: 80rpx; margin-top: 20rpx; font-size: 28rpx; display: inline-block; border-radius: 10rpx; } .active /deep/ .van-tag{ border: #5F7DF9 solid 2rpx; } .default /deep/ .van-tag{ border: #D8DCE0 solid 2rpx; } .popup{ padding: 20rpx; } .time-footer{ margin-top: 20rpx; } .time-footer /deep/ .van-button--small{ width: 80%; } .input{ width: calc(100% - 80rpx); margin: 20rpx auto; height: 60rpx; line-height: 60rpx; } .price-label{ color: #888; line-height: 48rpx; } .footer{ position: fixed; left: 0; bottom: 0; width: 100%; background-color: white; padding: 20rpx; } .footer /deep/ .van-button--primary { border: 2rpx solid #5F7DF9; color: white; background: linear-gradient(96deg, #569AFF, #4A6EF3); width: calc(100% - 40rpx); border-radius: 80rpx; } </style> <script setup> import { ref, reactive } from 'vue' import { onLoad } from '@dcloudio/uni-app' import navbar from '../../components/navbar/index.vue' import request from '../../components/js/request.js' const app = getApp() const selected = ref('') const setport = (index) => { selected.value = index } const form = reactive({}) const user = uni.getStorageSync('user') const token = uni.getStorageSync('token') const key = ref('') const show = (params) => { request({ url: '/charging/getChargingPileData', data: params, success: res => { for(let key in res.data.data){ form[key] = res.data.data[key] } } }) } const times = ref([ '10', '20', '30', '40', '50' ]) const activetime = ref(0) const customtimeshow = ref(false) const customtime = ref('') const setime = (index) => { activetime.value = index } const subtime = () => { if(customtime.value) { if(isNaN(customtime.value)) { uni.showToast({ title: '请输入数字', icon: 'none' }) }else{ if(times.value.includes(customtime.value)) { setime(times.value.indexOf(customtime.value)) }else{ if(times.value.length == 4) { times.value.push(customtime.value) }else{ times.value[times.value.length - 1] = customtime.value } setime(times.value.length - 1) } customtimeshow.value = false } }else{ uni.showToast({ title: '请输入自定义时间', icon: 'none' }) } } const start = () => { if(token) { if(selected.value === '') { uni.showToast({ title: '请选择设备端口', icon: 'none' }) }else{ request({ url: '/order/saveOrder', data: { amount: 50, hour: times.value[activetime.value] == '智能充满' ? 12 : times.value[activetime.value], portId: form.list[selected.value].portId, userId: user.memberId }, success: res => { if(res.data.code == 200) { uni.showToast({ title: '成功开启充电' }) setTimeout(() => { go(`/pages/station/powering?stationName=${form.stationName}&port=${res.data.data.portId}&pileId=${res.data.data.pileId}&portname=${form.list[selected.value].name}&orderNumber=${res.data.data.orderNumber}&hour=${res.data.data.hour}&delta=3`) }, 1500) }else{ uni.showToast({ title: '开始充电失败', icon: 'none' }) } } }) } }else{ uni.setStorageSync('redirecturl', '/pages/station/create?key=' + key.value) go('/pages/user/login') } } const go = (url) => { uni.navigateTo({ url: url }) } onLoad((option) => { key.value = option.key show(option) }) </script> 不改变逻辑,只美化界面
09-12
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值