qlfy-postmate 1.1.8 → 1.2.0

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/README.md CHANGED
@@ -1,208 +1,51 @@
1
- ### 子系统认证通信插件使用文档
1
+ ### 子系统认证通信插件使用文档1.2.0
2
2
 
3
- #### 1、安装
3
+ ### 1.2.0优化升级说明】
4
4
 
5
- ```
6
- npm i qlfy-postmate@1.1.3
7
- ```
8
-
9
- #### 2、导入
10
-
11
- ```js
12
- import { ChildPostmate } from 'qlfy-postmate'
13
- ```
5
+ ```txt
6
+ 1、优化了同IP链接切换时的系统资源重复加载问题
7
+ 增加了系统间的通信处理方式
8
+ 新版本中在new ChildPostmate时需传入第二个参数【vue-router的实例对象】router;
9
+ 通过通信支持 + ChildPostmate内部对router的操作,实现主系统操控集成系统页面跳转的功能;
14
10
 
15
- #### 3、使用
11
+ 2、老版本的兼容性支持
12
+ 如已完成集成的系统仍使用旧版本插件,集成效果不变,仅性能和切换效果差于新版
16
13
 
17
- ```js
18
- // 基本使用
19
- const childrenComm = new ChildPostmate({
20
- error: (err: any) => {
21
- console.log('-----------------链接失败-----------------', err)
22
- },
23
- success: (success: any) => {
24
- console.log('-----------------链接成功-----------------', success)
25
- },
26
- receive: (dataInfo: any) => {
27
- console.log('-----------------接收数据-----------------', dataInfo)
28
- },
29
- })
30
-
31
- // 带路由功能的使用(推荐)
32
- import { useRouter } from 'vue-router'
33
-
34
- const router = useRouter()
35
- const childrenComm = new ChildPostmate({
36
- error: (err: any) => {
37
- console.log('-----------------链接失败-----------------', err)
38
- },
39
- success: (success: any) => {
40
- console.log('-----------------链接成功-----------------', success)
41
- },
42
- receive: (dataInfo: any) => {
43
- console.log('-----------------接收数据-----------------', dataInfo)
44
- },
45
- }, router) // 传入router实例,支持路由更新功能
14
+ 3、建议
15
+ 已完成集成系统也建议使用最新版本,使用变化极小
16
+ 仅需以下两步操作:
17
+ (1)下载新版本插件:npm i qlfy-postmate@1.2.0
18
+ (2)使用处添加新参数:router
19
+ new ChildPostmate({...保持不变}, router)
46
20
  ```
47
21
 
48
- #### 4、参数对象说明
49
-
50
- | 回调函数名称 | 解释 | 回调参数 | 返回值 |
51
- | ------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------ |
52
- | error | 链接失败、未链接时执行 | null | void |
53
- | success | 链接成功时执行 | chldPostmate | void |
54
- | receive | 父页面推送数据时执行,初次链接成功会触发一次<br />可将本回调函数看做为websoket服务,后续父页面可能会不定时向子系统推送数据 | {<br />isHideHeader:boolean,<br />token:string,<br />loginInfo:object,<br />......<br />} | void |
55
-
56
- #### 5、方法
57
-
58
- | 名称 | 解释 | 使用 |
59
- | ---------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
60
- | getData | 链接成功后<br />可通过ChildPostmate实例对象,主动向父页面获取数据 | getData((dataInfo)=>void) |
61
- | setRouter | 设置Vue Router实例和自定义路由更新回调函数<br />用于在实例创建后设置或更新路由实例 | setRouter(router, [routeUpdateCallback]) |
62
- | sendOtherRequest | 向父页面发送自定义请求 | sendOtherRequest(params) |
63
-
64
- #### 注意:
65
-
66
- 1、ChildPostmate 链接的创建是异步过程,需等待error或success函数执行后才可进行登陆状态的判断
67
-
68
- 2、getData方法,仅能在链接创建完成后再调用
69
-
70
- 3、路由更新功能需要传入Vue Router实例才能使用
71
-
72
- 4、路由更新功能会自动判断URL变化类型:
73
- - 如果只有查询参数或哈希变化,只更新参数,不刷新页面
74
- - 如果路径变化,会更新整个路由路径,但不会刷新页面
75
- - 如果协议、主机或端口变化,会重新加载iframe
76
-
77
- 5、如果需要自定义路由更新逻辑,可以传入routeUpdateCallback回调函数
78
-
79
- 6、error、success函数仅作为链接状态的标注函数,不传递数据
80
-
81
-
82
-
83
- ### 接入步骤
84
-
85
- 1. 对系统登录状态进行改造,系统加载时先将登陆状态判断屏蔽
86
-
87
- 2. 系统公共部分(app.vue)对该插件进行导入和 new,创建实例,并传入相应回调
88
-
89
- 3. 等待回调被执行,并做出以下操作:
90
-
91
- ------- 如果error回调执行:解除对登录状态的屏蔽,走系统本身登陆逻辑;
92
22
 
93
- ------- 如果success回调执行:
94
23
 
95
- 1、保持对登录状态的屏蔽,并等待receive回调执行;
96
-
97
- ​ 2、receive回调执行:
98
-
99
- ​ (1)使用接收数据中的token、loginInfo数据,将本地的登陆状态设置为已登录,后续接口请求时携带本回调传入的token;
100
-
101
- ​ (2)使用接收数据中的isHideHeader字段,对系统页头的显隐进行控制
102
-
103
- ```vue
104
- <my-header v-if="!isHideHeader" />
105
- ```
106
-
107
- ​ (3)解除对登陆状态判断的屏蔽(因已使用接收的数据配置了登录状态,不会触发本系统的登陆);
108
-
109
- 接入步骤(动态路由)
110
-
111
- ### 样例一(app.vue):
112
-
113
- App.vue
114
-
115
- ```vue
116
- <template>
117
- <div class="system-content" v-loading="loading">
118
- <!-- 系统登录状态的判断,需等待postmate链接的响应后再执行 -->
119
-
120
- <!-- 页头 -->
121
- <my-header v-if="!isHideHeader"></my-header>
24
+ #### 1、安装
122
25
 
