Skip to content

Commit

Permalink
feat: 新增nToast组件
Browse files Browse the repository at this point in the history
  • Loading branch information
ljnMeow committed Nov 22, 2023
1 parent 2f96f7b commit 9e43938
Show file tree
Hide file tree
Showing 17 changed files with 552 additions and 9 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ module.exports = {
defineEmits: 'readonly',
defineExpose: 'readonly',
withDefaults: 'readonly',
NodeJS: true,
},
rules: {
// @typescript-eslint
Expand Down
8 changes: 8 additions & 0 deletions packages/nice2cu-ui-mobile-example/src/router/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,12 @@ export default [
title: '索引列表',
},
},
{
path: '/toast',
name: 'Toast',
component: () => import(/* webpackChunkName: "Toast" */ '@views/componentsViews/Toast.vue'),
meta: {
title: '消息提示',
},
},
];
1 change: 1 addition & 0 deletions packages/nice2cu-ui-mobile-example/src/views/HomeIndex.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@
<n-cell title="Tag 标签" link="tag"></n-cell>
<n-cell title="Card 卡片" link="card"></n-cell>
<n-cell title="IndexList 索引列表" link="IndexList"></n-cell>
<n-cell title="Toast 消息提示" link="Toast"></n-cell>
</div>
</template>
126 changes: 126 additions & 0 deletions packages/nice2cu-ui-mobile-example/src/views/componentsViews/Toast.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<template>
<div class="container">
<n-nav-bar title="Toast 消息提示" show-left left-text="" :shadow-buttom="true" fixed-top safe-area-inset-top placeholder></n-nav-bar>

<section>
<div class="title">基本用法</div>
<div class="content unflex">
<div class="item">
<n-button type="primary" block @click="showToast()">文字提示</n-button>
</div>
<div class="item">
<n-button type="success" block @click="showStatusToast('成功', 'success')">成功提示</n-button>
</div>
<div class="item">
<n-button type="warning" block @click="showStatusToast('警告', 'warning')">警告提示</n-button>
</div>
<div class="item">
<n-button type="danger" block @click="showStatusToast('失败', 'error')">失败提示</n-button>
</div>
<div class="item">
<n-button type="primary" block @click="showToastLoading">加载提示</n-button>
</div>
</div>
</section>
<section>
<div class="title">自定义属性</div>
<div class="content unflex">
<div class="item">
<n-button type="primary" block @click="showToastCostomIcon">自定义图标</n-button>
</div>
<div class="item">
<n-button type="primary" block @click="showToastCostomContent">自定义内容</n-button>
</div>
</div>
</section>
<section>
<div class="title">动态content</div>
<div class="content unflex">
<div class="item">
<n-button type="primary" block @click="showCountDown">倒计时</n-button>
</div>
</div>
</section>
<section>
<div class="title">带遮罩的toast</div>
<div class="content unflex">
<div class="item">
<n-button type="primary" block @click="showMaskToast">带透明遮罩无法点击后面</n-button>
</div>
</div>
</section>
</div>
</template>

