React实现全局组件的Toast轻提示效果

Toast是常用的轻提示弹框,常用于页面loading和提示语弹窗。

本例基于React实现一个随时可调用且不随页面渲染的全局组件。

需求分析

  • Toast 不需要同页面一起被渲染,而是根据需要被随时调用。
  • Toast 是一个轻量级的提示组件,它的提示不会打断用户操作,并且会在提示的一段时间后自动关闭。
  • Toast 需要提供几种不同的消息类型以适应不同的使用场景。
  • Toast 的方法必须足够简洁,以避免不必要的代码冗余。

如何使用

首先引入

import Toast from './components/toast'

JSX中事件调用:

<button onClick={() => { Toast.info('普通提示') }}>普通提示</button>

JS中方法调用:

Toast.info('普通提示')

回调方法:

const hideLoading = Toast.loading('加载中...', 0, () => {
  Toast.success('加载完成')
})
setTimeout(hideLoading, 2000)

调用规则:

3个参数:

  • content 提示内容 string(loading方法为可选)
  • duration 提示持续时间 number,单位ms(可选)
  • onClose 提示关闭时的回调函数(可选)
Toast.info("普通",2000)
Toast.success("成功",1000,() => {
  console.log('回调方法')
}))
Toast.error("错误")
Toast.loading()

代码实现

目录结构:

  1. index.js:对外export接口,设置默认的参数值,全局创建或销毁Toast的DIV。
  2. toast.js:Toast具体显示的内容及多次调用Toast时的状态管理。
  3. toast.css:Toast的样式,费话不多说。

index.js:

import React from 'react'
import ReactDOM from 'react-dom'
import Toast from './toast'
import './toast.css'

function createNotification() {
  const div = document.createElement('div')
  document.body.appendChild(div)
  const notification = ReactDOM.render(<Toast />, div)
  return {
    addNotice(notice) {
      return notification.addNotice(notice)
    },
    destroy() {
      ReactDOM.unmountComponentAtNode(div)
      document.body.removeChild(div)
    }
  }
}

let notification
const notice = (type, content, duration = 2000, onClose) => {
  if (!notification) notification = createNotification()
  return notification.addNotice({ type, content, duration, onClose })
}

export default {
  info(content, duration, onClose) {
    return notice('info', content, duration, onClose)
  },
  success(content = '操作成功', duration, onClose) {
    return notice('success', content, duration, onClose)
  },
  error(content, duration , onClose) {
    return notice('error', content, duration, onClose)
  },
  loading(content = '加载中...', duration = 0, onClose) {
    return notice('loading', content, duration, onClose)
  }
}

toast.js:

import React, { Component } from 'react'

class ToastBox extends Component {
  constructor() {
    super()
    this.transitionTime = 300
    this.state = { notices: [] }
    this.removeNotice = this.removeNotice.bind(this)
  }

  getNoticeKey() {
    const { notices } = this.state
    return `notice-${new Date().getTime()}-${notices.length}`
  }

  addNotice(notice) {
    const { notices } = this.state
    notice.key = this.getNoticeKey()

    // notices.push(notice);//展示所有的提示
    notices[0] = notice;//仅展示最后一个提示

    this.setState({ notices })
    if (notice.duration > 0) {
      setTimeout(() => {
        this.removeNotice(notice.key)
      }, notice.duration)
    }
    return () => { this.removeNotice(notice.key) }
  }

  removeNotice(key) {
    const { notices } = this.state
    this.setState({
      notices: notices.filter((notice) => {
        if (notice.key === key) {
          if (notice.onClose) setTimeout(notice.onClose, this.transitionTime)
          return false
        }
        return true
      })
    })
  }

