@jumerry/elplus-hooks 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +86 -0
- package/dist/index.cjs +135 -0
- package/dist/index.d.cts +27 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +98 -0
- package/package.json +47 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 - 2026-03-06
|
|
4
|
+
|
|
5
|
+
- 初始化 `elplus-hooks` npm 包。
|
|
6
|
+
- 新增 `useDialog` 组合式函数导出。
|
|
7
|
+
- 增加 `README.md`(安装、API、示例、发布说明)。
|
|
8
|
+
- 增加 `tsup` 构建配置(ESM/CJS/类型声明)。
|
|
9
|
+
- 配置 `peerDependencies`:`vue`、`element-plus`、`lodash`。
|
|
10
|
+
|
|
11
|
+
## 0.1.1 - 2026-03-06
|
|
12
|
+
|
|
13
|
+
- 包名调整为 `@jumerry/elplus-hooks`
|
|
14
|
+
- README 安装与导入示例已同步 scoped 包名
|
package/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# elplus-hooks
|
|
2
|
+
|
|
3
|
+
Element Plus 相关 Vue 组合式函数库(当前仅包含 `useDialog`)。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i @jumerry/elplus-hooks
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
你还需要在业务项目中安装以下 peer 依赖(若已安装可忽略):
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm i vue element-plus lodash
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 导出
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { useDialog } from "@jumerry/elplus-hooks";
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## API
|
|
24
|
+
|
|
25
|
+
### `useDialog<P = any>(content, options?)`
|
|
26
|
+
|
|
27
|
+
#### 参数
|
|
28
|
+
|
|
29
|
+
- `content`: `string | Component | JSX.Element`
|
|
30
|
+
- `options`: `DialogOptions<P> | Ref<DialogOptions<P>>`
|
|
31
|
+
|
|
32
|
+
#### `DialogOptions<P>`
|
|
33
|
+
|
|
34
|
+
- `dialogProps`: 透传给 `ElDialog` 的属性,额外支持 `onBeforeOpen?: () => boolean | void`
|
|
35
|
+
- `dialogSlots`: Dialog 插槽(`header`、`footer`)
|
|
36
|
+
- `contentProps`: 透传给内容组件 props
|
|
37
|
+
- `callBack`: 内容组件触发回调时执行
|
|
38
|
+
- `closeEventName`: 自定义关闭事件名(默认 `closeDialog`)
|
|
39
|
+
- `emits`: 事件映射,会自动转换为 `onXxx` 监听
|
|
40
|
+
|
|
41
|
+
#### 返回值
|
|
42
|
+
|
|
43
|
+
- `openDialog(modifyOptions?)`: 打开弹窗,可临时覆盖 `options`
|
|
44
|
+
- `closeDialog()`: 关闭弹窗
|
|
45
|
+
|
|
46
|
+
## 使用示例
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { defineComponent } from "vue";
|
|
50
|
+
import { useDialog } from "@jumerry/elplus-hooks";
|
|
51
|
+
|
|
52
|
+
const ContentComp = defineComponent({
|
|
53
|
+
props: {
|
|
54
|
+
title: String,
|
|
55
|
+
closeDialog: Function
|
|
56
|
+
},
|
|
57
|
+
setup(props) {
|
|
58
|
+
return () => (
|
|
59
|
+
<div>
|
|
60
|
+
<p>{props.title}</p>
|
|
61
|
+
<button onClick={() => props.closeDialog?.()}>关闭</button>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const { openDialog } = useDialog(ContentComp, {
|
|
68
|
+
contentProps: { title: "弹窗内容" },
|
|
69
|
+
dialogProps: { title: "提示", width: "480px" }
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
openDialog();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 发布
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npm login
|
|
79
|
+
npm run build
|
|
80
|
+
npm publish --access public
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 注意事项
|
|
84
|
+
|
|
85
|
+
- 本库会操作 `document.body`,请仅在浏览器端调用。
|
|
86
|
+
- SSR 场景请在客户端生命周期中调用 `openDialog`。
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
useDialog: () => useDialog
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
|
+
|
|
37
|
+
// src/useDialog.ts
|
|
38
|
+
var import_element_plus = require("element-plus");
|
|
39
|
+
var import_lodash = require("lodash");
|
|
40
|
+
var import_merge = __toESM(require("lodash/merge"), 1);
|
|
41
|
+
var import_vue = require("vue");
|
|
42
|
+
function getOptions(options) {
|
|
43
|
+
if (!options) return {};
|
|
44
|
+
return (0, import_vue.isRef)(options) ? options.value : options;
|
|
45
|
+
}
|
|
46
|
+
function useDialog(content, options) {
|
|
47
|
+
let dialogInstance = null;
|
|
48
|
+
let fragment = null;
|
|
49
|
+
const closeAfter = () => {
|
|
50
|
+
if (fragment) {
|
|
51
|
+
(0, import_vue.render)(null, fragment);
|
|
52
|
+
fragment.textContent = "";
|
|
53
|
+
fragment = null;
|
|
54
|
+
}
|
|
55
|
+
dialogInstance = null;
|
|
56
|
+
};
|
|
57
|
+
async function closeDialog() {
|
|
58
|
+
if (dialogInstance) {
|
|
59
|
+
dialogInstance.props.modelValue = false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const instance = (0, import_vue.getCurrentInstance)();
|
|
63
|
+
function openDialog(modifyOptions) {
|
|
64
|
+
if (dialogInstance) {
|
|
65
|
+
closeDialog().then(() => closeAfter());
|
|
66
|
+
}
|
|
67
|
+
const baseOptions = getOptions(options);
|
|
68
|
+
const mergedOptions = modifyOptions ? (0, import_merge.default)({}, baseOptions, modifyOptions) : baseOptions;
|
|
69
|
+
const { dialogProps, contentProps } = mergedOptions;
|
|
70
|
+
if (dialogProps?.onBeforeOpen?.() === false) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
fragment = document.createDocumentFragment();
|
|
74
|
+
const closeEventName = `on${(0, import_lodash.upperFirst)(
|
|
75
|
+
mergedOptions.closeEventName || "closeDialog"
|
|
76
|
+
)}`;
|
|
77
|
+
let onBeforeClose = null;
|
|
78
|
+
const contentAttrs = {
|
|
79
|
+
...contentProps,
|
|
80
|
+
[closeEventName]: closeDialog,
|
|
81
|
+
callBack: (data) => {
|
|
82
|
+
mergedOptions.callBack?.(data);
|
|
83
|
+
closeDialog();
|
|
84
|
+
},
|
|
85
|
+
beforeCloseDialog: (fn) => {
|
|
86
|
+
onBeforeClose = fn;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const eventListeners = {};
|
|
90
|
+
if (mergedOptions.emits) {
|
|
91
|
+
for (const [eventName, handler] of Object.entries(mergedOptions.emits)) {
|
|
92
|
+
const listenerName = `on${(0, import_lodash.upperFirst)(eventName)}`;
|
|
93
|
+
eventListeners[listenerName] = handler;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const vNode = (0, import_vue.h)(
|
|
97
|
+
import_element_plus.ElDialog,
|
|
98
|
+
{
|
|
99
|
+
...dialogProps,
|
|
100
|
+
modelValue: true,
|
|
101
|
+
beforeClose: async (done) => {
|
|
102
|
+
const result = await onBeforeClose?.();
|
|
103
|
+
if (result === false) return;
|
|
104
|
+
done();
|
|
105
|
+
},
|
|
106
|
+
onClosed: () => {
|
|
107
|
+
dialogProps?.onClosed?.();
|
|
108
|
+
closeAfter();
|
|
109
|
+
onBeforeClose = null;
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
default: () => [
|
|
114
|
+
typeof content === "string" ? content : (0, import_vue.h)(content, {
|
|
115
|
+
...contentAttrs,
|
|
116
|
+
...eventListeners
|
|
117
|
+
})
|
|
118
|
+
],
|
|
119
|
+
...mergedOptions.dialogSlots
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
vNode.appContext = instance?.appContext || null;
|
|
123
|
+
(0, import_vue.render)(vNode, fragment);
|
|
124
|
+
dialogInstance = vNode.component;
|
|
125
|
+
document.body.appendChild(fragment);
|
|
126
|
+
}
|
|
127
|
+
(0, import_vue.onUnmounted)(() => {
|
|
128
|
+
closeDialog();
|
|
129
|
+
});
|
|
130
|
+
return { openDialog, closeDialog };
|
|
131
|
+
}
|
|
132
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
133
|
+
0 && (module.exports = {
|
|
134
|
+
useDialog
|
|
135
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ElDialog } from 'element-plus';
|
|
2
|
+
import { h, Ref } from 'vue';
|
|
3
|
+
import { JSX } from 'vue/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
type Content = Parameters<typeof h>[0] | string | object | JSX.Element;
|
|
6
|
+
type ElDialogInstance = InstanceType<typeof ElDialog>;
|
|
7
|
+
type DialogProps = ElDialogInstance["$props"] & {
|
|
8
|
+
onBeforeOpen?: () => boolean | void;
|
|
9
|
+
};
|
|
10
|
+
interface ElDialogSlots {
|
|
11
|
+
header?: (...args: any[]) => Content;
|
|
12
|
+
footer?: (...args: any[]) => Content;
|
|
13
|
+
}
|
|
14
|
+
interface DialogOptions<P> {
|
|
15
|
+
dialogProps?: DialogProps;
|
|
16
|
+
dialogSlots?: ElDialogSlots;
|
|
17
|
+
contentProps?: P;
|
|
18
|
+
callBack?: (data: any) => void;
|
|
19
|
+
closeEventName?: string;
|
|
20
|
+
emits?: Record<string, (...args: any[]) => void>;
|
|
21
|
+
}
|
|
22
|
+
declare function useDialog<P = any>(content: Content, options?: Ref<DialogOptions<P>> | DialogOptions<P>): {
|
|
23
|
+
openDialog: (modifyOptions?: Partial<DialogOptions<P>>) => void;
|
|
24
|
+
closeDialog: () => Promise<void>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export { type DialogOptions, useDialog };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ElDialog } from 'element-plus';
|
|
2
|
+
import { h, Ref } from 'vue';
|
|
3
|
+
import { JSX } from 'vue/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
type Content = Parameters<typeof h>[0] | string | object | JSX.Element;
|
|
6
|
+
type ElDialogInstance = InstanceType<typeof ElDialog>;
|
|
7
|
+
type DialogProps = ElDialogInstance["$props"] & {
|
|
8
|
+
onBeforeOpen?: () => boolean | void;
|
|
9
|
+
};
|
|
10
|
+
interface ElDialogSlots {
|
|
11
|
+
header?: (...args: any[]) => Content;
|
|
12
|
+
footer?: (...args: any[]) => Content;
|
|
13
|
+
}
|
|
14
|
+
interface DialogOptions<P> {
|
|
15
|
+
dialogProps?: DialogProps;
|
|
16
|
+
dialogSlots?: ElDialogSlots;
|
|
17
|
+
contentProps?: P;
|
|
18
|
+
callBack?: (data: any) => void;
|
|
19
|
+
closeEventName?: string;
|
|
20
|
+
emits?: Record<string, (...args: any[]) => void>;
|
|
21
|
+
}
|
|
22
|
+
declare function useDialog<P = any>(content: Content, options?: Ref<DialogOptions<P>> | DialogOptions<P>): {
|
|
23
|
+
openDialog: (modifyOptions?: Partial<DialogOptions<P>>) => void;
|
|
24
|
+
closeDialog: () => Promise<void>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export { type DialogOptions, useDialog };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// src/useDialog.ts
|
|
2
|
+
import { ElDialog } from "element-plus";
|
|
3
|
+
import { upperFirst } from "lodash";
|
|
4
|
+
import merge from "lodash/merge";
|
|
5
|
+
import { getCurrentInstance, h, isRef, onUnmounted, render } from "vue";
|
|
6
|
+
function getOptions(options) {
|
|
7
|
+
if (!options) return {};
|
|
8
|
+
return isRef(options) ? options.value : options;
|
|
9
|
+
}
|
|
10
|
+
function useDialog(content, options) {
|
|
11
|
+
let dialogInstance = null;
|
|
12
|
+
let fragment = null;
|
|
13
|
+
const closeAfter = () => {
|
|
14
|
+
if (fragment) {
|
|
15
|
+
render(null, fragment);
|
|
16
|
+
fragment.textContent = "";
|
|
17
|
+
fragment = null;
|
|
18
|
+
}
|
|
19
|
+
dialogInstance = null;
|
|
20
|
+
};
|
|
21
|
+
async function closeDialog() {
|
|
22
|
+
if (dialogInstance) {
|
|
23
|
+
dialogInstance.props.modelValue = false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const instance = getCurrentInstance();
|
|
27
|
+
function openDialog(modifyOptions) {
|
|
28
|
+
if (dialogInstance) {
|
|
29
|
+
closeDialog().then(() => closeAfter());
|
|
30
|
+
}
|
|
31
|
+
const baseOptions = getOptions(options);
|
|
32
|
+
const mergedOptions = modifyOptions ? merge({}, baseOptions, modifyOptions) : baseOptions;
|
|
33
|
+
const { dialogProps, contentProps } = mergedOptions;
|
|
34
|
+
if (dialogProps?.onBeforeOpen?.() === false) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
fragment = document.createDocumentFragment();
|
|
38
|
+
const closeEventName = `on${upperFirst(
|
|
39
|
+
mergedOptions.closeEventName || "closeDialog"
|
|
40
|
+
)}`;
|
|
41
|
+
let onBeforeClose = null;
|
|
42
|
+
const contentAttrs = {
|
|
43
|
+
...contentProps,
|
|
44
|
+
[closeEventName]: closeDialog,
|
|
45
|
+
callBack: (data) => {
|
|
46
|
+
mergedOptions.callBack?.(data);
|
|
47
|
+
closeDialog();
|
|
48
|
+
},
|
|
49
|
+
beforeCloseDialog: (fn) => {
|
|
50
|
+
onBeforeClose = fn;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const eventListeners = {};
|
|
54
|
+
if (mergedOptions.emits) {
|
|
55
|
+
for (const [eventName, handler] of Object.entries(mergedOptions.emits)) {
|
|
56
|
+
const listenerName = `on${upperFirst(eventName)}`;
|
|
57
|
+
eventListeners[listenerName] = handler;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const vNode = h(
|
|
61
|
+
ElDialog,
|
|
62
|
+
{
|
|
63
|
+
...dialogProps,
|
|
64
|
+
modelValue: true,
|
|
65
|
+
beforeClose: async (done) => {
|
|
66
|
+
const result = await onBeforeClose?.();
|
|
67
|
+
if (result === false) return;
|
|
68
|
+
done();
|
|
69
|
+
},
|
|
70
|
+
onClosed: () => {
|
|
71
|
+
dialogProps?.onClosed?.();
|
|
72
|
+
closeAfter();
|
|
73
|
+
onBeforeClose = null;
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
default: () => [
|
|
78
|
+
typeof content === "string" ? content : h(content, {
|
|
79
|
+
...contentAttrs,
|
|
80
|
+
...eventListeners
|
|
81
|
+
})
|
|
82
|
+
],
|
|
83
|
+
...mergedOptions.dialogSlots
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
vNode.appContext = instance?.appContext || null;
|
|
87
|
+
render(vNode, fragment);
|
|
88
|
+
dialogInstance = vNode.component;
|
|
89
|
+
document.body.appendChild(fragment);
|
|
90
|
+
}
|
|
91
|
+
onUnmounted(() => {
|
|
92
|
+
closeDialog();
|
|
93
|
+
});
|
|
94
|
+
return { openDialog, closeDialog };
|
|
95
|
+
}
|
|
96
|
+
export {
|
|
97
|
+
useDialog
|
|
98
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jumerry/elplus-hooks",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Element Plus 相关 Vue 组合式函数集合(当前仅 useDialog)",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"vue",
|
|
7
|
+
"element-plus",
|
|
8
|
+
"composable",
|
|
9
|
+
"hook",
|
|
10
|
+
"dialog"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"author": "zyc",
|
|
14
|
+
"type": "module",
|
|
15
|
+
"main": "./dist/index.cjs",
|
|
16
|
+
"module": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.js",
|
|
22
|
+
"require": "./dist/index.cjs"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"README.md",
|
|
28
|
+
"CHANGELOG.md"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsup src/index.ts --format esm,cjs --dts --clean --external vue,element-plus,lodash,lodash/merge",
|
|
32
|
+
"check": "tsc --noEmit",
|
|
33
|
+
"prepublishOnly": "npm run build"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"element-plus": ">=2.8.0",
|
|
37
|
+
"lodash": ">=4.17.21",
|
|
38
|
+
"vue": ">=3.4.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"tsup": "^8.5.0",
|
|
42
|
+
"typescript": "^5.9.2"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
}
|
|
47
|
+
}
|