写点什么

跨平台应用开发进阶 (七) :uni-app 自定义 showToast

  • 2022 年 5 月 20 日
  • 本文字数:4531 字

    阅读完需:约 15 分钟

跨平台应用开发进阶(七) :uni-app 自定义 showToast

一、前言

利用uni-app跨平台开发框架开发多终端APP时,应用HBuilder自身提供的弹窗不满足业务需求,故开发自定义弹窗组件 showToast。该组件主要实现以下功能:


  • 支持标题、内容、按钮自定义;

  • 支持根据按钮标识执行不同业务逻辑;

  • 支持内容自适应;

  • 支持弹窗关闭按钮自定义显示隐藏;


完整代码下载详参【拓展阅读】章节。

二、实现原理

应用自定义指令结合自定义组件实现视图渲染及控制逻辑,应用Vuex实现状态管理。


首先在main.js定义全局组件,并在initToast.js中注册$showToastVue原型上,以方便全局调用。


// 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中注册$showToastVue原型上实现逻辑如下:


// 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
用户头像

No Silver Bullet 2021.07.09 加入

岂曰无衣 与子同袍

评论

发布
暂无评论
跨平台应用开发进阶(七) :uni-app 自定义 showToast_uni-app_No Silver Bullet_InfoQ写作社区