-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
662 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { AppContext } from "vue"; | ||
import _message from "./src/messageList.vue"; | ||
import MessageManager from "./src/instance"; | ||
import { MessageInstance, MessageItem, MessageType } from "./src/type"; | ||
export const isString = (data: any): boolean => typeof data === "string"; | ||
|
||
let msg: MessageManager; | ||
const types = ["text", "success", "warning", "error", "loading"] as const; | ||
|
||
const message = types.reduce((pre, value) => { | ||
pre[value] = (config: MessageInstance, appContext?: AppContext) => { | ||
// 直接传入消息提示内容的情况 | ||
if (isString(config)) { | ||
config = { content: config as string } as MessageItem; | ||
} | ||
|
||
const _config: MessageItem = { type: value as MessageType, ...(config as MessageItem) }; | ||
if (!msg) { | ||
msg = new MessageManager(appContext); | ||
} | ||
return msg!.add(_config as MessageItem); | ||
}; | ||
return pre; | ||
}, {} as any); | ||
|
||
const Message = Object.assign({ | ||
...message, | ||
removeAll: () => { | ||
msg && msg.clear(); | ||
}, | ||
}); | ||
|
||
export default Message; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { AppContext, Ref, createVNode, reactive, ref, render } from "vue"; | ||
import Message from "./messageList.vue"; | ||
import { MessageItem } from "./type"; | ||
import { arrayIndexOf, deepClone } from "@/utils/index"; | ||
|
||
class MessageManager { | ||
private mask: HTMLElement = document.createElement("div"); | ||
private messageList: Ref<MessageItem[]>; | ||
|
||
constructor(appContext?: AppContext) { | ||
this.messageList = ref<MessageItem[]>([]); | ||
this.mask.setAttribute("class", `bp-mask-message`); | ||
|
||
const vm = createVNode(Message, { | ||
list: this.messageList.value, | ||
onRemove: this.remove, | ||
}); | ||
|
||
if (appContext) { | ||
vm.appContext = appContext; | ||
} | ||
render(vm, this.mask); | ||
document.body.appendChild(this.mask); | ||
} | ||
|
||
/** | ||
* 添加消息提示 | ||
* @param {MessageItem} config | ||
* @returns | ||
*/ | ||
add = (config: MessageItem) => { | ||
const id = config.id ?? `_bp_message_${Math.random().toString(36).slice(-8)}`; | ||
this.mask.setAttribute("class", `bp-mask-message bp-message-${config.position || "top"}`); | ||
|
||
const message: MessageItem = reactive({ id, ...config }); | ||
|
||
// Check whether the message instance already exists. If has, update the message config, or push new one. | ||
const updateIdx = arrayIndexOf(this.messageList.value, "id", id); | ||
updateIdx !== -1 ? (this.messageList.value[updateIdx] = config) : this.messageList.value.push(message); | ||
|
||
// Handle possible simultaneous removal cases, step up 200ms to make the removal visual experience better. | ||
const len = this.messageList.value.length; | ||
if (len > 1 && this.messageList.value[len - 1]?.duration === message.duration) { | ||
message.duration = message.duration ?? 3000 + 200 * len; | ||
} | ||
|
||
return { | ||
remove: () => this.remove(id), | ||
}; | ||
}; | ||
|
||
/** | ||
* 移除消息提示 | ||
* @param {string} id 消息id | ||
*/ | ||
remove = (id: string) => { | ||
for (let i = 0; i < this.messageList.value.length; i++) { | ||
const { id: itemId } = this.messageList.value[i]; | ||
|
||
if (id === itemId) { | ||
this.messageList.value.splice(i, 1); | ||
break; | ||
} | ||
} | ||
}; | ||
|
||
/** 清除消息列表 */ | ||
clear = () => { | ||
const arr = deepClone(this.messageList.value); | ||
for (let i = 0; i < arr.length; i++) { | ||
const element = arr[i]; | ||
this.remove(element.id); | ||
} | ||
}; | ||
} | ||
|
||
export default MessageManager; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
<template> | ||
<li :class="clsName"> | ||
<span v-if="type !== 'text'" :class="[`${name}-icon`, `icon-${type}`]"> | ||
<component :is="iconType[type]" size="sm"></component> | ||
</span> | ||
<span :class="`${name}-content`">{{ content }}</span> | ||
<span v-if="closeable" :class="`${name}-close`" @click="handleClose"> | ||
<SfIconClose /> | ||
</span> | ||
</li> | ||
</template> | ||
|
||
<script setup lang="ts" name="MessageList"> | ||
import { PropType, nextTick, onMounted, onUnmounted, ref } from "vue"; | ||
import { MessageType } from "./type"; | ||
import { computed } from "vue"; | ||
import { SfIconClose, SfIconCancel, SfIconError, SfIconPublishedWithChanges, SfIconCheckCircle } from "@storefront-ui/vue"; | ||
const name = "bp-message"; | ||
const props = defineProps({ | ||
/** 消息ID Message id */ | ||
id: { type: String }, | ||
/** 消息提示类型 Message prompt type */ | ||
type: { type: String as PropType<MessageType>, default: "text" }, | ||
/** 消息提示内容 Message prompt content */ | ||
content: { type: String, default: "" }, | ||
/** 延迟关闭时间 Delayed shutdown time */ | ||
duration: { type: Number, default: 3000 }, | ||
/** 是否允许手动关闭 Closeable or not */ | ||
closeable: { type: Boolean, default: false }, | ||
/** 是否开启无背景展示 */ | ||
plain: { type: Boolean, default: false }, | ||
/** 关闭后的回调函数 */ | ||
onClose: { type: Function }, | ||
}); | ||
const emits = defineEmits<{ | ||
remove: [id: string]; | ||
}>(); | ||
const timer = ref(0); | ||
const iconType = { | ||
success: SfIconCheckCircle, | ||
error: SfIconCancel, | ||
warning: SfIconError, | ||
loading: SfIconPublishedWithChanges, | ||
}; | ||
const init = () => { | ||
if (props.duration > 0 && props.type !== "loading") { | ||
timer.value = window.setTimeout(handleClose, props.duration); | ||
} | ||
}; | ||
const clsName = computed(() => { | ||
let cls = [name]; | ||
cls.push(props.plain ? `${name}-plain` : `${name}-${props.type}`); | ||
return cls; | ||
}); | ||
const clearTimer = () => { | ||
if (timer.value) { | ||
window.clearTimeout(timer.value); | ||
timer.value = 0; | ||
} | ||
}; | ||
const handleClose = () => { | ||
emits("remove", props.id || ""); | ||
props.onClose && props.onClose(props.id); | ||
}; | ||
onMounted(() => { | ||
nextTick(() => init()); | ||
}); | ||
onUnmounted(() => { | ||
clearTimer(); | ||
}); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<template> | ||
<TransitionGroup class="bp-message-list" name="fademsg" tag="ul"> | ||
<template v-for="v in props.list" :key="`${v.id}`"> | ||
<message | ||
:id="v.id" | ||
:type="v.type" | ||
:content="v.content" | ||
:duration="v.duration" | ||
:closeable="v.closeable" | ||
:plain="v.plain" | ||
:on-close="v.onClose" | ||
@remove="onRemove" | ||
></message> | ||
</template> | ||
</TransitionGroup> | ||
</template> | ||
|
||
<script setup lang="ts" name="MessageList"> | ||
import { PropType } from "vue"; | ||
import { MessageItem } from "./type"; | ||
import message from "./message.vue"; | ||
const props = defineProps({ | ||
list: { type: Array as PropType<MessageItem[]>, default: () => [] }, | ||
}); | ||
const emits = defineEmits<{ | ||
(e: "remove", id: string): void; | ||
}>(); | ||
const onRemove = (id: string) => emits("remove", id); | ||
</script> |
Oops, something went wrong.