基于uniapp+vue3多端「h5+小程序+App」仿微信/抖音直播商城|uni-app+vue3小视频

uniapp-vue3-welive一款uniapp+vue3+pinia跨端仿抖音直播商城实例。

全新基于uniapp+vue3+vite4+pinia等技术研发的一款跨平台仿制微信/抖音直播带货商城uniapp+vue3短视频实例项目,支持编译到h5+小程序+App端。

在这里插入图片描述

技术框架

  • 编辑器:HbuilderX 3.98
  • 框架技术:uniapp+vue3+vite4+nvue+pinia
  • UI组件库:uv-ui + vk-uview
  • 弹框组件:uaPopup(uniapp封装多端弹框组件)
  • 自定义组件:uaNavbar+uaTabbar组件
  • 本地缓存:pinia-plugin-unistorage
  • 编译支持:H5+小程序+APP端

在这里插入图片描述
在这里插入图片描述
welive-uniapp支持全端编译至H5+小程序端+App端。
在这里插入图片描述
uni-welive短视频+直播页面采用Nvue开发范式。

在这里插入图片描述

项目结构

在这里插入图片描述
项目整体采用uniapp vue3 setup语法编码开发。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

uniapp+vue3自定义导航栏navbar+菜单栏tabbar

在这里插入图片描述
在这里插入图片描述
这两个组件的vue2版本已经发布到了插件市场,如果大家有需要,可以去下载一次性拿走使用。

https://ext.dcloud.net.cn/plugin?id=5592
https://ext.dcloud.net.cn/plugin?id=5593

uniapp+vue3短视频模块

uniapp-welive项目小视频模块采用全屏沉浸式滑动效果。分为顶部固定tabs+视频区+底部视频信息浮层三大模块。

在这里插入图片描述

<ua-layout>
    <view class="ua__swipervideo flex1">
        <swiper
            class="ua__swipervideo-wrap flex1"
            :current="currentVideo"
            vertical
            :circular="true"
            :duration="200"
            @change="handleChange"
            @transition="handleTransition"
        >
            <swiper-item v-for="(item, index) in videoList" :key="index">
                <video
                    class="ua__swipervideo-player flex1"
                    :id="'uplayer' + index"
                    :src="item.src"
                    :danmu-list="item.danmu"
                    :enable-danmu="true"
                    :controls="false"
                    :loop="true"
                    :autoplay="index == currentVideo"
                    :show-center-play-btn="false"
                    object-fit="contain"
                    @click="handleClickVideo"
                    @play="isPlaying=true"
                    @timeupdate="handleTimeUpdate"
                    :style="{'width': `${winWidth}px`, 'height': `${winHeight}px`}"
                >
                </video>
                
                <!-- 浮层模块 -->
                <view class="ulive__video-float__info flexbox flex-col">
                    <view class="flexbox flex-row flex-alignb">
                        <!-- 左侧 -->
                        <view class="vdinfo__left flex1 flexbox flex-col">
                            <view class="ltrow danmu flexbox" @click="handleOpenDanmu"><text class="danmu-txt"></text><uv-icon class="ico" name="edit-pen" color="#fff" size="14" /></view>
                            <view class="ltrow"><text class="ait">@{{item.author}}</text></view>
                            <view class="ltrow"><text class="desc">{{item.desc}}</text></view>
                        </view>
                        <!-- 右侧操作栏 -->
                        <view class="vdinfo__right flexbox flex-col">
                            <view class="rtbtn avatar flexbox flex-col">
                                <view class="ubox"><image class="uimg" :src="item.avatar" mode="aspectFill" /></view>
                                <view class="btn flexbox" :class="{'active': item.isFollow}" @click="handleFollow(index)"><uv-icon :name="item.isFollow ? 'checkmark' : 'plus'" :color="item.isFollow ? '#ff007f' : '#fff'" size="11" /></view>
                            </view>
                            <view class="rtbtn flexbox flex-col" @click="handleLiked(index)"><uv-icon name="heart-fill" :color="item.isLike ? '#ff007f' : '#fff'" size="40" /><text class="num">{{item.likeNum+(item.isLike ? 1 : 0)}}</text></view>
                            <view class="rtbtn flexbox flex-col" @click="handleOpenComment(index)"><uv-icon name="chat-fill" color="#fff" size="40" /><text class="num">{{item.replyNum}}</text></view>
                            <view class="rtbtn flexbox flex-col"><uv-icon name="star-fill" color="#fff" size="40" /><text class="num">{{item.starNum}}</text></view>
                            <view class="rtbtn flexbox flex-col" @click="handleOpenShare(index)"><uv-icon name="share-fill" color="#fff" size="40" /><text class="num">{{item.shareNum}}</text></view>
                        </view>
                    </view>
                </view>
            </swiper-item>
        </swiper>
        
        <!-- 固定tabs(脱离滑动区) -->
        <view class="ulive__video-header__tabs" :style="{'margin-top': `${menuBarT}px`}">
            <uv-tabs :current="tabsCurrent" :list="tabsList" />
        </view>
        
        <!-- 播放暂停按钮 -->
        <view v-if="!isPlaying" class="ua__swipervideo-playbtn" :style="{'left': `${winWidth/2}px`, 'top': `${winHeight/2}px`}" @click="handleClickVideo">
            <text class="ua__swipervideo-playico welive-icon welive-icon-play nvueicon"></text>
        </view>
        <!-- 播放mini进度条 -->
        <view class="ua__swipervideo-progress" :style="{'width': `${winWidth}px`}"><view class="ua__swipervideo-progressbar" :style="{'width': `${progressBar}px`}"></view></view>
    </view>
    
    <template #footer>
        <ua-tabbar bgcolor="transparent" color="rgba(255,255,255,.7)" :border="false" :dock="false" transparent z-index="1000" />
    </template>
