likes
comments
collection
share

Toast组件开发实践(Vuejs3.x)

作者站长头像
站长
· 阅读数 13

🎄Hi~ 大家好,我是小鑫同学,资深 IT 从业者,InfoQ 的签约作者,擅长前端开发并在这一领域有多年的经验,致力于分享我在技术方面的见解和心得

🚀技术&代码分享

  • 我在 94Code 总结技术学习;
  • 我在 1024Code 在线编写代码;
  • 我在 掘金 分享技术文章;
  • 我在 Github 参与开源学习;

😇推荐几个好用的工具

进入正题

Toast组件几乎是没有个组件库必备的组件,通过Toast组件开发可以比较全面的学习Vuejs的相关技能点,一起来看一下~

基础项目准备

依旧推荐你来1024Code Fork 我的《【项目模板】Vue3+Vite3+Ts4》 开始这次学习,如果你不习惯使用在线的IDE,那么可以将项目导出到本地运行~

组件开发

components目录下创建Toast文件夹,并新增插件文件(index.ts)和组件文件(index.vue),下面是Toast组件的样式及DOM结构,接下来将为其增加一系列必要的内容。

<template>
    <div class="toast">
      <div class="toast-content">Hello Vuejs</div>
    </div>
</template>

<script lang="ts">
</script>

<style>
.toast {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: #333;
  color: #fff;
  padding: 10px;
  border-radius: 5px;
  z-index: 9999;
}

.toast-content {
  display: inline-block;
  margin-right: 10px;
}
</style>

为组件增加属性

Toast组件接收一个必须属性是message用来显示提示的信息,还可以接收一个非必须的属性duration属性,在指定的时间后要自动隐藏掉提示信息,当然要有一个默认值的支持。

使用defineComponent来创建组件对象,并通过props提供messageduration属性,注意类型、必传及默认值的设置。

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  name: 'Toast',
  props: {
    message: {
      type: String,
      required: true
    },
    duration: {
      type: Number,
      default: 1000
    }
  },
})
</script>

添加完属性后就可以将模板中的Hello Vuejs替换成message属性了。

<template>
    <div class="toast">
      <div class="toast-content">{{ message }}</div>
    </div>
</template>

为组件增加状态

增加一个响应式的visible数据,动态的切换组件的显示和隐藏,在setup中将visible返回后,visible将被暴露,在插件中会通过修改visibletrue来显示吐司信息。

<template>
    <div class="toast" v-if="visible">
      <div class="toast-content">{{ message }}</div>
    </div>
</template>
import { ref } from 'vue'

setup(props) {
  const visible = ref(false)

  return {
    visible
  }
}

为组件增加监听器

自动隐藏需要用到watch,当监听到visible状态激活时启动计时器,在duration毫秒后将visible状态改为未激活状态。

watch(visible, (value) => {
  if (value) {
    setTimeout(() => {
      visible.value = false
    }, props.duration)
  }
})

组件部分完整代码

<template>
    <div class="toast" v-if="visible">
      <div class="toast-content">{{ message }}</div>
    </div>
</template>

<script lang="ts">
import { defineComponent, ref, watch } from 'vue'

export default defineComponent({
  name: 'Toast',
  props: {
    message: {
      type: String,
      required: true
    },
    duration: {
      type: Number,
      default: 1000
    }
  },
  setup(props) {
    const visible = ref(false)
    
    watch(visible, (value) => {
      if (value) {
        setTimeout(() => {
          visible.value = false
        }, props.duration)
      }
    })
    
    return {
      visible
    }
  }
})
</script>

<style>
.toast {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: #333;
  color: #fff;
  padding: 10px;
  border-radius: 5px;
  z-index: 9999;
}

.toast-content {
  display: inline-block;
  margin-right: 10px;
}
</style>

插件开发

在插件文件(index.ts)中必须包含一个Vuejs插件规范的install函数,另外需要抽取一个createToast函数来执行具体的Toast组件创建加载及提示流程。

实现install函数

install函数中主要的目的就是要在全局挂载一个可以随处执行的$toast方法,通过这个方法可以很方便的使用Toast组件。

在Vue3中挂载全局变量需要在globalProperties上添加,具体可以看Vuejs文档

