Skip to content

Commit 97ef19d

Browse files
Merge pull request #280 from openimsdk/chan
perf: optimize embed button loading with lazy iframe initialization
2 parents a9bddbe + 6171c4c commit 97ef19d

File tree

1 file changed

+184
-169
lines changed

1 file changed

+184
-169
lines changed

static/embed.js

Lines changed: 184 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -1,182 +1,197 @@
1+
function createButton() {
2+
const button = document.createElement('div');
3+
button.id = "wiseengage-guests-embed-button";
4+
5+
// 初始化样式
6+
Object.assign(button.style, {
7+
overflow: "hidden",
8+
position: "fixed",
9+
userSelect: "none",
10+
right: "20px",
11+
bottom: "40px",
12+
zIndex: "9999",
13+
width: "50px",
14+
height: "50px",
15+
borderRadius: "50%",
16+
display: "flex",
17+
justifyContent: "center",
18+
alignItems: "center",
19+
boxShadow: "0px 4px 8px rgba(0, 0, 0, 0.2)",
20+
cursor: "pointer",
21+
});
22+
button.style.backgroundColor = '#2160fd'
23+
button.style.padding = '8px'
24+
const iconImgEl = document.createElement('img');
25+
iconImgEl.src = '/logo/iframe-enter-icon-logo.svg';
26+
iconImgEl.style.width = '100%';
27+
iconImgEl.style.height = '100%';
28+
button.appendChild(iconImgEl);
29+
30+
return button;
31+
}
32+
33+
function createIframe() {
34+
const iframeWrap = document.createElement('div');
35+
const iframe = document.createElement('iframe');
36+
37+
iframeWrap.id = "wiseengage-guests-embed-iframe-wrap";
38+
iframe.id = "wiseengage-guests-embed-iframe";
39+
40+
Object.assign(iframeWrap.style, {
41+
position: "fixed",
42+
zIndex: "10000",
43+
borderRadius: "10px",
44+
boxShadow: "0px 10px 30px rgba(150, 150, 150, 0.2), 0px 0px 0px 1px rgba(150, 150, 150, 0.2)",
45+
transition: "transform 0.3s ease, opacity 0.3s ease",
46+
transform: "scale(0)",
47+
transformOrigin: "right bottom",
48+
opacity: 0,
49+
});
50+
51+
Object.assign(iframe.style, {
52+
width: "100%",
53+
height: "100%",
54+
});
55+
56+
return { iframeWrap, iframe };
57+
}
58+
159
(function () {
2-
console.log('[IFRAME] hello, embed injected')
3-
4-
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
5-
6-
const button = document.createElement('div');
7-
const iframe = document.createElement('iframe');
8-
9-
button.id = "openim-customer-service-embed-button";
10-
iframe.id = "openim-customer-service-embed-iframe";
11-
12-
let isMinMode = false;
13-
let isInit = false;
14-
const iframeSrc = "https://web.rentsoft.cn";
15-
const allowedOrigins = [iframeSrc];
16-
17-
function initUI() {
18-
Object.assign(button.style, {
19-
overflow: "hidden",
20-
position: "fixed",
21-
userSelect: "none",
22-
right: "20px",
23-
bottom: "40px",
24-
zIndex: "9999",
25-
width: "50px",
26-
height: "50px",
27-
borderRadius: "50%",
28-
display: "flex",
29-
justifyContent: "center",
30-
alignItems: "center",
31-
boxShadow: "0px 4px 8px rgba(0, 0, 0, 0.2)",
32-
cursor: "pointer",
33-
});
34-
button.style.backgroundColor = '#2160fd'
35-
button.style.padding = '8px'
36-
const iconImgEl = document.createElement('img');
37-
iconImgEl.src = '/logo/iframe-enter-icon-logo.svg';
38-
iconImgEl.style.width = '100%';
39-
iconImgEl.style.height = '100%';
40-
button.appendChild(iconImgEl);
60+
console.log('[IFRAME] hello, embed injected')
61+
62+
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
63+
64+
let isMinMode = false;
65+
let isInit = false;
66+
let isLoadIframe = false;
67+
68+
// DEBUG:
69+
const iframeSrc = "https://web.rentsoft.cn";
70+
const allowedOrigins = [iframeSrc];
71+
72+
const { iframeWrap, iframe } = createIframe();
73+
const button = createButton();
4174

75+
function initUI() {
76+
document.body.appendChild(iframeWrap);
77+
document.body.appendChild(button);
78+
isInit = true;
79+
80+
adjustIframeStyleForSmallScreens();
81+
}
82+
83+
const fireToIframe = (event, data) => {
84+
iframe.contentWindow?.postMessage({ event, data }, '*');
85+
};
86+
87+
button.onclick = function () {
88+
console.log('[embed] click button')
89+
90+
const isMinWidth = window.matchMedia("(max-width: 768px)").matches || isMobile;
91+
const isHidden = iframeWrap.style.transform === "scale(0)";
92+
93+
if (isHidden) {
94+
if (!isLoadIframe) {
4295
iframe.src = iframeSrc;
43-
Object.assign(iframe.style, {
44-
position: "fixed",
45-
zIndex: "10000",
46-
borderRadius: "10px",
47-
boxShadow: "0px 10px 30px rgba(150, 150, 150, 0.2), 0px 0px 0px 1px rgba(150, 150, 150, 0.2)",
48-
transition: "transform 0.3s ease, opacity 0.3s ease",
49-
transform: "scale(0)",
50-
transformOrigin: "right bottom",
51-
opacity: 0,
52-
});
53-
54-
document.body.appendChild(iframe);
55-
isInit = true;
56-
57-
adjustIframeStyleForSmallScreens();
96+
iframeWrap.appendChild(iframe);
97+
isLoadIframe = true;
98+
}
99+
fireToIframe('openIframe', isMinWidth);
100+
iframeWrap.style.transform = "scale(1)";
101+
iframeWrap.style.opacity = 1;
102+
} else {
103+
iframeWrap.style.transform = "scale(0)";
104+
iframeWrap.style.opacity = 0;
105+
}
106+
if (isMinWidth && isHidden) {
107+
document.body.style.overflow = 'hidden';
108+
document.documentElement.style.overflow = 'hidden';
58109
}
110+
};
59111

60-
const fireToIframe = (event, data) => {
61-
iframe.contentWindow?.postMessage({ event, data }, '*');
62-
};
63-
64-
button.onclick = function () {
65-
console.log('[embed] click button')
66-
67-
const isMinWidth = window.matchMedia("(max-width: 768px)").matches || isMobile;
68-
const isHidden = iframe.style.transform === "scale(0)";
69-
70-
if (isHidden) {
71-
fireToIframe('openIframe', isMinWidth);
72-
iframe.style.transform = "scale(1)";
73-
iframe.style.opacity = 1;
74-
} else {
75-
iframe.style.transform = "scale(0)";
76-
iframe.style.opacity = 0;
77-
}
78-
if (isMinWidth && isHidden) {
79-
document.body.style.overflow = 'hidden';
80-
document.documentElement.style.overflow = 'hidden';
112+
let isGetConfig = false;
113+
const rpc = setupParentRPCListener({
114+
allowedOrigins: allowedOrigins, // ★ 必填:子页面来源
115+
debug: true,
116+
handler: async function ({ action, data }) {
117+
if (action === 'closeIframe') {
118+
iframeWrap.style.transform = "scale(0)";
119+
iframeWrap.style.opacity = 0;
120+
document.body.style.overflow = '';
121+
document.documentElement.style.overflow = '';
122+
}
123+
if (action === 'toogleSize') {
124+
iframeWrap.style.width = isMinMode ? "720px" : "420px";
125+
iframeWrap.style.height = isMinMode ? "80vh" : "60vh";
126+
isMinMode = !isMinMode;
127+
}
128+
if (action === 'getConfig') {
129+
console.log('get config', data, isGetConfig);
130+
if(isGetConfig) return;
131+
document.body.appendChild(button);
132+
isGetConfig = true;
133+
}
134+
},
135+
});
136+
137+
// 在页面关闭/刷新时清理监听,避免内存泄漏,并使变量被有效使用
138+
try {
139+
window.addEventListener('beforeunload', function () {
140+
try {
141+
if (rpc && typeof rpc.dispose === 'function') {
142+
rpc.dispose();
81143
}
82-
};
83-
84-
let isGetConfig = false;
85-
const rpc = setupParentRPCListener({
86-
allowedOrigins: allowedOrigins, // ★ 必填:子页面来源
87-
debug: true,
88-
handler: async function ({ action, data }) {
89-
if (action === 'closeIframe') {
90-
iframe.style.transform = "scale(0)";
91-
iframe.style.opacity = 0;
92-
document.body.style.overflow = '';
93-
document.documentElement.style.overflow = '';
94-
}
95-
if (action === 'toogleSize') {
96-
iframe.style.width = isMinMode ? "720px" : "420px";
97-
iframe.style.height = isMinMode ? "80vh" : "60vh";
98-
isMinMode = !isMinMode;
99-
}
100-
if (action === 'getConfig') {
101-
console.log('get config', data, isGetConfig);
102-
if(isGetConfig) return;
103-
// if(data){
104-
// button.style.backgroundColor = '#2160fd'
105-
// button.style.padding = '8px'
106-
// const iconImgEl = document.createElement('img');
107-
// iconImgEl.src = data.iconUrl;
108-
// iconImgEl.style.width = '100%';
109-
// iconImgEl.style.height = '100%';
110-
// button.appendChild(iconImgEl);
111-
// }else {
112-
// button.innerHTML = "Ask";
113-
// button.style.color = "white";
114-
// button.style.backgroundColor = "#2160fd";
115-
// }
116-
document.body.appendChild(button);
117-
isGetConfig = true;
118-
}
119-
},
144+
} catch (e) {
145+
/* ignore dispose errors */
146+
console.error(e);
147+
}
120148
});
149+
} catch (e) {
150+
/* ignore addEventListener errors */
151+
console.error(e);
152+
}
121153

122-
// 在页面关闭/刷新时清理监听,避免内存泄漏,并使变量被有效使用
123-
try {
124-
window.addEventListener('beforeunload', function () {
125-
try {
126-
if (rpc && typeof rpc.dispose === 'function') {
127-
rpc.dispose();
128-
}
129-
} catch (e) {
130-
/* ignore dispose errors */
131-
console.error(e);
132-
}
133-
});
134-
} catch (e) {
135-
/* ignore addEventListener errors */
136-
console.error(e);
154+
window.onload = initUI;
155+
156+
function adjustIframeStyleForSmallScreens() {
157+
if (!isInit) return;
158+
const isMinWidth = window.matchMedia("(max-width: 768px)").matches || isMobile;
159+
const isHidden = iframeWrap.style.transform === "scale(0)";
160+
161+
if (isMinWidth) {
162+
Object.assign(iframeWrap.style, {
163+
width: "100%",
164+
height: "100%",
165+
right: "0",
166+
bottom: "0",
167+
left: "0",
168+
top: "0",
169+
borderRadius: "0",
170+
boxShadow: "none",
171+
});
172+
if (!isHidden) {
173+
document.body.style.overflow = 'hidden';
174+
document.documentElement.style.overflow = 'hidden';
175+
fireToIframe('resizeIframe', true);
176+
}
177+
} else {
178+
Object.assign(iframeWrap.style, {
179+
width: isMinMode ? "420px" : "640px",
180+
height: isMinMode ? "60vh" : "80vh",
181+
right: "20px",
182+
bottom: "100px",
183+
left: "unset",
184+
top: "unset",
185+
borderRadius: "10px",
186+
boxShadow: "0px 10px 30px rgba(150, 150, 150, 0.2), 0px 0px 0px 1px rgba(150, 150, 150, 0.2)",
187+
});
188+
document.body.style.overflow = '';
189+
document.documentElement.style.overflow = '';
190+
fireToIframe('resizeIframe', false);
137191
}
192+
}
138193

139-
window.onload = initUI;
140-
141-
function adjustIframeStyleForSmallScreens() {
142-
if (!isInit) return;
143-
const isMinWidth = window.matchMedia("(max-width: 768px)").matches || isMobile;
144-
const isHidden = iframe.style.transform === "scale(0)";
145-
146-
if (isMinWidth) {
147-
Object.assign(iframe.style, {
148-
width: "100%",
149-
height: "100%",
150-
right: "0",
151-
bottom: "0",
152-
left: "0",
153-
top: "0",
154-
borderRadius: "0",
155-
boxShadow: "none",
156-
});
157-
if (!isHidden) {
158-
document.body.style.overflow = 'hidden';
159-
document.documentElement.style.overflow = 'hidden';
160-
fireToIframe('resizeIframe', true);
161-
}
162-
} else {
163-
Object.assign(iframe.style, {
164-
width: isMinMode ? "420px" : "640px",
165-
height: isMinMode ? "60vh" : "80vh",
166-
right: "20px",
167-
bottom: "100px",
168-
left: "unset",
169-
top: "unset",
170-
borderRadius: "10px",
171-
boxShadow: "0px 10px 30px rgba(150, 150, 150, 0.2), 0px 0px 0px 1px rgba(150, 150, 150, 0.2)",
172-
});
173-
document.body.style.overflow = '';
174-
document.documentElement.style.overflow = '';
175-
fireToIframe('resizeIframe', false);
176-
}
177-
}
178-
179-
window.addEventListener('resize', adjustIframeStyleForSmallScreens);
194+
window.addEventListener('resize', adjustIframeStyleForSmallScreens);
180195
})();
181196

182197
// parent-rpc.js

0 commit comments

Comments
 (0)