Vue初始化完成后运行Raychat JS 无需监听raychat_ready方案
问题背景
需求为仅在Vue完全加载并初始化完成后,才运行、初始化对应JavaScript代码。当前需要接入第三方在线聊天服务Raychat,该服务常规初始化需要通过addEventListener监听raychat_ready事件后执行初始化逻辑,现需在Vue组件中完成该服务的集成。
以下是当前项目public/index.html中放置的Raychat官方引入代码:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width,initial-scale=1.0" /> <link rel="icon" href="<%= BASE_URL %>main-logo.png" /> <title><%= htmlWebpackPlugin.options.title %></title> </head> <body> <noscript> <strong >We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong > </noscript> <div id="app"></div> <!--BEGIN RAYCHAT CODE--> <script type="text/javascript"> !(function () { function t() { var t = document.createElement("script"); (t.type = "text/javascript"), (t.async = !0), localStorage.getItem("rayToken") ? (t.src = "https://app.raychat.io/scripts/js/" + o + "?rid=" + localStorage.getItem("rayToken") + "&href=" + window.location.href) : (t.src = "https://app.raychat.io/scripts/js/" + o + "?href=" + window.location.href); var e = document.getElementsByTagName("script")[0]; e.parentNode.insertBefore(t, e); } var e = document, a = window, o = "%= NODE_ENV %" === "development" ? "development-token" : "production-token"; "complete" == e.readyState ? t() : a.attachEvent ? a.attachEvent("onload", t) : a.addEventListener("load", t, !1); })(); </script> <!--END RAYCHAT CODE--> </body> </html>
现存问题
常规的Raychat用户信息同步逻辑需要写在raychat_ready事件监听回调中,示例代码如下:
window.addEventListener('raychat_ready', () => { const user = JSON.parse(localStorage.getItem('user')); if (user) { window.Raychat.setUser({ updateOnce: false, about: `id: ${user.id}`, name: user.name, phone: user.mobile, avatar: user.avatar ? user.avatar : 'https://png.pngtree.com/png-vector/20190223/ourlarge/pngtree-vector-avatar-icon-png-image_695765.jpg', }); } });
当前诉求是不希望将业务代码写在addEventListener绑定的raychat_ready事件回调中,需要可在Vue组件内完成Raychat初始化、无需显式绑定该事件监听的可行实现方案。
实现方案
核心思路是把事件监听逻辑封装成可复用的Promise工具,抹平Raychat加载和Vue生命周期的时序差异,组件内无需手动绑定事件,直接以异步调用的方式写业务逻辑即可。
第一步:封装Raychat就绪等待工具
新建src/utils/raychat.js文件,写入以下代码,内部自动处理实例已存在、事件绑定与移除逻辑:export const waitRaychatReady = () => { return new Promise((resolve) => { // 若Raychat已完成初始化,直接返回实例 if (window.Raychat) return resolve(window.Raychat) // 未就绪则监听一次就绪事件,触发后自动移除监听避免内存泄漏 const handleReady = () => { window.removeEventListener('raychat_ready', handleReady) resolve(window.Raychat) } window.addEventListener('raychat_ready', handleReady) }) }第二步:在Vue组件中调用
直接在根组件的挂载生命周期中调用工具方法即可,onMounted/mounted触发时Vue已经完成初始化,符合执行时机要求。Vue3 组合式API示例:
<script setup> import { onMounted } from 'vue' import { waitRaychatReady } from '@/utils/raychat' onMounted(async () => { // 等待Raychat就绪,无需手动绑定事件 const Raychat = await waitRaychatReady() // 直接编写业务逻辑,无需嵌套在事件回调中 const user = JSON.parse(localStorage.getItem('user')) if (user) { Raychat.setUser({ updateOnce: false, about: `id: ${user.id}`, name: user.name, phone: user.mobile, avatar: user.avatar || 'https://png.pngtree.com/png-vector/20190223/ourlarge/pngtree-vector-avatar-icon-png-image_695765.jpg' }) } }) </script>Vue2 选项式API示例:
import { waitRaychatReady } from '@/utils/raychat' export default { async mounted() { const Raychat = await waitRaychatReady() // 后续Raychat相关业务逻辑直接写在这里 } }
方案优势
- 自动适配时序:无论Vue挂载和Raychat脚本加载哪个先完成,都能正常拿到实例,不会出现事件绑定过晚漏触发的问题
- 无内存泄漏:事件触发后会自动移除监听,不会残留无效事件绑定
- 代码结构清晰:所有业务逻辑按线性顺序编写,没有回调嵌套
- 复用性强:其他组件需要调用Raychat能力(比如手动打开聊天窗口、更新用户信息)时,直接导入
waitRaychatReady即可,不需要重复判断加载状态
内容的提问来源于stack exchange,提问作者Niaz Estefaie
相关产品推荐
相关产品推荐