123
- <!-- 侧面导航 -->
124
- <my-aside v-if="!isHideHeader"></my-aside>
26
+ ```
27
+ npm i qlfy-postmate
28
+ ```
125
29
 
126
- <!-- 内容区 -->
127
- <RouterView v-if="!loading" />
128
- </div>
129
- </template>
30
+ #### 2、导入
130
31
 
131
- <script setup lang="ts">
132
- import { ref } from 'vue'
133
- import { useRouter } from 'vue-router'
134
- import { useSystemStore } from '@/store/modules/system'
32
+ ```js
135
33
  import { ChildPostmate } from 'qlfy-postmate'
136
-
137
- // 系统loading
138
- const loading = ref(false)
139
- // 页头是否展示
140
- const isHideHeader = ref(false)
141
- // pinia系统数据管理对象
142
- const systemStore = useSystemStore()
143
-
144
- initPostMate()
145
-
146
- // 方法 -- 初始化postmate链接
147
- function initPostMate() {
148
- loading.value = true
149
- // 获取router实例
150
- const router = useRouter()
151
-
152
- const childrenComm = new ChildPostmate({
153
- error: (err: any) => {
154
- console.log('-----------------链接失败-----------------')
155
- console.log(err)
156
- loading.value = false
157
- },
158
-
159
- success: (success: any) => {
160
- console.log('-----------------链接成功-----------------')
161
- console.log(success)
162
- loading.value = false
163
- },
164
-
165
- receive: (dataInfo: any) => {
166
- console.log('-----------------接收数据-----------------')
167
- console.log(dataInfo)
168
- if (dataInfo.status !== 200) return
169
- /**
170
- * 接收到推送数据后做如下操作
171
- * 1、根据isHideHeader控制页头显隐
172
- * 2、将登录装填变更为已登录,并将token保存在正常登录所在位置进行取用
173
- */
174
-
175
- // 控制导航、页头的展示
176
- isHideHeader.value = dataInfo.data.isHideHeader
177
- // 保存登陆信息
178
- systemStore.setLoginInfo(dataInfo.data.loginInfo)
179
- // 保存token
180
- systemStore.setTooken(dataInfo.data.token)
181
- },
182
- }, router) // 传入router实例,支持路由更新功能
183
- }
184
- </script>
185
-
186
- <style scoped></style>
187
-
188
34
  ```
189
35
 
190
- ### 样例二(main.js)【推荐】:
36
+ #### 3、使用(main.js
191
37
 
192
38
  ```js
193
39
  import { createApp } from "vue";
194
40
  import App from "./App.vue";
195
- import { ChildPostmate } from 'qlfy-postmate'
196
41
  import router from "./router";
197
-
198
42
  import { createPinia } from "pinia";
43
+ import { ChildPostmate } from 'qlfy-postmate'
199
44
  const store = createPinia(); //pinia实例
200
- export const app = createApp(App);
45
+ const app = createApp(App);
201
46
 
202
47
  // pinia
203
48
  app.use(store);
204
- // 路由拦截器
205
- import '@/permission.js'
206
49
 
207
50
  // 标识,是否为首次加载项目
208
51
  let flag = true
@@ -229,10 +72,10 @@ new ChildPostmate({
229
72
 
230
73
  // 数据更新 -- 是否隐藏页头
231
74
  $store.setIsHideHeader(dataInfo.data.isHideHeader);
75
+ // 数据更新 -- token
76
+ $store.setIsHideHeader(dataInfo.data.token);
232
77
  // 数据更新 -- 登陆信息
233
78
  $store.setLoginInfo(dataInfo.data.loginInfo);
234
- localStorage.setItem('info', JSON.stringify(dataInfo.data.loginInfo));
235
-
236
79
  // 项目挂载,仅首次加载项目时执行,后续receive触发不执行
237
80
  if (flag) {
238
81
  app.use(router)
@@ -243,61 +86,42 @@ new ChildPostmate({
243
86
  }, router) // 传入router实例,支持路由更新功能
244
87
  ```
245
88
 
89
+ #### 4、参数说明
246
90
 
91
+ | 参数名 | 说明 | 类型 |
92
+ | -------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
93
+ | eventObj | 事件对象集,对外暴露链接状态<br />详细说明见下方eventObj说明 | {<br />error:()=>void<br />success:(childPostmate)=>viod<br />receive:(res:any)=>void<br />} |
94
+ | router | 当前系统的vue-router实例 | Router |
247
95
 
248
- ### 父页面使用说明(ParentPostmate)
96
+ #### eventObj说明
249
97
 
250
- #### 1、导入
98
+ | 属性(支持的事件回调) | 说明 | 类型 |
99
+ | ---------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
100
+ | error | 链接失败、未链接时执行 | ()=>void |
101
+ | success | 链接成功时执行 | (chldPostmate)=>void |
102
+ | receive | 父页面推送数据时执行,初次链接成功会触发一次<br />可将本回调函数看做为websoket服务,<br />后续父页面可能会不定时向子系统推送数据 | (<br /> {<br /> isHideHeader:boolean,<br /> token:string,<br /> loginInfo:object,<br /> ......<br /> }<br />)=>void |
251
103
 
252
- ```js
253
- import { ParentPostmate } from 'qlfy-postmate'
254
- ```
255
104
 
256
- #### 2、基本使用
257
105
 
