From a29c78d0e0b895c02eaf0973a30dd1fe15949768 Mon Sep 17 00:00:00 2001 From: Tinsson <695724046@qq.com> Date: Tue, 16 Apr 2024 10:29:12 +0800 Subject: [PATCH] =?UTF-8?q?feat(notify)=EF=BC=9Aadd=20containerSelector=20?= =?UTF-8?q?and=20className=20prop=20support=20(#2046)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/zent/__tests__/notify.spec.jsx | 58 +++++++++++++ packages/zent/assets/notify.scss | 4 + packages/zent/src/notify/Notify.tsx | 82 +++++++++++++++---- packages/zent/src/notify/README_en-US.md | 19 +++-- packages/zent/src/notify/README_zh-CN.md | 19 +++-- .../notify/demos/custom-container-selector.md | 32 ++++++++ .../notify/demos/global-container-selector.md | 36 ++++++++ .../zent/src/notify/demos/global-duration.md | 3 +- 8 files changed, 225 insertions(+), 28 deletions(-) create mode 100644 packages/zent/src/notify/demos/custom-container-selector.md create mode 100644 packages/zent/src/notify/demos/global-container-selector.md diff --git a/packages/zent/__tests__/notify.spec.jsx b/packages/zent/__tests__/notify.spec.jsx index cc6a8397b6..d8dd06481d 100644 --- a/packages/zent/__tests__/notify.spec.jsx +++ b/packages/zent/__tests__/notify.spec.jsx @@ -63,4 +63,62 @@ describe('Notify component', () => { jest.advanceTimersByTime(1800); expect(document.querySelectorAll('.zent-notify').length).toBe(0); }); + + it('custom container selector', () => { + const div = document.createElement('div'); + div.className = 'custom-container'; + document.body.appendChild(div); + + const cb = jest.fn(); + Notify.info('test info', 3000, cb, '.custom-container'); + jest.advanceTimersByTime(1000); + + expect( + document.querySelectorAll('.custom-container > .zent-notify-container') + .length + ).toBe(1); + + Notify.error('test error', 3000); + jest.advanceTimersByTime(1000); + expect( + document.querySelectorAll('body > .zent-notify-container').length + ).toBe(1); + + Notify.error('test error', 3000, cb, '.empty-class'); + jest.advanceTimersByTime(1000); + expect( + document.querySelectorAll('.empty-class > .zent-notify-container').length + ).toBe(0); + }); + + it('custom container class name', () => { + const cb = jest.fn(); + Notify.error('test error', 3000, cb, '', 'test-custom-container'); + jest.advanceTimersByTime(1000); + + expect( + document.querySelectorAll('.zent-notify-container.test-custom-container') + .length + ).toBe(1); + }); + + it('Global default container selector', () => { + const div = document.createElement('div'); + div.className = 'custom-container'; + document.body.appendChild(div); + + Notify.config({ containerSelector: '.custom-container' }); + Notify.error('test error', 2000); + jest.advanceTimersByTime(1000); + + expect( + document.querySelectorAll('.custom-container > .zent-notify-container') + .length + ).toBe(1); + }); + + it('react node content', () => { + Notify.error(
test error
); + expect(document.querySelectorAll('.zent-notify').length).toBe(1); + }); }); diff --git a/packages/zent/assets/notify.scss b/packages/zent/assets/notify.scss index a86a7e9a47..a8d7ce8276 100644 --- a/packages/zent/assets/notify.scss +++ b/packages/zent/assets/notify.scss @@ -9,6 +9,10 @@ $transition-duration: 160ms; top: 80px; left: 50%; transform: translateX(-50%); + + &.zent-notify-container-custom { + position: absolute; + } } .zent-notify { diff --git a/packages/zent/src/notify/Notify.tsx b/packages/zent/src/notify/Notify.tsx index cac1c79921..91a9588bab 100644 --- a/packages/zent/src/notify/Notify.tsx +++ b/packages/zent/src/notify/Notify.tsx @@ -6,6 +6,7 @@ import NotifyContent from './NotifyContent'; let index = 0; let durationDefault = 3500; +let containerSelectorDefault = 'body'; const containerList = {}; const notifyContainerClass = 'zent-notify-container'; @@ -52,18 +53,44 @@ const closeAllNotify = () => { }; /** - * 创建承载notify portal的容器 + * 添加className,需要检查是否存在 + * @param {HTMLElement} node dom节点 + * @param {String} className class名称 */ -const createNotifyContainerNode = (): HTMLElement => { +const addClassName = (node: HTMLElement, className: string) => { + if (node.classList && !node.classList.contains(className)) { + node.classList.add(className); + } +}; + +/** + * 创建承载notify portal的容器,containerSelector可以自定义notify的挂载位置 + */ +const createNotifyContainerNode = ( + containerSelector, + className +): HTMLElement => { + const rootContainerSelector = containerSelector || containerSelectorDefault; + let notifyContainerNode = document.querySelector( - '.zent-notify-container' + `${rootContainerSelector} > .${notifyContainerClass}` ); + const rootContainer = + document.querySelector(rootContainerSelector) || document.body; + if (!notifyContainerNode) { - const bodyNode = document.body; const div = createElement('div'); div.className = notifyContainerClass; - notifyContainerNode = bodyNode.appendChild(div); + notifyContainerNode = rootContainer.appendChild(div); + } + + if (className) { + addClassName(notifyContainerNode, className); + } + + if (rootContainerSelector !== 'body') { + addClassName(notifyContainerNode, 'zent-notify-container-custom'); } return notifyContainerNode; @@ -75,17 +102,24 @@ const createNotifyContainerNode = (): HTMLElement => { * @param {[type]} duration 显示时长 * @param {[type]} status notify状态 * @param {Function} callback notify消失时回调 + * @param {[String]} containerSelector 自定义父容器挂载节点 + * @param {[String]} className 自定义样式类 */ const show = ( text: ReactNode, duration?: number, status?: string, - callback?: () => void + callback?: () => void, + containerSelector?: string, + className?: string ) => { if (!isBrowser) return null; const container = createElement('div'); - const notifyContainerNode = createNotifyContainerNode(); + const notifyContainerNode = createNotifyContainerNode( + containerSelector, + className + ); const props: any = { text, status, @@ -117,33 +151,48 @@ const show = ( export function success( text: ReactNode, duration?: number, - callback?: () => void + callback?: () => void, + containerSelector?: string, + className?: string ) { - return show(text, duration, 'success', callback); + return show( + text, + duration, + 'success', + callback, + containerSelector, + className + ); } export function warn( text: ReactNode, duration?: number, - callback?: () => void + callback?: () => void, + containerSelector?: string, + className?: string ) { - return show(text, duration, 'warn', callback); + return show(text, duration, 'warn', callback, containerSelector, className); } export function error( text: ReactNode, duration?: number, - callback?: () => void + callback?: () => void, + containerSelector?: string, + className?: string ) { - return show(text, duration, 'error', callback); + return show(text, duration, 'error', callback, containerSelector, className); } export function info( text: ReactNode, duration?: number, - callback?: () => void + callback?: () => void, + containerSelector?: string, + className?: string ) { - return show(text, duration, 'info', callback); + return show(text, duration, 'info', callback, containerSelector, className); } export function clear(containerId) { @@ -158,4 +207,7 @@ export function config(options) { if (options.duration) { durationDefault = options.duration; } + if (options.containerSelector) { + containerSelectorDefault = options.containerSelector; + } } diff --git a/packages/zent/src/notify/README_en-US.md b/packages/zent/src/notify/README_en-US.md index f3ad71dae3..ed856b2205 100644 --- a/packages/zent/src/notify/README_en-US.md +++ b/packages/zent/src/notify/README_en-US.md @@ -14,10 +14,10 @@ Display a notification at top of the viewport. ### API -- `Notify.info(text: node, duration?: number, callback?: () => ()): number` -- `Notify.success(text: node, duration?: number, callback?: () => ()): number` -- `Notify.warn(text: node, duration?: number, callback?: () => ()): number` -- `Notify.error(text: node, duration?: number, callback?: () => ()): number` +- `Notify.info(text: node, duration?: number, callback?: () => (), containerSelector?: string, className?: string): number` +- `Notify.success(text: node, duration?: number, callback?: () => (), containerSelector?: string, className?: string): number` +- `Notify.warn(text: node, duration?: number, callback?: () => (), containerSelector?: string, className?: string): number` +- `Notify.error(text: node, duration?: number, callback?: () => (), containerSelector?: string, className?: string): number` `Notify.info`, `Notify.success`, `Notify.warn` and `Notify.error` return an id, which can be used by `Notify.clear(id)` to close the specific notify instance; @@ -26,11 +26,18 @@ Display a notification at top of the viewport. | text | notify message | node | `''` | | duration | duration | number | `3500` | | callback | customize callabck when notify closes | func | | +| containerSelector `v9.12.14` | notify's parent node CSS selector | string | `'body'` | +| className `v9.12.14` | Custom class name | string | | - `Notify.clear(number?: id): void` If no `id` is passed to `Notify.clear`, it will close all notify instances that are active. -- `Notify.config(options): void` +- `Notify.config(options: Options): void` -`duration` is the only supported parameter in `options`, it is used to set `Notify` duration globally. +### Options + +| Property | Description | Type | Default | +| ----------- | ------------ | ------ | ------ | +| duration | global duration | number | `3500` | +| containerSelector `v9.12.14` | notify's parent node CSS selector | string | `'body'` | diff --git a/packages/zent/src/notify/README_zh-CN.md b/packages/zent/src/notify/README_zh-CN.md index 0518f578d0..70d12b4c41 100644 --- a/packages/zent/src/notify/README_zh-CN.md +++ b/packages/zent/src/notify/README_zh-CN.md @@ -15,10 +15,10 @@ group: 反馈 ### API -- `Notify.info(text: node, duration?: number, callback?: () => ()): number` -- `Notify.success(text: node, duration?: number, callback?: () => ()): number` -- `Notify.warn(text: node, duration?: number, callback?: () => ()): number` -- `Notify.error(text: node, duration?: number, callback?: () => ()): number` +- `Notify.info(text: node, duration?: number, callback?: () => (), containerSelector?: string, className?: string): number` +- `Notify.success(text: node, duration?: number, callback?: () => (), containerSelector?: string, className?: string): number` +- `Notify.warn(text: node, duration?: number, callback?: () => (), containerSelector?: string, className?: string): number` +- `Notify.error(text: node, duration?: number, callback?: () => (), containerSelector?: string, className?: string): number` `Notify.info`,`Notify.success`,`Notify.warn` 和 `Notify.error` 方法会返回一个 `id`,这个 `id` 可以作为 `Notify.clear(id)` 的入参,用于关闭指定notify。 @@ -27,11 +27,18 @@ group: 反馈 | text | 通知文案 | node | `''` | | duration | 持续时间 | number | `3500` | | callback | 关闭时的回调 | func | | +| containerSelector `v9.12.14` | 提示组件的父节点CSS selector | string | `'body'` | +| className `v9.12.14` | 自定义类名 | string | | - `Notify.clear(number: id): void` 如果 `Notify.clear` 调用时没有传入 `id` 参数,所有当前未关闭的实例都会被关闭。 -- `Notify.config(options): void` +- `Notify.config(options: Options): void` -`options` 当前只支持一个设置:`duration`,可以用来全局设置 `Notify` 的关闭延迟时间。 +### Options + +| 参数 | 说明 | 类型 | 默认值 | +| ----------- | ------------ | ------ | ------ | +| duration | 全局持续时间 | number | `3500` | +| containerSelector `v9.12.14` | 提示组件的父节点CSS selector | string | `'body'` | diff --git a/packages/zent/src/notify/demos/custom-container-selector.md b/packages/zent/src/notify/demos/custom-container-selector.md new file mode 100644 index 0000000000..4d2a67e183 --- /dev/null +++ b/packages/zent/src/notify/demos/custom-container-selector.md @@ -0,0 +1,32 @@ +--- +order: 7 +zh-CN: + title: 自定义父节点CSS selector + name: 自定义父节点 + +en-US: + title: Custom notify parent container css selector + name: custom notify content container + +--- + +```jsx +import { Notify, Button } from 'zent'; + +function customContent() { + Notify.success('{i18n.name}', '', () => {}, '#custom-container'); +} + +const relativeStyle = { + position: 'relative' +} + +ReactDOM.render( +
+ +
+
+ , mountNode +); + +``` diff --git a/packages/zent/src/notify/demos/global-container-selector.md b/packages/zent/src/notify/demos/global-container-selector.md new file mode 100644 index 0000000000..6bf4ebae5d --- /dev/null +++ b/packages/zent/src/notify/demos/global-container-selector.md @@ -0,0 +1,36 @@ + +--- +order: 8 +zh-CN: + title: 通过 config 调整全局挂载父节点 + name: 调整挂载父节点 + reset: 重置挂载父节点 + info: 常规提示 +en-US: + title: Adjust the global default container selector through Notify.config + name: Set global container selector to custom + reset: Reset global container selector config + info: info + +--- + +```jsx +import { Notify, Button } from 'zent'; + +const relativeStyle = { + position: 'relative' +} + +ReactDOM.render( +
+ + +
+
+
+ +
+ , mountNode +); + +``` diff --git a/packages/zent/src/notify/demos/global-duration.md b/packages/zent/src/notify/demos/global-duration.md index bd1751b78e..441b4e6dca 100644 --- a/packages/zent/src/notify/demos/global-duration.md +++ b/packages/zent/src/notify/demos/global-duration.md @@ -1,3 +1,4 @@ + --- order: 2 zh-CN: @@ -26,7 +27,7 @@ ReactDOM.render(
-
+