const createToast = (options: 
    { message: string, duration?: number }
) => {
  
}

export const ToastPlugin = {
  install(app: any) {
    app.config.globalProperties.$toast = {
      show: (message: string, duration?: number) => createToast({message, duration}),
    }
  }
}

实现createToast函数

实现createToast函数首先要导入vue模块中的createApp和同级目录下的组件模块,再借助createApp创建Toast组件应用程序实例,通过应用程序实例的mount函数将其挂载到一个新的div元素上,至此将得到一个成功挂载的组件实例。

import { createApp } from 'vue'
import Toast from './index.vue'

const createToast = (options: 
    { message: string, duration?: number }
) => {

  const app = createApp(Toast, {
    message: options.message,
    duration: options.duration,
  })

  const instance = app.mount(document.createElement('div'))
}

在得到Toast组件实例后,将可以直接访问组件暴露的状态和方法,此时就可以将Toast组件的visible变更为激活状态。

const createToast = (options: 
    { message: string, duration?: number }
) => {

  ...

  const instance = app.mount(document.createElement('div'))
  instance.visible = true;
}

最后可以通过组件实例上的$el属性获取已挂载组件对应的真实DOM,将其直接插入body元素中即完成插件的完整功能。

const createToast = (options: 
    { message: string, duration?: number }
) => {

  ...

  document.body.appendChild(instance.$el)
}

插件部分完整代码

import { createApp } from 'vue'
import Toast from './index.vue'

const createToast = (options: 
    { message: string, duration?: number }
) => {
  const app = createApp(Toast, {
    message: options.message,
    duration: options.duration,
  })

  const instance = app.mount(document.createElement('div'))
  instance.visible = true;

  document.body.appendChild(instance.$el)
}

export const ToastPlugin = {
  install(app: any) {
    app.config.globalProperties.$toast = {
      show: (message: string, duration?: number) => createToast({message, duration}),
    }
  }
}

组件使用

安装

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
// ① 导入插件模块
import { ToastPlugin } from './components/Toast/index'

createApp(App)
  // ② 使用use加载插件
  .use(ToastPlugin)
  .mount('#app')

使用

<script lang="ts">
export default {
  name: "App",
  methods: {
    toast() {
      this.$toast.show('Hello Vuejs')
    }
  }
}
</script>
// script setup
<script setup lang="ts">
import { getCurrentInstance } from 'vue';
const global = getCurrentInstance()?.appContext.config.globalProperties;

const toast = () => {
  global?.$toast.show('Hello Vuejs')
}
</script>
// defineComponent + setup
<script lang="ts">
import { defineComponent, getCurrentInstance } from 'vue';
export default defineComponent({
  name: "App",
  setup() {

   const global = getCurrentInstance()?.appContext.config.globalProperties;

    const toast = () => {
      global?.$toast.show('Hello Vuejs')
    }

    return {
      toast,
    }
  }
})
</script>

补充优化

这里做一点点小优化,就是为Toast组件增加一下状态切换时的动画效果,可以使用Vuejs内置的Transition,它可以将进入和离开动画应用到通过默认插槽传递给它的元素或组件上,通过v-if状态的变化即可激活绑定的动画效果。

<template>
  <transition name="toast">
    <div class="toast" v-if="visible">
      <div class="toast-content">{{ message }}</div>
    </div>
  </transition>
</template>

<style>
.toast-enter-active,
.toast-leave-active {
  transition: opacity 0.5s ease;
}

.toast-enter-from,
.toast-leave-to {
  opacity: 0;
}
</style>

总结

到此Toast组件的整个开发流程就结束了,在整个开发流程中涉及的Vuejs的属性、状态、监听器的使用,还有插件开发时的规则及全局变量的挂载,并且在组件使用时针对使用了setup后无法读取this而正确读取全局变量的,最后还提到了一点Vuejs基础中动画组件的使用。希望能给你带来帮助。更多的实现方式不妨你来尝试一下1024Code提供AI编程助手,响应速度非常棒~


如果看完觉得有收获,欢迎点赞、评论、分享支持一下。你的支持和肯定,是我坚持写作的动力~