258
- ```js
259
- // 创建父页面通信实例
260
- const parentComm = new ParentPostmate(
261
- // 传递给子页面的数据
262
- {
263
- loginInfo: { /* 登录信息 */ },
264
- token: 'token字符串',
265
- isHideHeader: true
266
- },
267
- // iframe容器元素
268
- document.getElementById('iframe-container'),
269
- // 子页面URL
270
- 'http://example.com/child-page',
271
- // 处理子页面其他请求的回调函数
272
- (params) => {
273
- console.log('收到子页面请求:', params)
274
- }
275
- )
276
- ```
106
+ #### 5、方法
277
107
 
278
- #### 3、路由更新功能
108
+ | 名称 | 说明 | 使用 |
109
+ | ---------------- | ------------------------------------------------------------ | ---------------------------------------- |
110
+ | getData | 链接成功后<br />可通过ChildPostmate实例对象,主动向父页面获取数据 | getData((dataInfo)=>void) |
111
+ | setRouter | 设置Vue Router实例和自定义路由更新回调函数<br />用于在实例创建后设置或更新路由实例 | setRouter(router, [routeUpdateCallback]) |
112
+ | sendOtherRequest | 向父页面发送自定义请求 | sendOtherRequest(params) |
279
113
 
280
- 当需要更新子页面URL时,只需调用`setIframeUrl`方法:
114
+ #### 注意:
281
115
 
282
- ```js
283
- // 更新子页面URL
284
- parentComm.setIframeUrl('http://example.com/child-page/new-route?param=value')
285
- ```
116
+ 1、ChildPostmate 链接的创建是异步过程,需等待error或success函数执行后才可进行登陆状态的判断
117
+
118
+ 2、getData方法,仅能在链接创建完成后再调用
286
119
 
287
- 系统会自动判断URL变化类型:
288
- - 如果只有查询参数或哈希变化,只更新参数,不刷新页面
289
- - 如果路径变化,会更新整个路由路径,但不会刷新页面
290
- - 如果协议、主机或端口变化,会重新加载iframe
120
+ 3、路由更新功能需要传入Vue Router实例才能使用
291
121
 
292
- #### 4、方法说明
122
+ 5、如果需要自定义路由更新逻辑,可以传入routeUpdateCallback回调函数
293
123
 
294
- | 方法名 | 说明 | 参数 |
295
- | ------ | ---- | ---- |
296
- | setIframeUrl | 设置iframe的URL | (url: string) |
297
- | setIframeEle | 设置iframe容器元素 | (element: HTMLElement \| (() => HTMLElement)) |
298
- | sendData | 向子页面发送数据 | () |
299
- | setLoadFunction | 设置iframe加载完成的回调函数 | (callback: () => void) |
300
- | destroy | 销毁实例 | () |
124
+ 6、error、success函数仅作为链接状态的标注函数,不传递数据
301
125
 
302
126
  ### 集成调试
303
127
 
package/lib/index.mjs CHANGED
@@ -8,13 +8,13 @@ const f = {
8
8
  reply: 1,
9
9
  request: 1
10
10
  };
