1
跨平台应用开发进阶 (七) :uni-app 自定义 showToast
- 2022 年 5 月 20 日
本文字数:4531 字
阅读完需:约 15 分钟
一、前言
利用uni-app
跨平台开发框架开发多终端APP
时,应用HBuilder
自身提供的弹窗不满足业务需求,故开发自定义弹窗组件 showToast。该组件主要实现以下功能:
支持标题、内容、按钮自定义;
支持根据按钮标识执行不同业务逻辑;
支持内容自适应;
支持弹窗关闭按钮自定义显示隐藏;
完整代码下载详参【拓展阅读】章节。
二、实现原理
应用自定义指令结合自定义组件实现视图渲染及控制逻辑,应用Vuex
实现状态管理。
首先在main.js
定义全局组件,并在initToast.js
中注册$showToast
到Vue
原型上,以方便全局调用。
// main.js
import 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.js
import 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 加入
岂曰无衣 与子同袍
评论