Skip to content

Commit

Permalink
feat: update.
Browse files Browse the repository at this point in the history
  • Loading branch information
tuin77 committed Jan 18, 2024
1 parent f1fbc7d commit e82239a
Show file tree
Hide file tree
Showing 18 changed files with 662 additions and 83 deletions.
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ module.exports = {
"no-debugger": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/ban-types": "off",
},
};
File renamed without changes.
11 changes: 9 additions & 2 deletions src/components/layout/RightDrawer.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<SfButton tag="span" class="!text-bold-100 relative" square variant="tertiary" @click="open = true" aria-controls="mobile-menu-2">
<SfIconMenu size="lg" /> <SfBadge class="!bg-red-500 !text-base top-[-8px] right-[-8px] px-2 py-0.5" :content="content"
<SfIconMenu size="lg" /> <SfBadge class="!bg-red-500 !text-base top-[-8px] right-[-8px] px-2 py-0.5" :content="cart.effectiveListCounts"
/></SfButton>

<transition
Expand Down Expand Up @@ -66,7 +66,9 @@
<img src="../../assets/images/home/icon-nav-wishlist.svg" class="object-contain w-[21px] h-[21px] text-blod" />
</template>
<span class="text-lg font-bold text-bold-100 ml-[24px]"> shopping cart </span>
<template #suffix> <SfCounter size="sm" pill class="text-white !px-1.5 bg-red-500 ring-white"> 2 </SfCounter></template>
<template #suffix>
<SfCounter size="sm" pill class="text-white !px-1.5 bg-red-500 ring-white"> {{ cart.effectiveListCounts }} </SfCounter></template
>
</SfListItem>
<div class="flex items-center justify-between px-[30px] mt-auto mb-[57px]">
<span class="text-lg text-gray-200">contact us</span>
Expand Down Expand Up @@ -104,4 +106,9 @@ const toPageCart = () => {
});
open.value = false;
};
import useStore from "@/stores";
const { cart } = useStore();
cart.getCartList();
</script>
33 changes: 33 additions & 0 deletions src/components/message/index.ts
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;
77 changes: 77 additions & 0 deletions src/components/message/src/instance.ts
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;
81 changes: 81 additions & 0 deletions src/components/message/src/message.vue
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>
31 changes: 31 additions & 0 deletions src/components/message/src/messageList.vue
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>
Loading

0 comments on commit e82239a

Please sign in to comment.