访客落地页、在线读秒与浏览轨迹
记录进线页面与换页路径,心跳刷新活跃时间;工作台展示落地页/当前页/轨迹时间线与在线时长,嵌入脚本同步宿主 SPA 路由。
This commit is contained in:
+86
-1
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* 客服云访客 Widget 嵌入脚本
|
||||
* 用法: <script src="https://your-host/widget.js" data-id="WK_xxxx"></script>
|
||||
*
|
||||
* 向 iframe 同步宿主页 URL / 标题,并监听 SPA 路由变化,供客服端展示落地页与浏览轨迹。
|
||||
*/
|
||||
(function () {
|
||||
if (window.__KEFU_WIDGET_LOADED__) return;
|
||||
@@ -28,6 +30,8 @@
|
||||
|
||||
var open = false;
|
||||
var iframe = null;
|
||||
var lastSentURL = '';
|
||||
var lastSentAt = 0;
|
||||
|
||||
var btn = document.createElement('button');
|
||||
btn.type = 'button';
|
||||
@@ -51,13 +55,56 @@
|
||||
'display:none', 'background:#fff',
|
||||
].join(';');
|
||||
|
||||
function hostPageInfo() {
|
||||
var href = '';
|
||||
var title = '';
|
||||
var ref = '';
|
||||
try {
|
||||
href = String(window.location.href || '');
|
||||
title = String(document.title || '');
|
||||
ref = String(document.referrer || '');
|
||||
} catch (e) { /* ignore */ }
|
||||
return { url: href, title: title, referrer: ref };
|
||||
}
|
||||
|
||||
function buildEmbedURL() {
|
||||
var info = hostPageInfo();
|
||||
var q =
|
||||
'channel_key=' + encodeURIComponent(channelKey) +
|
||||
'&embedded=1' +
|
||||
'&page_url=' + encodeURIComponent(info.url) +
|
||||
'&page_title=' + encodeURIComponent(info.title) +
|
||||
'&referrer=' + encodeURIComponent(info.referrer);
|
||||
return base + '/widget/embed?' + q;
|
||||
}
|
||||
|
||||
function postPageToIframe(force) {
|
||||
if (!iframe || !iframe.contentWindow) return;
|
||||
var info = hostPageInfo();
|
||||
var now = Date.now();
|
||||
if (!force && info.url === lastSentURL && now - lastSentAt < 800) return;
|
||||
lastSentURL = info.url;
|
||||
lastSentAt = now;
|
||||
try {
|
||||
iframe.contentWindow.postMessage({
|
||||
type: 'kefu-host-page',
|
||||
url: info.url,
|
||||
title: info.title,
|
||||
referrer: info.referrer,
|
||||
}, '*');
|
||||
} catch (e) { /* ignore */ }
|
||||
}
|
||||
|
||||
function ensureIframe() {
|
||||
if (iframe) return;
|
||||
iframe = document.createElement('iframe');
|
||||
iframe.title = '在线客服';
|
||||
iframe.allow = 'clipboard-write';
|
||||
iframe.style.cssText = 'width:100%;height:100%;border:0;display:block;background:#fff;';
|
||||
iframe.src = base + '/widget/embed?channel_key=' + encodeURIComponent(channelKey) + '&embedded=1';
|
||||
iframe.src = buildEmbedURL();
|
||||
iframe.addEventListener('load', function () {
|
||||
postPageToIframe(true);
|
||||
});
|
||||
panel.appendChild(iframe);
|
||||
}
|
||||
|
||||
@@ -67,6 +114,7 @@
|
||||
ensureIframe();
|
||||
panel.style.display = 'block';
|
||||
btn.style.display = 'none';
|
||||
postPageToIframe(true);
|
||||
} else {
|
||||
panel.style.display = 'none';
|
||||
btn.style.display = 'flex';
|
||||
@@ -80,8 +128,45 @@
|
||||
if (event.data.type === 'kefu-widget-close' || event.data.type === 'kefu-widget-minimize') {
|
||||
setOpen(false);
|
||||
}
|
||||
// iframe 就绪后可再次同步宿主页
|
||||
if (event.data.type === 'kefu-widget-ready') {
|
||||
postPageToIframe(true);
|
||||
}
|
||||
});
|
||||
|
||||
// —— SPA / 浏览器导航监听 ——
|
||||
function onRouteMaybeChanged() {
|
||||
if (!open) return;
|
||||
postPageToIframe(false);
|
||||
}
|
||||
|
||||
try {
|
||||
var _push = history.pushState;
|
||||
var _replace = history.replaceState;
|
||||
history.pushState = function () {
|
||||
var r = _push.apply(this, arguments);
|
||||
onRouteMaybeChanged();
|
||||
return r;
|
||||
};
|
||||
history.replaceState = function () {
|
||||
var r = _replace.apply(this, arguments);
|
||||
onRouteMaybeChanged();
|
||||
return r;
|
||||
};
|
||||
} catch (e) { /* ignore */ }
|
||||
|
||||
window.addEventListener('popstate', onRouteMaybeChanged);
|
||||
window.addEventListener('hashchange', onRouteMaybeChanged);
|
||||
// 标题可能异步更新
|
||||
try {
|
||||
var titleEl = document.querySelector('title');
|
||||
if (titleEl && typeof MutationObserver !== 'undefined') {
|
||||
new MutationObserver(function () { onRouteMaybeChanged(); }).observe(titleEl, {
|
||||
subtree: true, characterData: true, childList: true,
|
||||
});
|
||||
}
|
||||
} catch (e) { /* ignore */ }
|
||||
|
||||
function mount() {
|
||||
document.body.appendChild(btn);
|
||||
document.body.appendChild(panel);
|
||||
|
||||
Reference in New Issue
Block a user