Vue3封装自定义Toast组件

Toast.vue组件文件

<script setup lang="ts">
import { computed, onMounted, ref } from "vue";
import type { ToastProps } from './index';

const props = withDefaults(defineProps<ToastProps>(), {
  text: '',
  position: 'top-center',
  duration: 'normal',
});

const myself = ref<HTMLElement>();
const durationTimeMs = computed(() => {
  switch (props.duration) {
    case 'long':
      return 1500;
    case 'normal':
      return 1000;
    case 'short':
      return 500;
    default:
      return props.duration;
  }
})

onMounted(() => {
  setTimeout(() => {
  	// 一定时间后移除
	myself.value?.remove()
  }, durationTimeMs.value);
})

const toastClass = computed(() => {
  let className: string = props.position;
  if (className === 'top') className = 'top-center';
  if (className === 'bottom') className = 'bottom-center';
  return ['toast', className];
});
</script>

<template>
  <Teleport to="body">
    <div :class="toastClass" ref="myself">
      <div class="toast-wrapper">
      	/* 同时支持text和slot */
        <span v-if="text" class="toast-text">{{ props.text }}</span>
        <slot v-if="$slots.default"></slot>
      </div>
    </div>
  </Teleport>
</template>

<style scoped lang="scss">
@import "@/assets/variables";
.toast {
  position: fixed;

  &-wrapper {
    background-color: $color-white;
    border-radius: .5rem;
    box-shadow: $box-shadow;
    padding: .25rem .5rem;
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: .5rem;
  }

  .top-center {
    top: 0;
    left: 50%;
    transform: translateX(-50%);
  }
  .top-left {
    top: 0;
    left: 0;
  }
  .top-right {
    top: 0;
    right: 0;
  }
  .bottom-center {
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
  }
  .bottom-left {
    bottom: 0;
    left: 0;
  }
  .bottom-right {
    bottom: 0;
    right: 0;
  }
}
</style>

toast.ts函数文件

import type { ToastProps } from "@/components/toast/index";
import { createApp, h } from "vue";
import Toast from "@/components/toast/Toast.vue";

let toastDiv: HTMLDivElement;
function showToast(props: ToastProps) {
  if (!toastDiv) {
    toastDiv = document.createElement('div');
  }
  const element = createApp({
    render() {
      return h(Toast, props);
    }
  })
  // 添加div到根组件上
  document.querySelector('#app')?.appendChild(toastDiv);
  // Toast组件挂载到div内部
  element.mount(toastDiv);
}

export default showToast;

这里将toastDiv挂载在#app的内部,是由于我这里编写的框架结构导致的,正常情况下用
document.body.appendChild(toastDiv)就行。

index.ts定义文件

export interface ToastProps {
  text?: string;
  position?: 'top' | 'top-center' | 'top-left' | 'top-right' | 'bottom' | 'bottom-center' | 'bottom-left' | 'bottom-right';
  duration?: 'normal' | 'long' | 'short' | number;
}

使用方式

showToast({text: '1024程序员节快乐'});
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
封装自定义指令,你可以按照以下步骤进行操作: 1. 创建一个新的 Vue 指令。在 Vue 3 中,可以使用 `app.directive` 方法来创建指令。 ```javascript app.directive('myDirective', { // 指令选项 }); ``` 2. 在指令选项中,你需要定义以下几个钩子函数(可选): - `beforeMount`:在指令绑定元素挂载到DOM之前调用。 - `mounted`:在指令绑定元素挂载到DOM后调用。 - `beforeUpdate`:在指令所在组件更新之前调用。 - `updated`:在指令所在组件更新之后调用。 - `beforeUnmount`:在指令所在组件卸载之前调用。 - `unmounted`:在指令所在组件卸载后调用。 这些钩子函数允许你在指令的生命周期中执行相应的操作。 3. 在钩子函数中,你可以使用 `el` 参数获取到指令所绑定的 DOM 元素。通过操作 DOM 元素,你可以实现指令的功能。 下面是一个示例,演示了如何封装一个简单的自定义指令来实现点击元素时改变背景颜色的效果: ```javascript app.directive('changeBackground', { beforeMount(el) { el.style.backgroundColor = 'yellow'; }, mounted(el) { el.addEventListener('click', this.onClick); }, beforeUnmount(el) { el.removeEventListener('click', this.onClick); }, onClick(event) { event.target.style.backgroundColor = 'red'; } }); ``` 在上面的示例中,指令名称为 `changeBackground`,在 `beforeMount` 钩子函数中设置初始背景颜色为黄色,在 `mounted` 钩子函数中添加点击事件监听器,点击元素时调用 `onClick` 方法来改变背景颜色为红色,在 `beforeUnmount` 钩子函数中移除点击事件监听器。 你可以根据自己的需求,在钩子函数中实现自定义指令的具体功能。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值