1
跨平台应用开发进阶 (七) :uni-app 自定义 showToast
- 2022 年 5 月 20 日
本文字数:4531 字
阅读完需:约 15 分钟

一、前言
利用uni-app跨平台开发框架开发多终端APP时,应用HBuilder自身提供的弹窗不满足业务需求,故开发自定义弹窗组件 showToast。该组件主要实现以下功能:
支持标题、内容、按钮自定义;
支持根据按钮标识执行不同业务逻辑;
支持内容自适应;
支持弹窗关闭按钮自定义显示隐藏;
完整代码下载详参【拓展阅读】章节。
二、实现原理
应用自定义指令结合自定义组件实现视图渲染及控制逻辑,应用Vuex实现状态管理。
首先在main.js定义全局组件,并在initToast.js中注册$showToast到Vue原型上,以方便全局调用。
// main.jsimport initToast from "@/components/bocft-toast/initToast.js"import showToast from "@/components/bocft-toast/bocft-toast.vue"
initToast(Vue);Vue.component('show-toast',showToast);
复制代码
三、代码实现
initToast.js中注册$showToast到Vue原型上实现逻辑如下:
// initToast.jsimport Vuex from 'vuex'export default function initToast(v) { // 挂在store到全局Vue原型上 v.prototype.$toastStore = new Vuex.Store({ state: { show:false, icon:"success",//success:成功;fail:失败 title:"标题", content:'内容', success:null, downLoadUrl:null, toastCloseIconShow: '', toastCloseIconStyle: '', ...... }, mutations: { hideToast(state) { // 小程序导航条页面控制 // #ifndef H5 if(state.hideTabBar){ wx.showTabBar(); } // #endif state.show = false; }, // 按钮1方法 buttonOneClick(state, data) { let _this = this; console.log('data.flag:', data.flag) switch (data.flag) { case 'hide': state.show = false; break; ...... } }, // 按钮2方法 buttonTwoClick(state, data) { let _this = this; this.progress = 0; this.upshow = true; //切换进度条显示 switch (data.flag) { case 'reload': state.show = false; break; } }, close() { this.show2 = false; //关闭更新弹窗 this.upshow = false; //关闭进度条 uni.showTabBar(); //显示tabbar this.$emit('closeVersion');//关闭show组件 }, showToast(state,data) { state = Object.assign(state,data) console.log('state:', state); state.show = true // 按钮不展示时,延时2S隐藏提示框 if (!state.buttonShow) { setTimeout(()=>{ state.show = false return state.success(state.icon) },2000) } }, success(state,data) { // state = Object.assign(state,data) // console.log(state); // state.show = true // setTimeout(()=>{ // state.show = false // return state.success(state.icon) // },2000) } } }) // 注册$showToast到Vue原型上,以方便全局调用 v.prototype.$showToast = function (option) { if (typeof option === 'object') { // #ifndef H5 if(option.hideTabBar){ wx.hideTabBar(); } // #endif console.log('-------------option------------', option) v.prototype.$toastStore.commit('showToast', option) }else{ throw "配置项必须为对象传入的值为:"+typeof option; } }}
复制代码
视图渲染逻辑如下:
// toast.vue<template> <view :class="buttonShow ? 'showToast' : '_showToast'" class="prompt-box" v-show="show" @touchmove.stop.prevent="moveHandle"> <!-- 弹窗关闭按钮 --> <view v-if="toastCloseIconShow" @tap='closeToast'> <image class="Toast-close-icon" :style="{top: toastCloseIconStyle.top}" src='@/static/guanbi.png'></image> </view> <view class="_shade"> </view> <view class="_ToastBox"> <view class="Toast-box" :style="{minHeight: toastBoxStyle.minHeight, borderRadius: toastBoxStyle.borderRadius, top: toastBoxStyle.top, background: toastBoxStyle.background}"> <view style="height: 10px;"></view> <!-- 成功图片 --> <image v-if="icon=='success' && successImgSrc != ''" :style="{width: successImgClass.width, height: successImgClass.height }" class="Toast-icon" :src='successImgSrc'></image> <!-- 成功标题 --> <text v-if="icon=='success'" class="Toast-title-success" :style="{fontSize: toastTitleSuccessStyle.fontSize, fontWeight: toastTitleSuccessStyle.fontWeight, top: toastTitleSuccessStyle.top }">{{title}}</text> <!-- 失败图片 --> <image v-if="icon=='fail'" class="Toast-icon" :src='failImgSrc' :style="{width: failImgClass.width, height: failImgClass.height }"></image> <!-- 失败标题 --> <text v-if="icon=='fail'" class="Toast-title-fail" :style="{top: toastTitleFailStyle.top}">{{title}}</text> <!-- 提示内容 --> <text class="Toast-subtitle" :style="{top: toastTitleSuccessStyle.toastSubtitleTop, color: toastTitleSuccessStyle.contentFontColor, fontSize: toastTitleSuccessStyle.contentFontSize}">{{content}}</text> <!-- 按钮组 --> <view v-if="buttonShow" class="buttonShowClass" :style="{top: buttonShowStyle.top}"> <!-- 按钮1 --> <view v-if="buttonOneShow" class="sendBtn" :style="{fontFamily: buttonShowStyle.fontFamily, fontSize: buttonShowStyle.fontSize, color: buttonShowStyle.color, backgroundImage: buttonShowStyle.backgroundImage, borderTop: buttonShowStyle.borderTop, width: buttonShowStyle.width, borderRadius: buttonShowStyle.borderRadius, color: buttonOneTitleStyle.color, fontWeight: buttonOneTitleStyle.fontWeight}" @tap="buttonOneClick(buttonOneClickParam)">{{buttonOneTitle}}</view> <!-- 按钮2 --> <view v-if="buttonTwoShow" class="sendBtn" :style="{fontFamily: buttonShowStyle.fontFamily, fontSize: buttonShowStyle.fontSize, color: buttonShowStyle.color, backgroundImage: buttonShowStyle.backgroundImage, borderTop: buttonShowStyle.borderTop, width: buttonShowStyle.width, borderRadius: buttonShowStyle.borderRadius }" @tap="buttonTwoClick(buttonTwoClickParam)">{{buttonTwoTitle}}</view> </view> <view> <progress :percent="percent" stroke-width="10"></progress> </view> </view> </view> </view></template>
<script> export default { name:"show-toast", data() { return { percent: 0, }; }, computed: { show(){ return this.$toastStore.state.show; }, title(){ return this.$toastStore.state.title; }, content(){ return this.$toastStore.state.content; }, icon(){ return this.$toastStore.state.icon; }, downLoadUrl(){ return this.$toastStore.state.downLoadUrl; }, toastCloseIconShow(){ return this.$toastStore.state.toastCloseIconShow; }, toastCloseIconStyle(){ return this.$toastStore.state.toastCloseIconStyle; }, buttonShow(){ return this.$toastStore.state.buttonShow; }, buttonOneShow(){ return this.$toastStore.state.buttonOneShow; }, buttonTwoShow(){ return this.$toastStore.state.buttonTwoShow; }, buttonOneTitleStyle(){ return this.$toastStore.state.buttonOneTitleStyle; }, toastBoxStyle(){ return this.$toastStore.state.toastBoxStyle; }, toastTitleSuccessStyle(){ return this.$toastStore.state.toastTitleSuccessStyle; }, toastTitleFailStyle(){ return this.$toastStore.state.toastTitleFailStyle; }, buttonShowStyle(){ return this.$toastStore.state.buttonShowStyle; }, buttonOneClickParam(){ return this.$toastStore.state.buttonOneClickParam; }, buttonTwoClickParam(){ return this.$toastStore.state.buttonTwoClickParam; }, successImgSrc(){ return this.$toastStore.state.successImgSrc; }, failImgClass(){ return this.$toastStore.state.failImgClass; }, successImgClass(){ return this.$toastStore.state.successImgClass; }, failImgSrc(){ return this.$toastStore.state.failImgSrc; }, buttonOneTitle(){ return this.$toastStore.state.buttonOneTitle; }, buttonTwoTitle(){ return this.$toastStore.state.buttonTwoTitle; } }, mounted() { setTimeout(()=>{ this.$toastStore.commit('hideToast') this.$toastStore.commit('success',"confirm") },2000) }, methods:{ buttonOneClick(param){ this.$toastStore.commit('buttonOneClick', {flag: param}) }, buttonTwoClick(param){ this.$toastStore.commit('buttonTwoClick', {flag: param, url: this.downLoadUrl}) }, closeToast(){ this.$toastStore.commit('hideToast') }, clickBtn(res){ this.$toastStore.commit('hideToast') this.$toastStore.commit('success',res) }, moveHandle(){ return; } }, beforeDestroy(){ this.$toastStore.commit('hideToast') }, }</script>
复制代码
四、拓展阅读
划线
评论
复制
发布于: 刚刚阅读数: 3
版权声明: 本文为 InfoQ 作者【No Silver Bullet】的原创文章。
原文链接:【http://xie.infoq.cn/article/ae6a0311f0171c63b47152b3d】。文章转载请联系作者。
No Silver Bullet 2021.07.09 加入
岂曰无衣 与子同袍










评论