Vue自定义全局Toast和Loading

如果我们的Vue项目中没有用到任何UI框架的话,为了更好的用户体验,肯定会用到loading和toast。那么我们就自定义这两个组件吧。

1、Toast组件

首先,在common下新建global文件夹,存放我们的toast.vue和toast.js两个文件(当然文件的具体位置你可以自行安排)。

(1). toast.vue

<template lang="html">
  <div v-if="isShowToast" class="toast-container" @touchmove.prevent>
    <!-- 这里content为双花括号 -->
    <span class="loading-txt">{content}</span>
  </div>
</template>

<script>
export default {
  data () {
    return {
      isShowToast: true,
      content: ''
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.toast-container {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(255, 255, 255, 0.1);
}
.toast-msg {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 60%;
  padding: 35px;
  border-radius: 10px;
  font-size: 28px;
  line-height: 36px;
  background: #eee;
  color: #666;
}
</style>

(2). toast.js

import Vue from 'Vue'
import ToastComponent from './Toast.vue'

const Toast = {}
let showToast = false // 存储loading显示状态
let toastNode = null // 存储loading节点元素
const ToastConstructor = Vue.extend(ToastComponent)

Toast.install = function (Vue, options) {
  // 参数
  var opt = {
    duration: '1200'
  }
  for (var property in options) {
    opt[property] = options[property]
  }
  Vue.prototype.$toast = function (tips, type) {
    if (type === 'hide') {
      toastNode.isShowToast = showToast = false
    } else {
      if (showToast) {
        // 如果toast还在,则不再执行
        return
      }
      toastNode = new ToastConstructor({
        data: {
          isShowToast: showToast,
          content: tips
        }
      })
      toastNode.$mount() // 挂在实例,为了获取下面的toastNode.$el
      document.body.appendChild(toastNode.$el)
      toastNode.isShowToast = showToast = true
      setTimeout(function () {
        toastNode.isShowToast = showToast = false
      }, opt.duration)
    }
  };

  ['show', 'hide'].forEach(function (type) {
    Vue.prototype.$toast[type] = function (tips) {
      return Vue.prototype.$toast(tips, type)
    }
  })
}

export default Toast

然后,我们需要把写好的组件在/src/main.js中引用一下。

import Toast from './components/common/global/toast'

Vue.use(Toast)

最后,怎么使用呢?只需在要用的地方this.$toast.show(‘hello world’)

2、Loading组件

loading组件只需要照着toast组件搬过来,稍微改下就可以了。

首先,在common下新建global文件夹,存放我们的loading.vue和loading.js两个文件。

(1). loading.vue

<template lang="html">
  <div v-if="isShowLoading" class="loading-container">
    <div class="loading-box">
      <img class="loading-img" :src="require('../../../assets/images/loading.png')">
      <!-- 这里content为双花括号 -->
      <span class="loading-txt">{content}</span>
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      isShowLoading: false,
      content: ''
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.loading-container {
  display: flex;
  justify-content: center;
  align-items: center;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0);
  z-index: 1000;
}
.loading-box {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 150px;
  height: 150px;
  border-radius: 10px;
  background: #e5e5e5;
}
.loading-img {
  width: 70px;
  height: 70px;
  animation: rotating 2s linear infinite;
}
@keyframes rotating {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(1turn);
  }
}
.loading-txt {
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 24px;
  color: #666;
}
</style>

(2). loading.js

import Vue from 'Vue'
import LoadingComponent from './Loading.vue'

const Loading = {}
let showLoading = false // 存储loading显示状态
let loadingNode = null // 存储loading节点元素
const LoadingConstructor = Vue.extend(LoadingComponent)

Loading.install = function (Vue) {
  Vue.prototype.$loading = function (tips, type) {
    if (type === 'hide') {
      loadingNode.isShowLoading = showLoading = false
    } else {
      if (showLoading) {
        // 如果loading还在,则不再执行
        return
      }
      loadingNode = new LoadingConstructor({
        data: {
          isShowLoading: showLoading,
          content: tips
        }
      })
      loadingNode.$mount() // 挂在实例,为了获取下面的loadingNode.$el
      document.body.appendChild(loadingNode.$el)
      loadingNode.isShowLoading = showLoading = true
    }
  };

  ['show', 'hide'].forEach(function (type) {
    Vue.prototype.$loading[type] = function (tips) {
      return Vue.prototype.$loading(tips, type)
    }
  })
}

export default Loading

然后,在/src/main.js中引用一下loading组件。

import Loading from './components/common/global/loading'

Vue.use(Loading)

最后,只需在要用的地方this.$loading.show(‘hello world’)、 this.$loading.hide()

对于实现登录页面的自定义指令,可以考虑自定义一个全局指令或局部指令。 全局指令可以通过 Vue.directive() 方法来实现,它能够在整个应用中被调用。在实现登录页面自定义指令时,我们可以在线条型输入框中添加自定义指令: Vue.directive('login-validate', { bind(el, binding, vnode) { // 获取 input 元素 const input = el.querySelector('input') // 监听 input 元素的 input 事件 input.addEventListener('input', () => { // 获取输入框中的值 const value = input.value // 根据具体需求添加验证逻辑 if (!value) { // 如果输入值为空,添加错误提示 el.classList.add('error') input.classList.add('error') } else { // 如果输入值不为空,移除错误提示 el.classList.remove('error') input.classList.remove('error') } }) } }) 局部指令可以通过在组件的 directives 选项中注册来实现,它只会在该组件中被调用。在实现登录页面自定义指令时,我们可以在组件内添加自定义指令: export default { // ... directives: { loginValidate: { bind(el, binding, vnode) { // 获取 input 元素 const input = el.querySelector('input') // 监听 input 元素的 input 事件 input.addEventListener('input', () => { // 获取输入框中的值 const value = input.value // 根据具体需求添加验证逻辑 if (!value) { // 如果输入值为空,添加错误提示 el.classList.add('error') input.classList.add('error') } else { // 如果输入值不为空,移除错误提示 el.classList.remove('error') input.classList.remove('error') } }) } } } } 以上是自定义全局指令和局部指令的实现方法,实际应用时可以根据具体需求进行适当的修改和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值