<script lang="ts" setup>
import { Toast, nAvatar } from 'nice2cu-ui';
const showToast = () => {
Toast.showToast({
content: 'Nice2CU-UI',
});
};
const showStatusToast = (msg: string, type: string) => {
Toast.showToast({
content: msg,
type: type,
});
};
const showToastLoading = () => {
Toast.showToastLoading();
};
const showToastCostomIcon = () => {
Toast.showToast({
content: '自定义图标',
icon: 'n-beer-sharp',
});
};
const showToastCostomContent = () => {
Toast.showToast({
content: (h: any) => h(nAvatar, { src: 'https://bu.dusays.com/2023/06/04/647c4b5936222.webp' }),
});
};
let timer: NodeJS.Timeout;
const showCountDown = () => {
let times = 6;
if (timer) clearInterval(timer);
const toast = Toast.showToastLoading({
id: 'loading',
content: `倒计时${times}秒`,
duration: 0,
onClose: () => {
Toast.showToast({
content: '时间到!!!',
});
},
});
timer = setInterval(() => {
times--;
if (!times) {
clearInterval(timer);
Toast.hideToastLoading('loading');
} else {
toast.state.content = `倒计时${times}秒`;
}
}, 1000);
};
const showMaskToast = () => {
Toast.showToastLoading({
duration: 0,
hasMask: true,
});
setTimeout(() => {
Toast.hideToastLoading();
}, 3000);
};
</script>
1 change: 1 addition & 0 deletions packages/nice2cu-ui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ export * from './nDivider';
export * from './nTag';
export * from './nCard';
export * from './nIndexList';
export * from './nToast';
8 changes: 0 additions & 8 deletions packages/nice2cu-ui/src/nLoading/LoadingProps.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
/*
* @Author: linMeow [email protected]
* @Date: 2022-11-26 13:35:08
* @LastEditors: linMeow [email protected]
* @LastEditTime: 2023-07-03 17:19:45
* @FilePath: /nice2cu/packages/nice2cu-ui/src/nLoading/LoadingProps.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { ExtractPropTypes, PropType } from 'vue';

export function typeValidator(type: string): boolean {
Expand Down
107 changes: 107 additions & 0 deletions packages/nice2cu-ui/src/nToast/Toast.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<!-- eslint-disable vue/no-v-html -->
<template>
<div>
<div v-if="state.hasMask" :class="state.hasMask ? bem.e('mask') : undefined"></div>
<Transition name="toast-fade" @after-leave="transitionLeave">
<div v-if="state.show" :class="[bem.b()]" :style="state.customStyle">
<div :class="bem.b('inner')">
<n-icon
v-if="(state.type !== 'default' || state.icon) && !state.loading"
:icon="state.icon ? state.icon : `n-${state.type}`"
:class="bem.b('icon')"
:size="handleUnit(state.iconSize)"
:class-prefix="state.iconPrefix"
:style="{ marginBottom: state.content ? '10px' : '0px' }"
></n-icon>
<n-loading
v-if="state.loading"
:class="bem.b('loading')"
:style="{ marginBottom: state.content ? '10px' : '0px' }"
:color="state.customStyle.color ? state.customStyle.color : '#ffffff'"
size="large"
:type="state.loadingType"
></n-loading>
<component :is="handlerRenderContent()" v-if="isVNode(state.content) || isFunction(state.content)" />
<div
v-if="state.content && !isVNode(state.content) && !isFunction(state.content)"
:class="bem.e('content')"
v-html="handlerRenderContent()"
></div>
</div>
</div>
</Transition>
</div>
</template>

<script lang="ts">
import { defineComponent, reactive, onMounted, createVNode, isVNode } from 'vue';
import { createNamespace } from '../../utils/create';
import { ToastProps, ToastPropsType } from './ToastProps';
import { handleUnit, isFunction } from '../../utils/tools';
import NIcon from '../nIcon';
import NLoading from '../nLoading';
import './style/toast.less';
export default defineComponent({
name: 'NToast',
components: { NIcon, NLoading },
props: ToastProps,
setup(props: ToastPropsType) {
const bem = createNamespace('toast');
const state = reactive({
show: false,
...props,
});
let timer: NodeJS.Timeout | null | undefined;
const handlerRenderContent = () => {
if (isVNode(state.content)) {
return state.content;
} else if (typeof state.content === 'function') {
return state.content(createVNode);
} else {
return state.content;
}
};
const clearTimer = () => {
if (timer) {
clearTimeout(timer);
timer = null;
}
};
const hideToast = () => {
state.show = false;
if (state.onClose) {
state.onClose();
}
};
const timerourHide = () => {
clearTimer();
if (state.duration) {
timer = setTimeout(() => {
hideToast();
}, state.duration);
}
};
const transitionLeave = () => {
clearTimer();
if (state.clearToast) state.clearToast(state.id);
};
if (state.duration) {
timerourHide();
}
onMounted(() => {
state.show = true;
});
return { bem, state, transitionLeave, handleUnit, handlerRenderContent, isVNode, isFunction };
},
});
</script>
62 changes: 62 additions & 0 deletions packages/nice2cu-ui/src/nToast/ToastProps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { ExtractPropTypes, PropType, VNode } from 'vue';

const typeValidator = (position: string) => {
return ['default', 'success', 'warning', 'error'].includes(position);
};

export function loadingTypeValidator(type: string): boolean {
return ['circle', 'time', 'wave', 'point', 'rever', 'bounce', 'battery'].includes(type);
}

export const ToastProps = {
id: {
type: [String, Number],
default: '',
},
type: {
type: String as PropType<'default' | 'success' | 'warning' | 'error'>,
default: 'default',
validator: typeValidator,
},
content: {
type: [String, Function, Object] as PropType<string | VNode | ((h: any) => VNode)>,
defualt: '',
},
duration: {
type: Number,
default: 2000,
},
customStyle: {
type: Object,
default: {},
},
icon: {
type: String,
defalt: '',
},
iconSize: {
type: [String, Number],
default: '36px',
},
iconPrefix: {
type: String,
default: 'nice2cu-icon',
},
loading: {
type: Boolean,
default: false,
},
loadingType: {
type: String as PropType<'circle' | 'time' | 'wave' | 'point' | 'rever' | 'bounce' | 'battery'>,
default: 'circle',
validator: loadingTypeValidator,
},
hasMask: {
type: Boolean,
default: false,
},
clearToast: Function,
onClose: Function,
};

export type ToastPropsType = ExtractPropTypes<typeof ToastProps>;
Loading

0 comments on commit 9e43938

Please sign in to comment.