</ua-layout>

底部tabbar上面有一条迷你型小视频播放进度条。
在这里插入图片描述

<script setup>
    import { ref, computed, getCurrentInstance } from 'vue'
    import { onShow, onHide } from '@dcloudio/uni-app'
    import { getRandomColor } from '@/utils'
    
    // ...
    
    const { globalData } = getApp()
    const menuBarT = ref(globalData.menu?.top || globalData.statusBarH)
    const winWidth = ref(globalData.screenWidth)
    const winHeight = ref(globalData.screenHeight)
    
    const tabsList = ref([
        { name: '推荐', count: 5 },
        { name: '关注' },
        { name: '同城' }
    ])
    const tabsCurrent = ref(0)
    
    // 视频参数
    const currentVideo = ref(0)
    const isPlaying = ref(false)
    const clickNum = ref(0)
    const clickTimer = ref(null)
    const progressBar = ref(0)
    
    // 视频源
    const videoList = ref(videoJson)
    const danmuEditor = ref('')
    const isVisibleDanmu = ref(false)
    const commentRef = ref(null)
    const shareRef = ref(null)
    
    // ...
    
    
    /**
     * ====================== 视频播放模块 ======================
    */
    // 创建并返回 video 上下文 videoContext 对象
    const getVideoContext = () => {
        // return uni.createVideoContext(`uplayer${currentVideo.value}`, this)
        return uni.createVideoContext(`uplayer${currentVideo.value}`, getCurrentInstance())
    }
    
    // 垂直滑动视频,滑动改变时会触发 change 事件
    const handleChange = (e) => {
        const index = e.detail.current
        progressBar.value = 0
        handleReset()
        
        currentVideo.value = index
        // 播放
        handlePlay()
    }
    
    // 播放
    const handlePlay = () => {
        console.log('video play')
        let video = getVideoContext()
        if(!video) return
        video.play()
        isPlaying.value = true
    }
    
    // 暂停
    const handlePause = () => {
        console.log('video pause')
        let video = getVideoContext()
        if(!video) return
        video.pause()
        isPlaying.value = false
    }
    
    // 重置播放
    const handleReset = () => {
        console.log('video reset')
        let video = getVideoContext()
        if(!video) return
        video.pause()
        video.seek(0)
        video.stop()
        isPlaying.value = false
    }
    
    // 监听播放进度条
    const handleTimeUpdate = (e) => {
        let { currentTime, duration } = e.detail
        progressBar.value = parseInt((currentTime / duration).toFixed(2) * parseInt(winWidth.value))
    }
    
    // 点击视频(监听单双击)
    const handleClickVideo = () => {
        console.log('video click')
        clearTimeout(clickTimer.value)
        clickNum.value++
        clickTimer.value = setTimeout(() => {
            if(clickNum.value >= 2) {
                console.log('double click')
            }else {
                if(isPlaying.value) {
                    handlePause()
                }else {
                    handlePlay()
                }
            }
            clickNum.value = 0
        }, 200)
    }
    
    
    /**
     * ====================== 其它功能模块 ======================
    */
    // 打开弹幕弹框
    const handleOpenDanmu = () => {
        isVisibleDanmu.value = true
    }
    // 关闭弹幕弹框
    const handleCloseDanmu = () => {
        uni.hideKeyboard()
        isVisibleDanmu.value = false
        danmuEditor.value = ''
    }
    // 发送弹幕
    const handleSendDanmu = () => {
        let video = getVideoContext()
        if(!video) return
        video.sendDanmu({
            text: danmuEditor.value,
            color: getRandomColor()
        })
        handleCloseDanmu()
    }
    
    // 打开评论框
    const handleOpenComment = (index) => {
        commentRef.value.open()
    }
    
    // ...

