feat: 新增Notify组件、演示demo、文档 (#9)

* feat:  新增Notify组件、演示demo、文档

* feat:  新增Notify组件、演示demo、文档
This commit is contained in:
黄蛋蛋 2023-08-26 11:59:27 +08:00 committed by GitHub
parent 90ad2643a4
commit 996fc39d70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 622 additions and 6 deletions

1
.gitignore vendored
View File

@ -25,3 +25,4 @@ yarn-error.log*
*.njsproj
*.sln
*.sw*
.history

View File

@ -283,6 +283,9 @@ export default defineConfig({
}, {
link: "/component/toast",
text: "Toast 轻提示"
}, {
link: "/component/notify",
text: "Notify 消息通知"
}, {
link: "/component/tooltip",
text: "Tooltip 文字提示"

227
docs/component/notify.md Normal file
View File

@ -0,0 +1,227 @@
<frame/>
# Notify 消息通知
## 基本用法
需要在页面中引入该组件,作为挂载点。
```html
<wd-notify selector="notify" />
```
```ts
import { useNotify } from '@/uni_modules/wot-design-uni'
const { showNotify, closeNotify } = useNotify('notify')
// 3 秒后自动关闭
showNotify('通知内容')
// 主动关闭
closeNotify()
```
## 通知类型
支持 `primary``success``warning``danger` 四种通知类型,默认为 `danger`
```ts
// 主要通知
showNotify({ type: 'primary', message: '通知内容' })
// 成功通知
showNotify({ type: 'success', message: '通知内容' })
// 危险通知
showNotify({ type: 'danger', message: '通知内容' })
// 警告通知
showNotify({ type: 'warning', message: '通知内容' })
```
## 自定义通知
```ts
showNotify({
message: '自定义颜色',
color: '#ad0000',
background: '#ffe1e1'
})
showNotify({
message: '自定义位置',
position: 'bottom'
})
showNotify({
message: '自定义时长',
duration: 1000
})
```
## 使用 Notify 组件
如果需要在 Notify 内嵌入组件或其他自定义内容,可以直接使用 Notify 组件,并使用默认插槽进行定制。
```html
<wd-button type="primary" @click="showNotify">使用 Notify 组件调用</wd-button>
<wd-notify type="success" :safe-height="safeHeight" v-model:visible="visible">
<wd-icon name="check-outline" size="inherit" color="inherit" />
成功通知
</wd-notify>
```
```ts
import { ref, onMounted } from 'vue'
let timer: ReturnType<typeof setTimeout>
export default {
setup() {
const visible = ref(false)
const safeHeight = ref(0)
const showNotify = () => {
visible.value = true
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
visible.value = false
}, 3000)
}
onMounted(() => {
// #ifdef H5
safeHeight.value = 44
// #endif
})
return {
visible,
showNotify,
safeHeight
}
}
}
```
## 进阶`demo`
```vue
// App.vue
<script setup lang="ts">
import { onLaunch } from '@dcloudio/uni-app'
import { setNotifyDefaultOptions } from '@/uni_modules/wot-design-uni'
onLaunch(() => {
setNotifyDefaultOptions({
// #ifdef H5
safeHeight: 44,
// #endif
onClick: (event) => console.log('onClick', event),
onClosed: () => console.log('onClosed'),
onOpened: () => console.log('onOpened')
})
// 隐藏原生tabBar
uni.hideTabBar()
})
</script>
<style lang="scss">
:root, page {
// 品牌色
--wot-color-theme: #1989fa;
// 模块标题/重要正文
--wot-color-title: #323233;
// // 副标题
// --color-content: #969799;
// // 次内容
// --nut-text-color: #c8c9cc;
}
</style>
```
```vue
// /components/layout/layout.vue
<template>
<wd-config-provider>
<slot />
<TabBar />
<wd-notify selector="notify" />
</wd-config-provider>
</template>
<script lang="ts">
export default {
// #ifdef H5
name: 'Layout',
// #endif
options: { virtualHost: true, addGlobalClass: true, styleIsolation: 'shared' }
}
</script>
<script setup lang="ts">
import TabBar from './components/tabbar.vue'
</script>
```
```vue
// /pages/user.vue
<template>
<layout>
<view>User</view>
<wd-button type="primary" @click="showNotify('消息通知')">消息通知</wd-button>
</layout>
</template>
<script lang="ts">
export default {
// #ifdef H5
name: 'User',
// #endif
options: { virtualHost: true, addGlobalClass: true, styleIsolation: 'shared' }
}
</script>
<script setup lang="ts">
import { useNotify } from '@/uni_modules/wot-design-uni'
const { showNotify } = useNotify('notify')
</script>
```
## Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 | 最低版本 |
| ------------ | ----------------------------------------------------------------| ------- | ------------------------- | ------------ | -------- |
| type | 类型 | NotifyType | `primary` `success` `warning` `danger` | `danger` | - |
| message | 展示文案,支持通过`\n`换行 | string | - | - | - |
| duration | 展示时长(ms),值为 0 时notify 不会消失 | number | - | `3000` | - |
| zIndex | 层级 | number | - | `99` | - |
| position | 弹出位置 | NotifyPosition | `top` `bottom` | `top` | - |
| color | 字体颜色 | string | - | - | - |
| background | 背景颜色 | string | - | - | - |
| safeHeight | 顶部安全高度 | number / string | - | - | - |
| selector | 指定唯一标识 | number | - | - | - |
## Events
| 事件名 | 说明 | 参数 | 最低版本 |
| -------- | ----------------------------------------- | ------- | -------- |
| click | 点击时的回调函数 | (event: MouseEvent) => void | - |
| closed | 关闭时的回调函数 | () => void | - |
| opened | 展示后的回调函数 | () => void | - |
## Methods
| 方法名称 | 说明 | 参数 | 最低版本 |
| -------- | ----------------------------------------- | ------- | -------- |
| showNotify | 展示提示 | `NotifyOptions` / `string` | - |
| closeNotify | 关闭提示 | - | - |
| setNotifyDefaultOptions | 修改默认配置,影响所有的 `showNotify` 调用 | `NotifyOptions` | - |
| resetNotifyDefaultOptions | 重置默认配置,影响所有的 `showNotify` 调用 | - | - |
## NotifyOptions
调用 `showNotify``setNotifyDefaultOptions` 等方法时,支持传入以下选项:
| 参数 | 说明 | 类型 | 可选值 | 默认值 | 最低版本 |
| ------------ | ----------------------------------------------------------------| ------- | ------------------------- | ------------ | -------- |
| type | 类型 | NotifyType | `primary` `success` `warning` `danger` | `danger` | - |
| message | 展示文案,支持通过`\n`换行 | string | - | - | - |
| duration | 展示时长(ms),值为 0 时notify 不会消失 | number | - | `3000` | - |
| zIndex | 层级 | number | - | `99` | - |
| position | 弹出位置 | NotifyPosition | `top` `bottom` | `top` | - |
| color | 字体颜色 | string | - | - | - |
| background | 背景颜色 | string | - | - | - |
| safeHeight | 顶部安全高度 | number / string | - | - | - |
| onClick | 点击时的回调函数 | (event: MouseEvent) => void | - | - | - |
| onClosed | 关闭时的回调函数 | () => void | - | - | - |
| onOpened | 展示后的回调函数 | () => void | - | - | - |

View File

@ -15,6 +15,7 @@
</wd-cell> -->
<slot />
</view>
<wd-notify selector="notify" />
</wd-config-provider>
</template>
<script lang="ts">
@ -27,14 +28,27 @@ export default {
}
</script>
<script lang="ts" setup>
import { computed, ref } from 'vue'
import { computed, ref, onMounted } from 'vue'
import { setNotifyDefaultOptions } from '@/uni_modules/wot-design-uni'
import { useDark } from '../../store'
const darkMode = useDark()
const isDark = ref<boolean>(false)
const theme = computed(() => {
return darkMode.isDark.value || isDark.value ? 'dark' : 'light'
})
onMounted(() => {
setNotifyDefaultOptions({
// #ifdef H5
safeHeight: 44,
// #endif
onClick: (event) => console.log('onClick', event),
onClosed: () => console.log('onClosed'),
onOpened: () => console.log('onOpened')
})
})
</script>
<style lang="scss" scoped>
.wot-theme-dark {

View File

@ -181,6 +181,17 @@
"navigationBarTitleText": "Toast 轻提示"
}
},
{
"path": "pages/notify/Index",
"name": "toast",
"style": {
"mp-alipay": {
"allowsBounceVertical": "NO"
},
"navigationBarTitleText": "Notify 消息通知"
}
},
{
"path": "pages/loading/Index",
"name": "loading",

View File

@ -223,6 +223,10 @@ const list = ref([
id: 'toast',
name: 'Toast 轻提示'
},
{
id: 'notify',
name: 'Notify 消息通知'
},
{
id: 'tooltip',
name: 'Tooltip 文字提示'

View File

@ -0,0 +1,83 @@
<template>
<page-wraper>
<demo-block title="基本用法" transparent>
<wd-cell-group>
<wd-cell title="基础用法" is-link @click="showBasicNotify" />
</wd-cell-group>
</demo-block>
<demo-block title="通知类型" transparent>
<wd-cell-group>
<wd-cell title="主要通知" is-link @click="showType('primary')" />
<wd-cell title="成功通知" is-link @click="showType('success')" />
<wd-cell title="危险通知" is-link @click="showType('danger')" />
<wd-cell title="警告通知" is-link @click="showType('warning')" />
</wd-cell-group>
</demo-block>
<demo-block title="自定义配置" transparent>
<wd-cell-group>
<wd-cell title="自定义颜色" is-link @click="showCustomColor" />
<wd-cell title="自定义位置" is-link @click="showCustomPosition" />
<wd-cell title="自定义时长" is-link @click="showCustomDuration" />
</wd-cell-group>
</demo-block>
<demo-block title="使用 Notify 组件" transparent>
<wd-cell-group>
<wd-cell title="使用 Notify 组件" is-link @click="showNotifyComponent" />
</wd-cell-group>
</demo-block>
<wd-notify type="success" :safe-height="safeHeight" v-model:visible="visible">
<wd-icon name="check-outline" size="inherit" color="inherit" />
成功通知
</wd-notify>
</page-wraper>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import type { NotifyType } from '@/uni_modules/wot-design-uni/components/wd-notify/type'
import { useNotify } from '@/uni_modules/wot-design-uni'
let timer: ReturnType<typeof setTimeout>
const visible = ref(false)
const safeHeight = ref(0)
const { showNotify } = useNotify('notify')
const showType = (type: NotifyType) => {
showNotify({
message: '通知内容',
type
})
}
const showBasicNotify = () => showNotify('测试')
const showCustomColor = () => {
showNotify({
color: '#ad0000',
message: '自定义颜色',
background: '#ffe1e1'
})
}
const showCustomPosition = () => {
showNotify({
message: '自定义位置',
position: 'bottom'
})
}
const showCustomDuration = () => {
showNotify({
message: '自定义时长',
duration: 1000
})
}
const showNotifyComponent = () => {
visible.value = true
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
visible.value = false
}, 2000)
}
onMounted(() => {
// #ifdef H5
safeHeight.value = 44
// #endif
})
</script>

View File

@ -702,3 +702,13 @@ $-upload-preview-name-height: var(--wot-upload-preview-name-height, 22px) !defau
$-curtain-content-radius: var(--wot-curtain-content-radius, 24px) !default; // 内容圆角
$-curtain-content-close-color: var(--wot-curtain-content-close-color, $-color-white) !default; // 关闭按钮颜色
$-curtain-content-close-fs: var(--wot-curtain-content-close-fs, $-fs-big) !default; // 关闭按钮大小
// Notify
$notify-text-color: var(--wot-notify-text-color, $-color-white) !default;
$notify-padding: var(--wot-notify-padding, 8px 16px) !default;
$notify-font-size: var(--wot-notify-font-size, $-fs-content) !default;
$notify-line-height: var(--wot-notify-line-height, 20px) !default;
$notify-primary-background: var(--wot-notify-primary-background, $-color-theme) !default;
$notify-success-background: var(--wot-notify-success-background, $-color-success) !default;
$notify-danger-background: var(--wot-notify-danger-background, $-color-danger) !default;
$notify-warning-background: var(--wot-notify-warning-background, $-color-warning) !default;

View File

@ -235,10 +235,19 @@ export function isArray(value: any) {
/**
*
* @param {Object} value
* @param {Function} value
*/
export function isFunction(value): boolean {
return typeof value === 'function'
// eslint-disable-next-line @typescript-eslint/ban-types
export function isFunction<T extends Function>(value: any): value is T {
return getType(value) === 'function'
}
/**
*
* @param {unknown} value
*/
export function isString(value: unknown): value is string {
return getType(value) === 'string'
}
/**

View File

@ -0,0 +1,34 @@
@import '../common/abstracts/variable';
@import '../common/abstracts/mixin';
@include b(notify) {
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
padding: $notify-padding;
font-size: $notify-font-size;
line-height: $notify-line-height;
color: $notify-text-color;
// allow newline character
white-space: pre-wrap;
text-align: center;
word-wrap: break-word;
@include m(primary) {
background: $notify-primary-background;
}
@include m(success) {
background: $notify-success-background;
}
@include m(danger) {
background: $notify-danger-background;
}
@include m(warning) {
background: $notify-warning-background;
}
}

View File

@ -0,0 +1,58 @@
import type { InjectionKey } from 'vue'
import { ref, provide, reactive } from 'vue'
import type { NotifyProps } from './type'
import { deepMerge, getType } from '../common/util'
let timer: ReturnType<typeof setTimeout>
let currentOptions = getDefaultOptions()
const notifyOptionKey = '__NOTIFY_OPTION__'
const notifyDefaultOptionKey = Symbol(notifyOptionKey) as InjectionKey<NotifyProps>
export const setNotifyDefaultOptions = (options: NotifyProps) => {
currentOptions = deepMerge(currentOptions, options) as NotifyProps
}
export const resetNotifyDefaultOptions = () => {
currentOptions = getDefaultOptions()
}
export const useNotify = (selector: string = '') => {
const notifyOption = reactive<NotifyProps>(currentOptions)
const showNotify = (option: NotifyProps | string) => {
const options = deepMerge(currentOptions, getType(option) === 'string' ? { message: option } : option) as NotifyProps
Object.assign(notifyOption, options, { visible: true })
if (notifyOption.duration && notifyOption.duration > 0) {
timer && clearTimeout(timer)
timer = setTimeout(() => closeNotify(), options.duration)
}
}
const closeNotify = () => {
timer && clearTimeout(timer)
notifyOption.visible = false
}
// provide
provide(getNotifyOptionKey(selector), notifyOption)
return {
showNotify,
closeNotify
}
}
export const getNotifyOptionKey = (selector: string) => {
return selector ? `${notifyOptionKey}${selector}` : notifyDefaultOptionKey
}
function getDefaultOptions(): NotifyProps {
return {
type: 'danger',
color: undefined,
zIndex: 99,
message: '',
duration: 3000,
position: 'top',
safeHeight: undefined,
background: undefined,
onClick: undefined,
onClosed: undefined,
onOpened: undefined
}
}

View File

@ -0,0 +1,91 @@
import type { PropType, ExtractPropTypes } from 'vue'
export type NotifyMessage = string | number
export type NotifyType = 'primary' | 'success' | 'danger' | 'warning'
export type NotifyPosition = 'top' | 'bottom'
export type NotifyProps = Omit<Partial<ExtractPropTypes<typeof notifyProps>>, 'selector'> & {
onClick?: (event: MouseEvent) => void
onClosed?: () => void
onOpened?: () => void
}
export type NotifyThemeVars = {
notifyPadding?: string
notifyFontSize?: string
notifyTextColor?: string
notifyLineHeight?: number | string
notifyDangerBackground?: string
notifyPrimaryBackground?: string
notifySuccessBackground?: string
notifyWarningBackground?: string
}
export const notifyProps = {
/**
* primary success danger warning
*/
type: {
type: String as PropType<NotifyType>,
default: 'danger'
},
/**
*
*/
color: {
type: String,
default: ''
},
/**
* z-index
*/
zIndex: {
type: Number,
default: 99
},
/**
*
*/
visible: {
type: Boolean,
default: false
},
/**
* \n换行
*/
message: {
type: [Number, String] as PropType<NotifyMessage>,
default: ''
},
/**
*
*/
selector: {
type: String,
default: ''
},
/**
* (ms) 0 notify
*/
duration: {
type: Number,
default: 3000
},
/**
* top bottom
*/
position: {
type: String as PropType<NotifyPosition>,
default: 'top'
},
/**
*
*/
safeHeight: {
type: Number
},
/**
*
*/
background: {
type: String,
default: ''
}
}

View File

@ -0,0 +1,69 @@
<template>
<wd-popup
v-model="state.visible"
:custom-style="customStyle"
:position="state.position"
:z-index="state.zIndex"
:duration="250"
:modal="false"
@leave="onClosed"
@enter="onOpened"
>
<view class="wd-notify" :class="[`wd-notify--${state.type}`]" :style="{ color: state.color, background: state.background }" @click="onClick">
<slot>{{ state.message }}</slot>
</view>
</wd-popup>
</template>
<script lang="ts">
export default {
// #ifdef H5
name: 'wd-notify',
// #endif
options: { virtualHost: true, addGlobalClass: true, styleIsolation: 'shared' }
}
</script>
<script lang="ts" setup>
import { inject, computed, watch } from 'vue'
import { notifyProps, NotifyProps } from './type'
import { getNotifyOptionKey } from '.'
import { isDef, addUnit, isFunction } from '../common/util'
const props = defineProps(notifyProps)
const emits = defineEmits<{
(e: 'update:visible', value: boolean): void
(e: 'click', event: MouseEvent): void
(e: 'closed'): void
(e: 'opened'): void
}>()
const state = inject<NotifyProps>(getNotifyOptionKey(props.selector), props)
const customStyle = computed(() => {
const { safeHeight, position } = state
if (!isDef(safeHeight) || position !== 'top') return ''
return `top: ${addUnit(safeHeight)}`
})
const onClick = (event: MouseEvent) => {
if (isFunction(state.onClick)) return state.onClick(event)
emits('click', event)
}
const onClosed = () => {
if (isFunction(state.onClosed)) return state.onClosed()
emits('closed')
}
const onOpened = () => {
if (isFunction(state.onOpened)) return state.onOpened()
emits('opened')
}
watch(
() => state.visible,
(visible) => emits('update:visible', visible as boolean)
)
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>

View File

@ -12,7 +12,9 @@
export { useToast } from './components/wd-toast'
// Messageb
export { useMessage } from './components/wd-message-box'
// Loading
// Notify
export * from './components/wd-notify'
export { dayjs } from './components/common/dayjs'
export * as CommonUtil from './components/common/util'