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(
-
+