</script>
注意:在uniapp+vue3中没有this上下文,只能通过如下方式获取视频上下文实例。
uni.createVideoContext(`uplayer${currentVideo.value}`, getCurrentInstance())

uniapp+vue3仿抖音/微信直播

直播模块分为顶部信息条+直播流媒体区+滚动消息(加入直播间+送礼物+讲解商品)+底部toolbar栏

在这里插入图片描述
在这里插入图片描述

<ua-layout>
    <view class="ua__swipervideo flex1">
        <swiper
            class="ua__swipervideo-wrap flex1"
            :current="currentLive"
            vertical
            @change="handleChange"
        >
            <swiper-item v-for="(item, index) in liveList" :key="index">
                <video
                    class="ua__swipervideo-player flex1"
                    :id="'uplayer' + index"
                    :src="item.src"
                    :controls="false"
                    :loop="true"
                    :autoplay="index == currentLive"
                    :show-center-play-btn="false"
                    object-fit="contain"
                    :style="{'width': `${winWidth}px`, 'height': `${winHeight}px`}"
                >
                </video>
                
                <!-- 浮层模块 -->
                <swiper class="ulive__swiperscreen flex1" :current="1">
                    <!-- 清屏 -->
                    <swiper-item>
                        第一屏
                    </swiper-item>
                    <swiper-item>
                        <!-- 顶部区域 -->
                        <view class="ulive__headlayer" :style="{'top': menuBarT+'px'}">
                            <!-- logo+关注 -->
                            <view class="ulive__hd-liveinfo flexbox flex-row flex-alignc">
                                <view class="ulive__hd-avatar ulive__mask flex-alignc">
                                    <image class="logo" :src="item.logo" mode="widthFix" />
                                    <view class="flex1 flexbox flex-col ml-10">
                                        <text class="name">{{item.name}}</text>
                                        <text class="zan">{{item.likeNum}}本场点赞</text>
                                    </view>
                                    <view class="btn flexbox flex-row flex-alignc" :class="{'active': item.isFollow}" @click="handleFollow(index)"><text class="btntext" :class="{'active': item.isFollow}">{{item.isFollow ? '已关注' : '关注'}}</text></view>
                                </view>
                                <view class="ulive__hd-onlineuser flex1">
                                    <uv-icon name="close" color="#fff" @click="handleLiveQuit" />
                                </view>
                            </view>
                            <view class="ulive__hd-livewrap flexbox flex-row">
                                <view class="ulive__hd-livewrap__left flex1 flexbox flex-col">
                                    <view class="ulive__hd-livewrap__tags flexbox flex-row">
                                        <view class="ulive__roundwrap ulive__mask">
                                            <uv-icon name="shopping-cart" color="#ffdd1a" /><text class="ulive__roundtext">服饰鞋包榜第1</text>
                                        </view>
                                        <view class="ulive__roundwrap ulive__mask ml-10">
                                            <uv-icon name="level" color="#ffdd1a" /><text class="ulive__roundtext">小时榜</text>
                                        </view>
                                    </view>
                                    <!-- 红包+福袋倒计时 -->
                                    <view class="ulive__hd-livewrap__redpacket flexbox flex-row">
                                        <view class="ulive__redpacket-item ulive__mask" @click="handleOpenRedpacket(1)">
                                            <image class="ulive__redpacket-image" src="/static/icon-fudai.png" mode="widthFix" /><text class="ulive__redpacket-time">04:49</text>
                                        </view>
                                        <view class="ulive__redpacket-item ulive__mask" @click="handleOpenRedpacket(2)">
                                            <image class="ulive__redpacket-image" src="/static/icon-hb.png" mode="widthFix" /><text class="ulive__redpacket-time">04:49</text>
                                        </view>
                                        <view class="ulive__redpacket-item ulive__mask center">
                                            <image class="ulive__redpacket-image" src="/static/icon-rotate.png" mode="widthFix" /><text class="ulive__redpacket-time">04:49</text>
                                        </view>
                                    </view>
                                </view>
                                <view class="ulive__hd-livewrap__right flexbox flex-col">
                                    <view class="ulive__roundwrap ulive__mask mr-20">
                                        <uv-icon name="kefu-ermai" color="#fff" /><text class="ulive__roundtext ml-5">后台</text>
                                    </view>
                                </view>
                            </view>
                        </view>
                        
                        <!-- 底部区域 -->
                        <view class="ulive__footlayer">
                            <!-- 商品提示层 -->
                            <view class="ulive__ft-livewrap-placeholder animated fadeIn">
                                <view class="ulive__ft-livewrap-hotbuy flexbox flex-row">
                                    <image class="gimg" :src="item.poster" mode="aspectFill" />
                                    <view class="ginfo flex1">
                                        <view class="flexbox flex-row"><text class="user c-ffdd1a">Andy</text><text class="c-fff">{{item.saleNum}}人在购买</text></view>
                                        <text class="gdesc clamp1">{{item.desc}}</text>
                                    </view>
                                    <view class="btn"><text class="btntext">去购买</text></view>
                                </view>
                            </view>
                            <!-- 加入直播间/送礼物提示 -->
                            <view class="ulive__ft-livewrap-animateview flexbox flex-col">
                                <view class="ulive__ft-livewrap-animatejoin ulive__ft-livewrap-placeholder">
                                    <view v-if="joinRoomData" class="ulive__ft-livewrap-joinroom"><text class="ulive__ft-livewrap-joinroom__text">欢迎{{joinRoomData}}加入了直播间</text></view>
                                </view>
                                
                                <!-- 送礼物 -->
                                <view class="ulive__ft-livewrap-animategift ulive__ft-livewrap-placeholder">
                                    <view v-if="!isEmpty(sendGiftData)" class="ulive__ft-livewrap-activegift flexbox flex-row flex-alignc">
                                        <image class="avatar" :src="sendGiftData.avatar" />
                                        <view class="info flex1"><text class="name">{{sendGiftData.user}}</text><text class="desc">送出</text></view>
                                        <image class="gift" :src="sendGiftData.pic" />
                                    </view>
                                </view>
                            </view>
                            <!-- 聊天浮层+商品讲解 -->
                            <view class="ulive__ft-livewrap-mixinview flexbox flex-row">
                                <!-- 聊天消息 -->
                                <view class="ulive__ft-livewrap-chats flex1">
                                    <scroll-view class="ulive__ft-livewrap-chats__scrollview flex1" scroll-y show-scrollbar="false" :scroll-into-view="scrollToView" :lower-threshold="5" @scroll="handleMsgScroll" @scrolltolower="handleMsgScrollLower">
                                        <block v-for="(msgitem, msgidx) in item.message" :key="msgidx">
                                            <view v-if="msgitem.type == 'notice'" class="notice" :id="`msg-${msgitem.id}`"><view class="item"><text class="noticetext">{{msgitem.content}}</text></view></view>
                                            <view v-else-if="msgitem.type == 'gift'" class="gift" :id="`msg-${msgitem.id}`">
                                                <view class="item">
                                                    <text class="giftuser">{{msgitem.user}}</text>
                                                    <text class="gifttext">送出了{{msgitem.content}}</text>
                                                    <image class="giftimg" :src="msgitem.img" mode="widthFix" />
                                                    <text class="giftnum">x{{msgitem.num}}</text>
                                                </view>
                                            </view>
                                            <view v-else class="msg" :id="`msg-${msgitem.id}`">
                                                <view class="item">
                                                    <text v-if="msgitem.tag" class="tag">{{msgitem.tag}}</text>
                                                    <text class="user">{{msgitem.user}}</text>
                                                    <text class="text" :style="[fixTextStyle]">{{msgitem.isbuy ? '正在购买' : msgitem.content}}</text>
                                                    <text v-if="msgitem.isbuy" class="tag tag-buy">去购买</text>
                                                </view>
                                            </view>
                                        </block>
                                    </scroll-view>
                                    <view v-if="!isEmpty(msgUnread)" class="ulive__ft-livewrap-chats__unread" @click="handleMsgIsRead"><text class="c-eb4868 fs-24">{{msgUnread.length}}条新消息</text></view>
                                </view>
                                <!-- 商品讲解 -->
                                <view v-if="isVisibleGoodsTalk" class="ulive__ft-livewrap-activegoods animated fadeInRight" id="goodsTalkID">
                                    <view class="ulive__ft-livewrap-activegoods__hotsale flexbox flex-row">
                                        <image class="fimg" src="/static/icon-hot.png" mode="widthFix" /><text class="c-fff fs-32">热卖 x{{item.saleNum}}</text>
                                    </view>
                                    <swiper class="ulive__ft-livewrap-activegoods__swiper">
                                        <swiper-item>
                                            <view class="ulive__ft-livewrap-activegoods__card">
                                                <view class="gwrap" @click="toGoodsDetail">
                                                    <image class="gimg" :src="item.poster" mode="aspectFill" />
                                                    <view class="waves"><text class="c-fff fs-24">讲解中</text></view>
                                                    <view class="close" @click.stop="isVisibleGoodsTalk=false"><uv-icon name="close-circle-fill" color="rgba(0, 0, 0, .3)" size="14" /></view>
                                                </view>
                                                <view class="ginfo flexbox flex-col">
                                                    <text class="clamp1 fs-24">{{item.desc}}</text>
                                                    <text class="clamp1 fs-24 c-eb4868">7天无理由退货</text>
                                                </view>
                                                <view class="btn flexbox flex-row"><text class="flex1 c-fff fs-28">79.00</text><text class="qiang"></text></view>
                                            </view>
                                        </swiper-item>
                                    </swiper>
                                </view>
                            </view>
                            <!-- 工具栏 -->
                            <view class="ulive__ft-livewrap-toolbar flexbox flex-row">
                                <view class="editorwrap flex1 flexbox flex-row flex-alignc">
                                    <view class="flex1" @click="handleOpenChatbox"><text class="editorwrap-text">说点什么...</text></view>
                                </view>
                                <view class="btnwrap flexbox flex-row">
                                    <view class="btn flexbox" @click="handleOpenMenus"><uv-icon name="grid" color="#3c9cff" size="22" /></view>
                                    <view class="btn flexbox" @click="handleOpenGoods(item)"><uv-icon name="shopping-cart-fill" color="#ffaa00" size="24" /></view>
                                    <view class="btn flexbox" @click="handleOpenGifts"><uv-icon name="gift" color="#ff0ad3" size="22" /></view>
                                    <view class="btn flexbox"><uv-icon name="more-dot-fill" color="#efe9ff" size="18" /></view>
                                </view>
                            </view>
                        </view>
                    </swiper-item>
                </swiper>
            </swiper-item>
        </swiper>
    </view>