11
- function p(n, t) {
11
+ function u(n, t) {
12
12
  return (typeof t != "string" || n.origin === t) && !!n.data && (typeof n.data != "object" || "postmate" in n.data) && n.data.type === c && !!f[n.data.postmate];
13
13
  }
14
14
  class g {
15
15
  constructor(t) {
16
16
  this.parent = t.parent, this.frame = t.frame, this.child = t.child, this.childOrigin = t.childOrigin, this.events = {}, this.listener = (e) => {
17
- if (!p(e, this.childOrigin)) return;
17
+ if (!u(e, this.childOrigin)) return;
18
18
  const { value: s = {} } = e.data, { name: a, data: r } = s;
19
19
  e.data.postmate === "emit" && a in this.events && this.events[a].call(this, r);
20
20
  }, this.parent.addEventListener("message", this.listener, !1);
@@ -53,10 +53,10 @@ class g {
53
53
  window.removeEventListener("message", this.listener, !1), this.frame.parentNode.removeChild(this.frame);
54
54
  }
55
55
  }
56
- class P {
56
+ class w {
57
57
  constructor(t) {
58
58
  this.model = t.model, this.parent = t.parent, this.parentOrigin = t.parentOrigin, this.child = t.child, this.child.addEventListener("message", (e) => {
59
- if (!p(e, this.parentOrigin)) return;
59
+ if (!u(e, this.parentOrigin)) return;
60
60
  const { postmate: s, property: a, uid: r, data: h } = e.data, i = this.model[a];
61
61
  if (s !== "call") {
62
62
  const l = typeof i == "function" ? i() : i;
@@ -99,9 +99,9 @@ class o {
99
99
  })();
100
100
  let s = 0, a;
101
101
  return new o.Promise((r, h) => {
102
- const i = (u) => {
103
- if (!p(u, e)) return !1;
104
- u.data.postmate === "handshake-reply" ? (clearInterval(a), this.parent.removeEventListener("message", i, !1), this.childOrigin = u.origin, r(new g(this))) : h("Failed handshake");
102
+ const i = (p) => {
103
+ if (!u(p, e)) return !1;
104
+ p.data.postmate === "handshake-reply" ? (clearInterval(a), this.parent.removeEventListener("message", i, !1), this.childOrigin = p.origin, r(new g(this))) : h("Failed handshake");
105
105
  };
106
106
  this.parent.addEventListener("message", i, !1);
107
107
  const l = () => {
@@ -120,7 +120,7 @@ class o {
120
120
  });
121
121
  }
122
122
  }
123
- class y {
123
+ class P {
124
124
  constructor(t) {
125
125
  return this.child = window, this.model = t, this.parent = window.parent, this.sendHandshakeReply();
126
126
  }
@@ -139,7 +139,7 @@ class y {
139
139
  const a = s.data.model;
140
140
  a && Object.keys(a).forEach((r) => {
141
141
  this.model[r] = a[r];
142
- }), t(new P(this));
142
+ }), t(new w(this));
143
143
  }
144
144
  }, !1);
145
145
  });
@@ -153,8 +153,8 @@ o.Promise = (() => {
153
153
  return Promise;
154
154
  }
155
155
  })();
156
- o.Model = y;
157
- class w {
156
+ o.Model = P;
157
+ class y {
158
158
  constructor(t, e, s) {
159
159
  this.childPostmate = null, this.parentPostmate = null, this.isGetData = !1, this.getDataCllBack = null, this.router = null, this.routeUpdateCallback = null, this.router = e, this.routeUpdateCallback = s, window.top !== window.self ? this.init(t) : t.error({ status: 500, data: null, message: "未在一体化平台中运行" });
160
160
  }
@@ -176,6 +176,10 @@ class w {
176
176
  // 处理路由更新
177
177
  routeUpdate(s) {
178
178
  try {
179
+ window.parent.postMessage(JSON.stringify({
180
+ type: "route_update_support",
181
+ supported: !0
182
+ }), "*");
179
183
  const a = JSON.parse(s);
180
184
  if (e.routeUpdateCallback) {
181
185
  e.routeUpdateCallback(a);
@@ -232,13 +236,13 @@ class U {
232
236
  loginInfo: {},
233
237
  token: "",
234
238
  isHideHeader: !0
235
- }, this.iframeEle = null, this.currentUrl = "", this.currentIframe = null, this.loadFunction = null, this.handleOtherRequest = null, this.parsedCurrentUrl = null, this.dataInfo = t || this.dataInfo, this.iframeEle = e, this.setIframeUrl(s), a && (this.handleOtherRequest = a);
239
+ }, this.iframeEle = null, this.currentUrl = "", this.currentIframe = null, this.loadFunction = null, this.handleOtherRequest = null, this.parsedCurrentUrl = null, this.childSupportsRouteUpdate = !0, this.dataInfo = t || this.dataInfo, this.iframeEle = e, this.setIframeUrl(s), a && (this.handleOtherRequest = a);
236
240
  }
237
241
  /** 解析URL */
238
242
  parseUrl(t) {
239
243
  const e = document.createElement("a");
240
244
  e.href = t;
241
- const s = e.protocol.length > 4 ? e.protocol : window.location.protocol, a = e.hostname, r = e.port || (s === "https:" ? "443" : s === "http:" ? "80" : ""), h = e.pathname.startsWith("/") ? e.pathname : `/${e.pathname}`, i = e.search, l = e.hash, d = e.origin || `${s}//${a}${r ? `:${r}` : ""}`, u = `${h}${i}${l}`;
245
+ const s = e.protocol.length > 4 ? e.protocol : window.location.protocol, a = e.hostname, r = e.port || (s === "https:" ? "443" : s === "http:" ? "80" : ""), h = e.pathname.startsWith("/") ? e.pathname : `/${e.pathname}`, i = e.search, l = e.hash, d = e.origin || `${s}//${a}${r ? `:${r}` : ""}`, p = `${h}${i}${l}`;
242
246
  return {
243
247
  protocol: s,
244
248
  host: a,
@@ -247,7 +251,7 @@ class U {
247
251
  search: i,
248
252
  hash: l,
249
253
  origin: d,
250
- fullPath: u
254
+ fullPath: p
251
255
  };
252
256
  }
253
257
  /** 比较两个URL是否相同(协议、主机、端口) */
@@ -274,7 +278,7 @@ class U {
274
278
  }
275
279
  /** 初始化 */
276
280
  async init(t = null) {
277
- if (this.clear(), !this.iframeEle || !this.currentUrl) {
281
+ if (this.clear(), this.childSupportsRouteUpdate = !0, !this.iframeEle || !this.currentUrl) {
278
282
  console.warn("iframeEle 和 currentUrl 是必需的");
279
283
  return;
280
284
  }
@@ -313,7 +317,7 @@ class U {
313
317
  return;
314
318
  }
315
319
  const e = this.parseUrl(t);
316
- if (this.postmateParent && this.compareUrlBase(this.currentUrl, t))
320
+ if (this.postmateParent && this.compareUrlBase(this.currentUrl, t) && this.childSupportsRouteUpdate)
317
321
  if (this.compareUrlPath(this.currentUrl, t)) {
318
322
  if (this.compareUrlFull(this.currentUrl, t))
319
323
  return;
@@ -327,15 +331,36 @@ class U {
327
331
  }
328
332
  /** 向子页面发送路由更新消息 */
329
333
  sendRouteUpdate(t) {
330
- this.postmateParent && this.postmateParent.call(
331
- "routeUpdate",
332
- JSON.stringify({
333
- fullPath: t.fullPath,
334
- pathname: t.pathname,
335
- search: t.search,
336
- hash: t.hash
337
- })
338
- );
334
+ if (this.postmateParent) {
335
+ if (!this.childSupportsRouteUpdate) {
336
+ console.warn("子页面不支持路由更新,直接重新初始化iframe"), this.init();
337
+ return;
338
+ }
339
+ try {
340
+ this.postmateParent.call(
341
+ "routeUpdate",
342
+ JSON.stringify({
343
+ fullPath: t.fullPath,
344
+ pathname: t.pathname,
345
+ search: t.search,
346
+ hash: t.hash
347
+ })
348
+ );
349
+ let e = !1;
350
+ const s = (a) => {
351
+ try {
352
+ const r = JSON.parse(a.data);
353
+ r && r.type === "route_update_support" && r.supported === !0 && (e = !0, window.removeEventListener("message", s));
354
+ } catch {
355
+ }
356
+ };
357
+ window.addEventListener("message", s), setTimeout(() => {
358
+ window.removeEventListener("message", s), e || (console.warn("子页面不支持路由更新,将在下次更新时重新初始化iframe"), this.childSupportsRouteUpdate = !1, this.init());
359
+ }, 1e3);
360
+ } catch (e) {
361
+ console.warn("发送路由更新消息失败,将重新初始化iframe:", e), this.childSupportsRouteUpdate = !1, this.init();
362
+ }
363
+ }
339
364
  }
340
365
  /** 向子页面发送消息 */
341
366
  sendData() {
@@ -347,6 +372,6 @@ class U {
347
372
  }
348
373
  }
349
374
  export {
350
- w as ChildPostmate,
375
+ y as ChildPostmate,
351
376
  U as ParentPostmate
352
377
  };
package/lib/index.mjs.gz CHANGED
Binary file
package/lib/index.umd.js CHANGED
@@ -1 +1 @@
1
- (function(c,n){typeof exports=="object"&&typeof module<"u"?n(exports):typeof define=="function"&&define.amd?define(["exports"],n):(c=typeof globalThis<"u"?globalThis:c||self,n(c["qlfy-postmate"]={}))})(this,function(c){"use strict";const n="application/x-postmate-v1+json";let f=0;const g={handshake:1,"handshake-reply":1,call:1,emit:1,reply:1,request:1};function m(o,t){return(typeof t!="string"||o.origin===t)&&!!o.data&&(typeof o.data!="object"||"postmate"in o.data)&&o.data.type===n&&!!g[o.data.postmate]}class P{constructor(t){this.parent=t.parent,this.frame=t.frame,this.child=t.child,this.childOrigin=t.childOrigin,this.events={},this.listener=e=>{if(!m(e,this.childOrigin))return;const{value:s={}}=e.data,{name:a,data:r}=s;e.data.postmate==="emit"&&a in this.events&&this.events[a].call(this,r)},this.parent.addEventListener("message",this.listener,!1)}get(t){return new h.Promise(e=>{const s=++f,a=r=>{r.data.uid===s&&r.data.postmate==="reply"&&(this.parent.removeEventListener("message",a,!1),e(r.data.value))};this.parent.addEventListener("message",a,!1),this.child.postMessage({postmate:"request",type:n,property:t,uid:s},this.childOrigin)})}call(t,e){this.child.postMessage({postmate:"call",type:n,property:t,data:e},this.childOrigin)}on(t,e){this.events[t]=e}destroy(){window.removeEventListener("message",this.listener,!1),this.frame.parentNode.removeChild(this.frame)}}class y{constructor(t){this.model=t.model,this.parent=t.parent,this.parentOrigin=t.parentOrigin,this.child=t.child,this.child.addEventListener("message",e=>{if(!m(e,this.parentOrigin))return;const{postmate:s,property:a,uid:r,data:l}=e.data,i=this.model[a];if(s!=="call"){const d=typeof i=="function"?i():i;h.Promise.resolve(d).then(u=>{e.source.postMessage({property:a,postmate:"reply",type:n,uid:r,value:u},e.origin)})}else a in this.model&&typeof i=="function"&&i(l)})}emit(t,e){this.parent.postMessage({postmate:"emit",type:n,value:{name:t,data:e}},this.parentOrigin)}}class h{constructor({container:t=document.body,model:e,url:s,name:a,classListArray:r=[]}){return this.parent=window,this.frame=document.createElement("iframe"),this.frame.name=a||"",this.frame.classList.add(...r),t.appendChild(this.frame),this.child=this.frame.contentWindow,this.model=e||{},this.sendHandshake(s)}sendHandshake(t){const e=(()=>{const r=document.createElement("a");r.href=t;const l=r.protocol.length>4?r.protocol:window.location.protocol,i=r.host.length?r.port==="80"||r.port==="443"?r.hostname:r.host:window.location.host;return r.origin||`${l}//${i}`})();let s=0,a;return new h.Promise((r,l)=>{const i=p=>{if(!m(p,e))return!1;p.data.postmate==="handshake-reply"?(clearInterval(a),this.parent.removeEventListener("message",i,!1),this.childOrigin=p.origin,r(new P(this))):l("Failed handshake")};this.parent.addEventListener("message",i,!1);const d=()=>{s++,this.child.postMessage({postmate:"handshake",type:n,model:this.model},e),s===5&&clearInterval(a)},u=()=>{d(),a=setInterval(d,500)};this.frame.onload=u,this.frame.attachEvent&&this.frame.attachEvent("onload",u),this.frame.src=t})}}class w{constructor(t){return this.child=window,this.model=t,this.parent=window.parent,this.sendHandshakeReply()}sendHandshakeReply(){return new h.Promise((t,e)=>{this.child.addEventListener("message",s=>{if(s.data.postmate){if(s.data.postmate!=="handshake")return e("Handshake Reply Failed");this.child.removeEventListener("message",this,!1),s.source.postMessage({postmate:"handshake-reply",type:n},s.origin),this.parentOrigin=s.origin;const a=s.data.model;a&&Object.keys(a).forEach(r=>{this.model[r]=a[r]}),t(new y(this))}},!1)})}}h.debug=!1,h.Promise=(()=>{try{return typeof window<"u"?window.Promise:Promise}catch{return Promise}})(),h.Model=w;class U{constructor(t,e,s){this.childPostmate=null,this.parentPostmate=null,this.isGetData=!1,this.getDataCllBack=null,this.router=null,this.routeUpdateCallback=null,this.router=e,this.routeUpdateCallback=s,window.top!==window.self?this.init(t):t.error({status:500,data:null,message:"未在一体化平台中运行"})}init(t){const e=this;this.childPostmate=new h.Model({baseData(s){s=JSON.parse(s),e.isGetData?e.getDataCllBack&&e.getDataCllBack({status:200,message:"success",data:s}):t.receive({status:200,message:"success",data:s}),e.isGetData=!1},routeUpdate(s){try{const a=JSON.parse(s);if(e.routeUpdateCallback){e.routeUpdateCallback(a);return}e.router?e.router.replace(a.fullPath):console.warn("未提供router实例,无法进行路由更新")}catch(a){console.error("路由更新失败:",a)}}}).then(s=>{e.parentPostmate=s,e.getData(),t.success({status:200,message:"success",data:{ChildPostmate:s}})}).catch(s=>{t.error({status:500,data:null,message:s})})}getData(t){if(!this.parentPostmate){t({status:500,message:"父页面未连接",data:null});return}t?(this.isGetData=!0,this.getDataCllBack=t):(this.isGetData=!1,this.getDataCllBack=null),this.parentPostmate.emit("requestBaseData")}setRouter(t,e){this.router=t,e&&(this.routeUpdateCallback=e)}sendOtherRequest(t){this.parentPostmate&&this.parentPostmate.emit("otherRequest",t)}}class E{constructor(t,e,s="",a){this.postmateParent=null,this.dataInfo={loginInfo:{},token:"",isHideHeader:!0},this.iframeEle=null,this.currentUrl="",this.currentIframe=null,this.loadFunction=null,this.handleOtherRequest=null,this.parsedCurrentUrl=null,this.dataInfo=t||this.dataInfo,this.iframeEle=e,this.setIframeUrl(s),a&&(this.handleOtherRequest=a)}parseUrl(t){const e=document.createElement("a");e.href=t;const s=e.protocol.length>4?e.protocol:window.location.protocol,a=e.hostname,r=e.port||(s==="https:"?"443":s==="http:"?"80":""),l=e.pathname.startsWith("/")?e.pathname:`/${e.pathname}`,i=e.search,d=e.hash,u=e.origin||`${s}//${a}${r?`:${r}`:""}`,p=`${l}${i}${d}`;return{protocol:s,host:a,port:r,pathname:l,search:i,hash:d,origin:u,fullPath:p}}compareUrlBase(t,e){if(!t||!e)return!1;const s=this.parseUrl(t),a=this.parseUrl(e);return s.protocol===a.protocol&&s.host===a.host&&s.port===a.port}compareUrlPath(t,e){if(!t||!e)return!1;const s=this.parseUrl(t),a=this.parseUrl(e);return s.pathname===a.pathname}compareUrlFull(t,e){if(!t||!e)return!1;const s=this.parseUrl(t),a=this.parseUrl(e);return s.fullPath===a.fullPath}clear(){this.postmateParent&&(this.postmateParent.destroy(),this.postmateParent=null),this.currentIframe&&this.currentIframe.parentNode&&this.currentIframe.parentNode.removeChild(this.currentIframe),this.currentIframe=null}async init(t=null){if(this.clear(),!this.iframeEle||!this.currentUrl){console.warn("iframeEle 和 currentUrl 是必需的");return}const e=typeof this.iframeEle=="function"?this.iframeEle():this.iframeEle;if(!e){console.warn("无法获取 iframe 容器");return}const s=new h({container:e,url:this.currentUrl,name:"",model:""});this.currentIframe=e.querySelector("iframe"),this.currentIframe.setAttribute("frameborder","0"),this.currentIframe.setAttribute("allow","fullscreen"),this.currentIframe.addEventListener("load",()=>{this.loadFunction&&this.loadFunction()}),s.then(a=>{this.postmateParent=a,a.on("requestBaseData",()=>{this.sendData()}),a.on("otherRequest",r=>{this.handleOtherRequest&&this.handleOtherRequest(r)}),typeof t=="function"&&t()}).catch(a=>{console.error("Postmate 连接失败:",a)})}setLoadFunction(t){this.loadFunction=t}setIframeUrl(t){if(this.currentUrl===t)return;if(!this.currentUrl){this.currentUrl=t,this.parsedCurrentUrl=this.parseUrl(t),this.iframeEle&&this.init();return}const e=this.parseUrl(t);if(this.postmateParent&&this.compareUrlBase(this.currentUrl,t))if(this.compareUrlPath(this.currentUrl,t)){if(this.compareUrlFull(this.currentUrl,t))return;this.currentUrl=t,this.parsedCurrentUrl=e,this.sendRouteUpdate(e);return}else{this.currentUrl=t,this.parsedCurrentUrl=e,this.sendRouteUpdate(e);return}this.currentUrl=t,this.parsedCurrentUrl=e,this.iframeEle&&this.init()}sendRouteUpdate(t){this.postmateParent&&this.postmateParent.call("routeUpdate",JSON.stringify({fullPath:t.fullPath,pathname:t.pathname,search:t.search,hash:t.hash}))}sendData(){this.postmateParent&&this.postmateParent.call("baseData",JSON.stringify(this.dataInfo))}destroy(){this.clear()}}c.ChildPostmate=U,c.ParentPostmate=E,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})});
1
+ (function(d,n){typeof exports=="object"&&typeof module<"u"?n(exports):typeof define=="function"&&define.amd?define(["exports"],n):(d=typeof globalThis<"u"?globalThis:d||self,n(d["qlfy-postmate"]={}))})(this,function(d){"use strict";const n="application/x-postmate-v1+json";let f=0;const g={handshake:1,"handshake-reply":1,call:1,emit:1,reply:1,request:1};function m(o,t){return(typeof t!="string"||o.origin===t)&&!!o.data&&(typeof o.data!="object"||"postmate"in o.data)&&o.data.type===n&&!!g[o.data.postmate]}class P{constructor(t){this.parent=t.parent,this.frame=t.frame,this.child=t.child,this.childOrigin=t.childOrigin,this.events={},this.listener=e=>{if(!m(e,this.childOrigin))return;const{value:s={}}=e.data,{name:a,data:r}=s;e.data.postmate==="emit"&&a in this.events&&this.events[a].call(this,r)},this.parent.addEventListener("message",this.listener,!1)}get(t){return new h.Promise(e=>{const s=++f,a=r=>{r.data.uid===s&&r.data.postmate==="reply"&&(this.parent.removeEventListener("message",a,!1),e(r.data.value))};this.parent.addEventListener("message",a,!1),this.child.postMessage({postmate:"request",type:n,property:t,uid:s},this.childOrigin)})}call(t,e){this.child.postMessage({postmate:"call",type:n,property:t,data:e},this.childOrigin)}on(t,e){this.events[t]=e}destroy(){window.removeEventListener("message",this.listener,!1),this.frame.parentNode.removeChild(this.frame)}}class w{constructor(t){this.model=t.model,this.parent=t.parent,this.parentOrigin=t.parentOrigin,this.child=t.child,this.child.addEventListener("message",e=>{if(!m(e,this.parentOrigin))return;const{postmate:s,property:a,uid:r,data:l}=e.data,i=this.model[a];if(s!=="call"){const c=typeof i=="function"?i():i;h.Promise.resolve(c).then(u=>{e.source.postMessage({property:a,postmate:"reply",type:n,uid:r,value:u},e.origin)})}else a in this.model&&typeof i=="function"&&i(l)})}emit(t,e){this.parent.postMessage({postmate:"emit",type:n,value:{name:t,data:e}},this.parentOrigin)}}class h{constructor({container:t=document.body,model:e,url:s,name:a,classListArray:r=[]}){return this.parent=window,this.frame=document.createElement("iframe"),this.frame.name=a||"",this.frame.classList.add(...r),t.appendChild(this.frame),this.child=this.frame.contentWindow,this.model=e||{},this.sendHandshake(s)}sendHandshake(t){const e=(()=>{const r=document.createElement("a");r.href=t;const l=r.protocol.length>4?r.protocol:window.location.protocol,i=r.host.length?r.port==="80"||r.port==="443"?r.hostname:r.host:window.location.host;return r.origin||`${l}//${i}`})();let s=0,a;return new h.Promise((r,l)=>{const i=p=>{if(!m(p,e))return!1;p.data.postmate==="handshake-reply"?(clearInterval(a),this.parent.removeEventListener("message",i,!1),this.childOrigin=p.origin,r(new P(this))):l("Failed handshake")};this.parent.addEventListener("message",i,!1);const c=()=>{s++,this.child.postMessage({postmate:"handshake",type:n,model:this.model},e),s===5&&clearInterval(a)},u=()=>{c(),a=setInterval(c,500)};this.frame.onload=u,this.frame.attachEvent&&this.frame.attachEvent("onload",u),this.frame.src=t})}}class y{constructor(t){return this.child=window,this.model=t,this.parent=window.parent,this.sendHandshakeReply()}sendHandshakeReply(){return new h.Promise((t,e)=>{this.child.addEventListener("message",s=>{if(s.data.postmate){if(s.data.postmate!=="handshake")return e("Handshake Reply Failed");this.child.removeEventListener("message",this,!1),s.source.postMessage({postmate:"handshake-reply",type:n},s.origin),this.parentOrigin=s.origin;const a=s.data.model;a&&Object.keys(a).forEach(r=>{this.model[r]=a[r]}),t(new w(this))}},!1)})}}h.debug=!1,h.Promise=(()=>{try{return typeof window<"u"?window.Promise:Promise}catch{return Promise}})(),h.Model=y;class U{constructor(t,e,s){this.childPostmate=null,this.parentPostmate=null,this.isGetData=!1,this.getDataCllBack=null,this.router=null,this.routeUpdateCallback=null,this.router=e,this.routeUpdateCallback=s,window.top!==window.self?this.init(t):t.error({status:500,data:null,message:"未在一体化平台中运行"})}init(t){const e=this;this.childPostmate=new h.Model({baseData(s){s=JSON.parse(s),e.isGetData?e.getDataCllBack&&e.getDataCllBack({status:200,message:"success",data:s}):t.receive({status:200,message:"success",data:s}),e.isGetData=!1},routeUpdate(s){try{window.parent.postMessage(JSON.stringify({type:"route_update_support",supported:!0}),"*");const a=JSON.parse(s);if(e.routeUpdateCallback){e.routeUpdateCallback(a);return}e.router?e.router.replace(a.fullPath):console.warn("未提供router实例,无法进行路由更新")}catch(a){console.error("路由更新失败:",a)}}}).then(s=>{e.parentPostmate=s,e.getData(),t.success({status:200,message:"success",data:{ChildPostmate:s}})}).catch(s=>{t.error({status:500,data:null,message:s})})}getData(t){if(!this.parentPostmate){t({status:500,message:"父页面未连接",data:null});return}t?(this.isGetData=!0,this.getDataCllBack=t):(this.isGetData=!1,this.getDataCllBack=null),this.parentPostmate.emit("requestBaseData")}setRouter(t,e){this.router=t,e&&(this.routeUpdateCallback=e)}sendOtherRequest(t){this.parentPostmate&&this.parentPostmate.emit("otherRequest",t)}}class E{constructor(t,e,s="",a){this.postmateParent=null,this.dataInfo={loginInfo:{},token:"",isHideHeader:!0},this.iframeEle=null,this.currentUrl="",this.currentIframe=null,this.loadFunction=null,this.handleOtherRequest=null,this.parsedCurrentUrl=null,this.childSupportsRouteUpdate=!0,this.dataInfo=t||this.dataInfo,this.iframeEle=e,this.setIframeUrl(s),a&&(this.handleOtherRequest=a)}parseUrl(t){const e=document.createElement("a");e.href=t;const s=e.protocol.length>4?e.protocol:window.location.protocol,a=e.hostname,r=e.port||(s==="https:"?"443":s==="http:"?"80":""),l=e.pathname.startsWith("/")?e.pathname:`/${e.pathname}`,i=e.search,c=e.hash,u=e.origin||`${s}//${a}${r?`:${r}`:""}`,p=`${l}${i}${c}`;return{protocol:s,host:a,port:r,pathname:l,search:i,hash:c,origin:u,fullPath:p}}compareUrlBase(t,e){if(!t||!e)return!1;const s=this.parseUrl(t),a=this.parseUrl(e);return s.protocol===a.protocol&&s.host===a.host&&s.port===a.port}compareUrlPath(t,e){if(!t||!e)return!1;const s=this.parseUrl(t),a=this.parseUrl(e);return s.pathname===a.pathname}compareUrlFull(t,e){if(!t||!e)return!1;const s=this.parseUrl(t),a=this.parseUrl(e);return s.fullPath===a.fullPath}clear(){this.postmateParent&&(this.postmateParent.destroy(),this.postmateParent=null),this.currentIframe&&this.currentIframe.parentNode&&this.currentIframe.parentNode.removeChild(this.currentIframe),this.currentIframe=null}async init(t=null){if(this.clear(),this.childSupportsRouteUpdate=!0,!this.iframeEle||!this.currentUrl){console.warn("iframeEle 和 currentUrl 是必需的");return}const e=typeof this.iframeEle=="function"?this.iframeEle():this.iframeEle;if(!e){console.warn("无法获取 iframe 容器");return}const s=new h({container:e,url:this.currentUrl,name:"",model:""});this.currentIframe=e.querySelector("iframe"),this.currentIframe.setAttribute("frameborder","0"),this.currentIframe.setAttribute("allow","fullscreen"),this.currentIframe.addEventListener("load",()=>{this.loadFunction&&this.loadFunction()}),s.then(a=>{this.postmateParent=a,a.on("requestBaseData",()=>{this.sendData()}),a.on("otherRequest",r=>{this.handleOtherRequest&&this.handleOtherRequest(r)}),typeof t=="function"&&t()}).catch(a=>{console.error("Postmate 连接失败:",a)})}setLoadFunction(t){this.loadFunction=t}setIframeUrl(t){if(this.currentUrl===t)return;if(!this.currentUrl){this.currentUrl=t,this.parsedCurrentUrl=this.parseUrl(t),this.iframeEle&&this.init();return}const e=this.parseUrl(t);if(this.postmateParent&&this.compareUrlBase(this.currentUrl,t)&&this.childSupportsRouteUpdate)if(this.compareUrlPath(this.currentUrl,t)){if(this.compareUrlFull(this.currentUrl,t))return;this.currentUrl=t,this.parsedCurrentUrl=e,this.sendRouteUpdate(e);return}else{this.currentUrl=t,this.parsedCurrentUrl=e,this.sendRouteUpdate(e);return}this.currentUrl=t,this.parsedCurrentUrl=e,this.iframeEle&&this.init()}sendRouteUpdate(t){if(this.postmateParent){if(!this.childSupportsRouteUpdate){console.warn("子页面不支持路由更新,直接重新初始化iframe"),this.init();return}try{this.postmateParent.call("routeUpdate",JSON.stringify({fullPath:t.fullPath,pathname:t.pathname,search:t.search,hash:t.hash}));let e=!1;const s=a=>{try{const r=JSON.parse(a.data);r&&r.type==="route_update_support"&&r.supported===!0&&(e=!0,window.removeEventListener("message",s))}catch{}};window.addEventListener("message",s),setTimeout(()=>{window.removeEventListener("message",s),e||(console.warn("子页面不支持路由更新,将在下次更新时重新初始化iframe"),this.childSupportsRouteUpdate=!1,this.init())},1e3)}catch(e){console.warn("发送路由更新消息失败,将重新初始化iframe:",e),this.childSupportsRouteUpdate=!1,this.init()}}}sendData(){this.postmateParent&&this.postmateParent.call("baseData",JSON.stringify(this.dataInfo))}destroy(){this.clear()}}d.ChildPostmate=U,d.ParentPostmate=E,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})});
@@ -16,7 +16,7 @@ export default class ChildPostmate {
16
16
  getDataCllBack: Function | null;
17
17
  router: any;
18
18
  routeUpdateCallback: ((routeInfo: RouteUpdateInfo) => void) | null;
19
- constructor(eventObj: EventObj, router?: any, routeUpdateCallback?: (routeInfo: RouteUpdateInfo) => void);
19
+ constructor(eventObj: EventObj, router: any, routeUpdateCallback?: (routeInfo: RouteUpdateInfo) => void);
20
20
  init(eventObj: EventObj): void;
21
21
  getData(callback?: any): void;
22
22
  /**
@@ -32,6 +32,8 @@ export default class ParentPostmate {
32
32
  handleOtherRequest: ((params: any) => void) | null;
33
33
  /** 当前URL解析结果 */
34
34
  parsedCurrentUrl: ParsedUrl | null;
35
+ /** 子页面是否支持路由更新 */
36
+ childSupportsRouteUpdate: boolean;
35
37
  constructor(dataInfo: DataInfo, iframeEle: HTMLElement | (() => HTMLElement), iframeUrl?: string, handleOtherRequest?: (params: any) => void);
36
38
  /** 解析URL */
37
39
  parseUrl(url: string): ParsedUrl;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qlfy-postmate",
3
- "version": "1.1.8",
3
+ "version": "1.2.0",
4
4
  "description": "",
5
5
  "types": "lib/index.d.ts",
6
6
  "module": "lib/index.umd.js",