
(function (window) { // 私有作用域不污染全局 const AI_FLOAT_PLUGIN function () { // 配置项 const config { // iframe 地址外部可修改 iframeSrc: https://www.baidu.com, // 弹窗宽高 modalWidth: 420, modalHeight: 520, // 悬浮球大小 btnSize: 56, // 主题色 primaryColor: #1677ff }; // 拖拽状态 const state { btnDrag: { isDrag: false, offsetX: 0, offsetY: 0 }, modalDrag: { isDrag: false, startX: 0, startY: 0, startLeft: 0, startTop: 0 } }; // 容器DOM let floatBtn null; let modalWrap null; let modalHeader null; let closeBtn null; let iframe null; // 创建样式 function createStyle() { const style document.createElement(style); style.id ai-float-plugin-style; style.textContent #ai-float-btn { position: fixed; right: 20px; bottom: 120px; width: ${config.btnSize}px; height: ${config.btnSize}px; border-radius: 50%; background: ${config.primaryColor}; box-shadow: 0 4px 12px rgba(22, 119, 255, 0.3); cursor: move; z-index: 99999; display: flex; align-items: center; justify-content: center; color: #fff; font-size: 24px; user-select: none; transition: transform 0.2s; } #ai-float-btn:hover { transform: scale(1.08); } #ai-modal-wrap { position: fixed; width: ${config.modalWidth}px; height: ${config.modalHeight}px; background: #fff; border-radius: 12px; box-shadow: 0 8px 30px rgba(0,0,0,0.2); z-index: 99998; overflow: hidden; display: none; user-select: none; } #ai-modal-header { height: 40px; line-height: 40px; background: ${config.primaryColor}; color: #fff; padding: 0 15px; display: flex; align-items: center; justify-content: space-between; cursor: move; } #ai-modal-close { font-size: 20px; cursor: pointer; padding: 0 8px; } #ai-modal-close:hover { color: #f5f5f5; } #ai-iframe { width: 100%; height: calc(100% - 40px); border: none; } ; document.head.appendChild(style); } // 创建DOM结构 function createDom() { // 悬浮按钮 floatBtn document.createElement(div); floatBtn.id ai-float-btn; floatBtn.innerText AI; // 弹窗外层 modalWrap document.createElement(div); modalWrap.id ai-modal-wrap; // 弹窗头部 modalHeader document.createElement(div); modalHeader.id ai-modal-header; modalHeader.innerHTML spanAI智能助手/span; // 关闭按钮 closeBtn document.createElement(span); closeBtn.id ai-modal-close; closeBtn.innerText ×; modalHeader.appendChild(closeBtn); // iframe iframe document.createElement(iframe); iframe.id ai-iframe; iframe.src config.iframeSrc; // 组装 modalWrap.appendChild(modalHeader); modalWrap.appendChild(iframe); // 挂载到body document.body.appendChild(floatBtn); document.body.appendChild(modalWrap); } // 悬浮球拖拽 function bindBtnDrag() { floatBtn.addEventListener(mousedown, (e) { if (e.button ! 0) return; state.btnDrag.isDrag true; const rect floatBtn.getBoundingClientRect(); state.btnDrag.offsetX e.clientX - rect.left; state.btnDrag.offsetY e.clientY - rect.top; floatBtn.style.transition none; e.preventDefault(); }); document.addEventListener(mousemove, (e) { if (!state.btnDrag.isDrag) return; const winW window.innerWidth; const winH window.innerHeight; const btnW floatBtn.offsetWidth; const btnH floatBtn.offsetHeight; let x e.clientX - state.btnDrag.offsetX; let y e.clientY - state.btnDrag.offsetY; x Math.max(0, Math.min(x, winW - btnW)); y Math.max(0, Math.min(y, winH - btnH)); floatBtn.style.left x px; floatBtn.style.right auto; floatBtn.style.top y px; }); document.addEventListener(mouseup, () { if (state.btnDrag.isDrag) { state.btnDrag.isDrag false; floatBtn.style.transition transform 0.2s; } }); } // 点击打开弹窗 function bindBtnClick() { floatBtn.addEventListener(click, () { // 拖拽不触发点击 if (state.btnDrag.isDrag) return; modalWrap.style.display block; // 弹窗居中 const winW window.innerWidth; const winH window.innerHeight; const mW modalWrap.offsetWidth; const mH modalWrap.offsetHeight; modalWrap.style.left (winW - mW) / 2 px; modalWrap.style.top (winH - mH) / 2 px; }); } // 弹窗关闭 function bindClose() { closeBtn.addEventListener(click, () { modalWrap.style.display none; }); // ESC关闭 document.addEventListener(keydown, (e) { if (e.key Escape) { modalWrap.style.display none; } }); } // 弹窗拖拽 function bindModalDrag() { modalHeader.addEventListener(mousedown, (e) { if (e.button ! 0) return; state.modalDrag.isDrag true; state.modalDrag.startX e.clientX; state.modalDrag.startY e.clientY; const rect modalWrap.getBoundingClientRect(); state.modalDrag.startLeft rect.left; state.modalDrag.startTop rect.top; e.preventDefault(); }); document.addEventListener(mousemove, (e) { if (!state.modalDrag.isDrag) return; const winW window.innerWidth; const winH window.innerHeight; const mW modalWrap.offsetWidth; const mH modalWrap.offsetHeight; const moveX e.clientX - state.modalDrag.startX; const moveY e.clientY - state.modalDrag.startY; let newLeft state.modalDrag.startLeft moveX; let newTop state.modalDrag.startTop moveY; newLeft Math.max(0, Math.min(newLeft, winW - mW)); newTop Math.max(0, Math.min(newTop, winH - mH)); modalWrap.style.left newLeft px; modalWrap.style.top newTop px; }); document.addEventListener(mouseup, () { state.modalDrag.isDrag false; }); } // 初始化 function init(options {}) { // 合并外部配置 Object.assign(config, options); // 防止重复创建 if (document.getElementById(ai-float-btn)) return; createStyle(); createDom(); bindBtnDrag(); bindBtnClick(); bindClose(); bindModalDrag(); } // 对外暴露方法 return { init, // 手动关闭弹窗 closeModal() { if (modalWrap) modalWrap.style.display none; }, // 手动打开弹窗 openModal() { if (modalWrap) modalWrap.style.display block; }, // 更新iframe地址 setIframeSrc(url) { if (iframe) iframe.src url; }, // 销毁插件 destroy() { const style document.getElementById(ai-float-plugin-style); style style.remove(); floatBtn floatBtn.remove(); modalWrap modalWrap.remove(); } }; }; // 挂载到全局兼容所有框架 window.AiFloatPlugin AI_FLOAT_PLUGIN(); })(window);