  render() {
    const { notices } = this.state
    const icons = {
      info: 'toast_info',
      success: 'toast_success',
      error: 'toast_error',
      loading: 'toast_loading'
    }
    return (
      <div className="toast">
        {
          notices.map(notice => (
            <div className="toast_bg" key={notice.key}>
              <div className='toast_box'>
                <div className={`toast_icon ${icons[notice.type]}`}></div>
                <div className='toast_text'>{notice.content}</div>
              </div>
            </div>
          ))
        }
      </div>
    )
  }
}

export default ToastBox

toast.css:

.toast {
 position: fixed;
 left: 0;
 top: 0;
 z-index: 999;
 display: flex;
 flex-direction: column; }
 .toast_bg {
  position: fixed;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0; }
 .toast_box {
  position: relative;
  left: 50%;
  top: 50%;
  width: 2.8rem;
  height: 2rem;
  margin: -1rem -1.4rem;
  background: rgba(0, 0, 0, 0.65);
  border-radius: .1rem;
  color: #fff; }
 .toast_text {
  position: absolute;
  bottom: 16%;
  text-align: center;
  width: 90%;
  margin: 0 5%;
  height: .28rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap; }
 .toast_icon {
  position: relative;
  left: 50%;
  top: 15%;
  margin: -.4rem;
  width: .8rem;
  height: .8rem; }
 .toast_loading {
  -webkit-animation: loading 1s steps(12, end) infinite;
  animation: loading 1s steps(12, end) infinite;
  background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAM1BMVEUAAAD///////////////////////////////////////////////////////////////+3leKCAAAAEHRSTlMAENCA8KAgsGDgQMCQUDBwhylaLQAAAL1JREFUOMu9U0kSwyAMK9jsS/T/1zZt2pgEZzq9RBeMZYRGDI/70bO5JptjrOAQVTonIJVK5bW2ma9A7VvpK8OdeQfbZectrDnyU+Oo0b68wGK0muDPdxpOciaizq5pkAgiIPAoew2rBVNYZoM2YHbZDNKz/2Ogam3ff5gMEL8wisfh2KKZiFiGWFkk1B7NSbhNQFy4M2+PghbODNsg7y8THM2njiy8gBgcaEUA9GgNJbxh6fJv+NxiFvYmPAFtCQZNK1qZIAAAAABJRU5ErkJggg==") no-repeat;
  background-size: 100%; }
 .toast_success {
  background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAM1BMVEUAAAD///////////////////////////////////////////////////////////////+3leKCAAAAEHRSTlMA8DAQ0GBP4LCggMBwIJBAIttdjAAAAINJREFUOMvdkUsOwyAMBbH5hUCauf9pK1SlohF438x2LPn52f09+8vUfiNb/gighj8FouEjYCUoQDXiBSD7pdcMiK7XC9wCFmlDO3T20Scgx287ne13pwDU89NOJ3g3maCmJDANqIGRtLj8oi1ed1GMdmcB7wXIYX8QdQZJiM5Em3smbyVICDCOrCqSAAAAAElFTkSuQmCC") no-repeat;
  background-size: 100%; }
 .toast_error {
  background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgBAMAAACBVGfHAAAAMFBMVEUAAAD///////////////////////////////////////////////////////////87TQQwAAAAD3RSTlMA0BDAMODwUKBgsCCAQJClzVPvAAAA0UlEQVQoz2MgErAclv9o44Dgc8b/B4KvBTA+t/3XdgeWivjPG6ACbl8ngNXlp0AN+L8IwtD6DzFm2w+Y3v5sMGW/ACbA9Rms9ZsCTIApH2QR608GhoUKQJ4xA8P8AKCAP5CwF2JgUPwIlPwCFDj/AMRRYJIHCnL8AZkJ1AfkAcUYGNhBpso7MICUgBQw8H4EEv/B5ssDFYA4mAKYWjANfd+Aai3CYZ9BDoM63RDkdEGQ0zE9h+l9zADCDEIGt2/wQEZEwwVepGhgYEdEFGZUEgYAW05XI3jSsVwAAAAASUVORK5CYII=") no-repeat;
  background-size: 100%; }
 .toast_info {
  background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgBAMAAACBVGfHAAAALVBMVEUAAAD///////////////////////////////////////////////////////+hSKubAAAADnRSTlMA4CCAwKBAMJBg8NAQUNhWlbcAAAC+SURBVCjPYyASsLfse+1cgOBzyr0DgocXYHwmv4dtCkwZck8UoAJZDydA1C2H8NnexUAYR99BjNF6CtMbtwhM+QUACUUhIMH6BKz14QEgafcYSPDIgSxifMkAE2CYJwAk6gQQAozPgURfA0KAA0T6JSAE2ECm7lNACDC9BhLvGGACIA6GAFyLohBEC9xQqLeeQKwFA4i1EIfBAeNzuNMVhSBOx/AcpvcxAwgzCDEDGTMaGHhhEYWIShN4VBIGAPvRT5YzufhUAAAAAElFTkSuQmCC") no-repeat;
  background-size: 100%; }

@-webkit-keyframes loading {
 0% {
  -webkit-transform: rotate3d(0, 0, 1, 0deg);
  transform: rotate3d(0, 0, 1, 0deg); }
 100% {
  -webkit-transform: rotate3d(0, 0, 1, 360deg);
  transform: rotate3d(0, 0, 1, 360deg); } }

@keyframes loading {
 0% {
  -webkit-transform: rotate3d(0, 0, 1, 0deg);
  transform: rotate3d(0, 0, 1, 0deg); }
 100% {
  -webkit-transform: rotate3d(0, 0, 1, 360deg);
  transform: rotate3d(0, 0, 1, 360deg); } }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • React Native开发封装Toast与加载Loading组件示例

    在App开发中,我们避免不了使用的两个组件,一个Toast,一个网络加载Loading,在RN开发中,也是一样,React Native官方并没有提供者这两个常用组件,需要开发者自己根据需求来自定义.作者就在其他组件的基础上在进行二次封装,使用起来更加简单,更具扩展性,同学们只需将Toast与Loading文件拖到项目中,install对应的组件库即可 效果图 Toast和Loading Demo地址 https://github.com/guangqiang-liu/react-native-

  • ReactNative实现Toast的示例

    对于Android开发工程师来说,Toast在熟悉不过了,用它来显示一个提示信息,并自动隐藏.在我们开发RN应用的时候,我门也要实现这样的效果,就一点困难了,倒也不是困难,只是需要我们去适配,RN官方提供了一个API ToastAndroid,看到这个名字应该猜出,它只能在Android中使用,在iOS中使用没有效果,所以,我们需要适配或者我们自定义一个,今天的这篇文章就是自定义一个Toast使其在Android和iOS都能运行,并有相同的运行效果. 源码传送门 定义组件 import Reac

  • React实现全局组件的Toast轻提示效果

    Toast是常用的轻提示弹框,常用于页面loading和提示语弹窗. 本例基于React实现一个随时可调用且不随页面渲染的全局组件. 需求分析 Toast 不需要同页面一起被渲染,而是根据需要被随时调用. Toast 是一个轻量级的提示组件,它的提示不会打断用户操作,并且会在提示的一段时间后自动关闭. Toast 需要提供几种不同的消息类型以适应不同的使用场景. Toast 的方法必须足够简洁,以避免不必要的代码冗余. 如何使用 首先引入 import Toast from './compone

  • vue如何实现Toast轻提示

    目录 vue实现Toast轻提示 首先创建一个toast组件 在js文件中引入组件 在入口文件中引入上面这个js文件 下面就可以在view里全局使用了 使用vant的Toast轻提示报错 文档中是这样写的 实际使用是这样写 vue实现Toast轻提示 首先创建一个toast组件 <template>   <div class="context" v-show="isshow">     <span class="tip&quo

  • vant中的toast轻提示实现代码

    在main.js中按需引入 import { Toast } from 'vant Vue.use(Toast) 页面中的methods中使用 send(name, img) { let msg = `${this.Cname}送${name}1`; this.$toast({ message: msg, icon: img }); }, 补充知识:Vant的Toast 轻提示API文档不准确解决方案 开发企业微信应用使用Vant组件库过程中,想要用到轻提示Toast,发现API文档无法使用:

  • vue中使用vant的Toast轻提示报错的解决

    目录 使用vant的Toast轻提示报错 提示信息弹出(toast) 实现过程如下 使用vant的Toast轻提示报错 记录一下今天使用vant中的Toast 轻提示,按照官方文档中的方法去使用发现报错使用不了. 文档中是这样写的 Toast.success('成功文案'); Toast.fail('失败文案'); main.js中引用vant后直接调用Toast报错. 实际使用是这样写 this.$toast.success("成功文案"); this.$toast.fail(&qu

  • react实现全局组件确认弹窗

    本例基于react实现了一个简单的确认弹窗,可以让我们在项目中根据需要随时调用 创建全局modal组件 此处我将弹窗模态框独立出来,用户可以通过传入组件或Element来填充模态框的内容. import ReactDOM from 'react-dom'; import React, { Fragment } from 'react'; import Button from 'components/common/button'; import Icon from 'components/comm

  • 基于 flexible 的 Vue 组件:Toast -- 显示框效果

    基于flexible.js 的 Vue 组件 前言: 目前手头的移动端Vue项目是用手淘的 lib-flexible作适配的,并用px2rem 来自动转换成rem.关于lib-flexible和px2rem的配置,请移步 vue-cli 配置 flexible. 由于使用rem作适配,导致现有的很多移动端UI框架不能与之很好的配合,往往需要大动干戈更改UI框架的样式,背离了使用UI框架达到快速开发的初衷. 为了以后项目的组件复用,以及提高开发可复用组件的能力,特把平时项目中 常用的.简单的 组件

  • 详解vue使用vue-layer-mobile组件实现toast,loading效果

    安装vue-layer-mobile // 当前最新版本 1.2.0 npm install vue-layer-mobile // 如新版遇到问题可回退旧版本 npm install vue-layer-mobile@1.0.0 此版本安装后启动会报错,报错提示将css里的display:box改成display:flex; 在main.js里面全局引用 import 'vue-layer-mobile/need/layer.css' import layer from 'vue-layer-

  • 最简单的vue消息提示全局组件的方法

    简介 实现功能 自定义文本 自定义类型(默认,消息,成功,警告,危险) 自定义过渡时间 使用vue-cli3.0生成项目 toast全局组件编写 /src/toast/toast.vue <template> <div class="app-toast" v-if="isShow" :class="{'info': type=== 'info','success': type=== 'success','wraning': type===

  • Vue3中注册全局的组件,并在TS中添加全局组件提示方式

    目录 Vue3中注册全局的组件 Vue3踩坑--全局注册组件 我的框架:vue3+vite+ts+naiveUI Vue3中注册全局的组件 1. 在src/components中新建index.ts用来将所有需要全局注册的组件导入 : 如果使用的是 JS 可以删除类型校验 import type { Component } from 'vue' import SvgIcon from './SvgIcon/index.vue' // 如果使用的是 JS 可以删除类型校验 const compon

  • 手把手教你写一个vue全局注册的Toast的实现

    目录 前言: 我们先思考下面的问题: 首先: 然后: 后来: 再且: 前言: 前几天客户经理不让我用某饿了么之类的UI库做一个轻提示之类的组件,当时一想我是饿了么战士,怎么会写哪个东西,然后我就想着用个alert糊弄过去,但是不行,然后我就细琢磨,发现Vue有个非常不错的Vue.extend. 经过一番努力,我学会了,可能是以前学的时候马虎漏掉了.不过问题不大,还能肝. 我们先思考下面的问题: 在写vue项目的时候啊,我们有了初始化的根实例之后,页面之间都是通过router进行管理,组件也是通过

随机推荐