</ua-layout>

由于短视频及直播页面采用Nvue编码,vk-uview组件库不支持nvue,有些组件则是使用uv-ui组件库(支持nvue)。

OK,以上就是uniapp+vue3开发跨端直播商城项目的一些分享。

最后附上两个实例项目

在这里插入图片描述

### 回答1: Uniapp Vue3 TS中创建项目的详细过程如下:1.首先,安装Vue CLI,这是一个用于构建Vue应用程序的命令行界面工具;2.安装uniapp,使用npm或者yarn安装uniapp;3.使用Vue CLI创建一个新的Vue应用;4.在Vue应用中安装uniapp;5.使用uniapp CLI安装需要的组件;6.使用uniapp CLI构建项目;7.使用uniapp CLI运行项目;8.部署应用程序。 ### 回答2: 在UniApp中使用Vue3和TypeScript创建一个项目的详细过程如下: 1. 环境准备:确保已安装Node.js和npm包管理器,然后使用命令行工具执行以下命令安装UniApp CLI工具:`npm install -g @vue/cli @vue/cli-init` 2. 创建项目:在命令行中执行以下命令创建一个UniApp项目:`vue create -p dcloudio/uni-preset-vue@next your-project-name`。 3. 过程中会提示选择预设(Presets)类型,选择"Manually select features"手动选择特性。 4. 选择特性:通过方向键选择"TypeScript"并按空格进行选择,然后按Enter键确认。 5. 选择样式预处理器(Stylus/Sass/Less):根据需要选择相应的样式预处理器,或选择"None"不使用。 6. 选择静态资源目录:根据需要选择存放静态资源的目录,或选择默认值。 7. 选择ESLint代码检查工具和配置:根据需要选择是否使用ESLint检查代码规范,以及设置相应的规则。 8. 选择保存配置或预设:根据个人需要选择是否保存配置或使用预设。 9. 安装依赖:根据命令行提示,在项目根目录下执行`npm install`命令安装项目所需的依赖。 10. 启动开发服务器:依然在命令行中执行`npm run dev:%PLATFORM%`(%PLATFORM%为平台标识,如h5app-plus等),启动开发服务器,进行项目开发。 11. 创建页面:在项目的`src/pages/`目录下创建相应的页面,例如`src/pages/index/`,并在该目录下创建`index.vue`作为页面的入口文件。 12. 编写代码:使用Vue3和TypeScript编写页面逻辑和样式代码。 13. 预览页面:在开发服务器启动后,打开浏览器,访问相应的开发链接(如http://localhost:%PORT%)即可预览页面效果。 14. 进行开发和测试:根据需求,在页面中添加事件处理、数据请求等逻辑,并进行开发和测试。 15. 打包发布:完成页面开发和测试后,执行相应的命令进行打包发布。例如使用`npm run build:%PLATFORM%`(%PLATFORM%为平台标识,如h5app-plus等)命令打包相应平台的代码。 以上就是在UniApp中使用Vue3和TypeScript创建项目的详细过程。根据个人需求和项目的特点,还可以进一步配置和调整相应的开发环境、插件和工具等。 ### 回答3: 在Uniapp中使用Vue3和TypeScript创建一个项目的详细过程如下: 1. 首先,确保已经安装了Node.js和npm(Node.js自带)。 2. 打开终端命令行窗口,进入要创建项目的文件夹。 3. 运行以下命令安装uniapp-cli: ``` npm install -g @vue/cli @vue/cli-init ``` 4. 使用以下命令创建一个新的uniapp项目: ``` vue create -p dcloudio/uni-preset-vue my-project ``` 5. 创建过程中会提示选择预设配置,选择"Manually select features"并按回车。 6. 在选择特性的界面上,选择"TypeScript"并按回车。 7. 继续选择其他你需要的特性,或者直接按回车跳过。 8. 等待项目依赖安装完成。 9. 进入项目文件夹: ``` cd my-project ``` 10. 运行以下命令启动开发服务器: ``` npm run dev:mp-weixin ``` 11. 打开微信开发者工具,导入项目。 在微信开发者工具中,选择"导入项目",然后选择项目文件夹。 12. 选择小程序开发目录为项目文件夹中的`dist/dev/mp-weixin`文件夹。 13. 点击确定,等待项目导入完成。 14. 点击微信开发者工具的"编译"按钮,以确保项目成功运行。 通过以上步骤,你已经成功创建了一个基于UniappVue3和TypeScript项目,并且可以在微信开发者工具中进行调试和开发。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiaoyan_2018

你的鼓励将是我持续作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值