Vue在线客服插件不装也能接
作者:周屿|更新于 2026-10-26
公司官网是 Vue 写的。运营过来说一句,网站上加个在线客服吧。
做前端的,多半先去 npm 上搜「Vue在线客服插件」,想找个装上就能用的组件。搜出来的,大多是别人自己写的聊天组件。界面是有了,可消息谁来回、存在哪,还得自己再搭一套后台。
其实不用装插件,也不用自己搭后台。接上以后,客户在网页上点一下,就能打开聊天窗问。客服在客服系统里看到这条消息,直接回,客户在聊天窗里就能看到。

前端要做的,就是往项目里贴一段代码,再在组件里调几下。下面用合从按顺序走一遍。
先拿到那段代码
代码在合从的工作台里拿。工作台,就是客服平时回消息的那个网页。
登录工作台,点「设置」,在「客户」下面找到「渠道管理」,点「接入新渠道」。
类型选「网页接入」,名字起一个自己认得的,比如「官网」,点「创建渠道」。建好以后,页面就停在「安装代码」,点「复制代码」。

复制出来的代码里,已经带好了这个渠道的编号,不用改。
没建过渠道的,网站贴一段代码就能接待那篇写得更细。
Vue 项目里,代码贴在 index.html
拿到代码,很多人先想到的是放进 App.vue,在 onMounted 里用 document.createElement 插进去,觉得这样更像 Vue 的写法。
不用这样。聊天窗是跟着整个页面走的,不跟着组件走。组件创建、销毁,它都在。放进组件里,组件重新挂载一次,script 就多插一次。
所以就贴在 index.html 里,跟普通网页一样。Vite 建的项目,index.html 在根目录。Vue CLI 建的,在 public/ 里。
贴在 </body> 前面,后面再跟一行占位函数:
<!-- index.html:Vite 建的项目在根目录,Vue CLI 建的在 public/ 里 -->
<body>
<div id="app"></div>
<script async
src="https://assets.aihecong.com/sdk/hecong.js"
data-channel-id="0190a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b">
</script>
<script>
window.hecong = window.hecong || function (c) { (window.hecong.q = window.hecong.q || []).push(c) }
</script>
</body>
data-channel-id 换成你复制出来的那个。占位函数照原样抄,后面组件里会用到。
贴完就能用了,不用写初始化代码。按钮颜色、文案、欢迎语,都在工作台里改。运营想换欢迎语,自己去改,不用你再发版。合从也没有 npm 包,就这一段 script。
要放进手机上的活动页,按钮挡住页面怎么办,H5 落地页上的客服按钮怎么在手机上调讲过。
点自己的按钮打开聊天窗
贴完,网页右下角就有聊天按钮了。可很多官网本来就有一个「咨询客服」按钮,在帮助中心、商品页这些地方。产品要的是,客户点这个按钮,打开的就是聊天窗。
在点击事件里这样写:
<template>
<button @click="openChat">咨询客服</button>
</template>
<script setup>
function openChat() {
window.hecong((hc) => hc.open())
}
</script>
有人会担心,script 是异步加载的,组件可能比它先跑。客户一进页面就点按钮,那时候还没有 window.hecong,会不会报错?
不会,前面那行占位函数就是管这个的。有了它,window.hecong 从一开始就在。早调的先排着队,等 script 加载好再执行。所以组件里什么时候调都行,换了路由以后再调也行。
自己的按钮能用了,右下角那个就多余了。到这个渠道的「启动器」里,找到「按钮来源」。
把它改成「使用自有按钮」,右下角的按钮就不出来了。

改之前,先把自己的按钮发上线。不然中间这段时间,页面上一个能问的地方都没有。原来的按钮样式会留着,切回去就恢复。
把登录的客户带给客服
网站有登录的,客服最想知道的是这人是谁。不传的话,客服看到的就是一个匿名客户,是谁还得再问一遍。
传之前,先想好用什么当 id。合从是按 id 认人的,id 一样,就当成同一个客户。
很多人顺手就用数据库里的自增编号,1001、1002 这种。可这种数,别人随手改一个就能对上另一个客户。两个人传了同一个 id,后来的那位,会看到前一位的聊天记录。手机号、邮箱也一样,别人能猜到。
所以 id 要用别人猜不到的值,数据库里的 UUID 就可以。拿不到这种 id 的时候,就别传,按匿名客户接待,也别传一个固定值凑数。
id 想好了,Vue 3 里用 watchEffect 跟着登录状态走。客户登录了,就调 identify,把 id 和姓名传过去。客户退出登录,调一次 reset:
import { watchEffect } from 'vue'
// user 是项目里存登录用户的 ref,比如从 Pinia 里取
watchEffect(() => {
if (!user.value) return
window.hecong((hc) => {
hc.identify({ id: user.value.uuid, profile: { name: user.value.name } })
})
})
// 客户退出登录时
function onLogout() {
window.hecong((hc) => hc.reset())
}
reset 不能省。营业厅、展厅平板这种好几个人用的机器,上一位退出了,下一位不登录,就会顶着上一位的身份进来,看到上一位的聊天记录。
传好以后,客服在工作台对话的右边,就能看到网站传来的姓名。

换路由时收个尾
Vue 做的是单页应用,换页面不刷新。组件没了,它在聊天窗上挂的东西还在。有两样要自己收。
自己加的监听
比如想统计客户打开了几次聊天窗,在组件里用 hc.on 监听。组件每挂载一次,就多注册一次。客户来回切几次页面,打开一次聊天窗,统计就记了好几遍。
hc.on 会返回一个退订函数,在 onBeforeUnmount 里调它:
import { onMounted, onBeforeUnmount } from 'vue'
let off
let cancelled = false
onMounted(() => {
window.hecong((hc) => {
if (cancelled) return
off = hc.on('chat:open', () => {
// 你的统计代码
})
})
})
onBeforeUnmount(() => {
cancelled = true
off?.()
})
cancelled 管的是另一种情况。客户切走得太快,script 还没加载好,组件就卸载了,这时候还没拿到 off。有了它,迟到的回调就不会再去注册。
带进输入框的商品
商品页常用 setPresend,把正在看的商品带进聊天窗的输入框。客户换到别的页面,它不会自动清。
结果客户到了订单页,点开聊天窗想问物流,输入框里还是上一件商品。
在商品页组件卸载的时候清掉,或者到了新页面再调一次:
onBeforeUnmount(() => {
window.hecong((hc) => hc.setPresend(null))
})
聊天窗本身不用管,组件卸载了它照样在页面上。identify 也不用管。
TypeScript 报错
项目用 TypeScript 的话,写 window.hecong 会报错,说 Window 上没有这个属性。
合从没有类型声明包,在 src 下自己写一个 hecong.d.ts 就行。用到哪几个方法,就声明哪几个:
// src/hecong.d.ts
interface HecongApi {
identify(args: { id: string; profile?: { name?: string } }): Promise<unknown>
reset(): Promise<unknown>
open(): void
setPresend(input: { text?: string } | null): void
// eslint-disable-next-line @typescript-eslint/no-explicit-any
on(event: string, handler: (arg: any) => void): () => void
}
declare global {
interface Window {
hecong: (cb: (hc: HecongApi) => void) => void
}
}
export {}
完整的写法在文档站的 React 与 Vue 接入示例里,可以整段复制。
本地跑一遍再提交
上线前,先在本地试。新建的渠道不限域名,npm run dev 起来,localhost 上就能调通。
打开页面,回到工作台的「安装代码」页,看下面的「安装状态」。有人打开页面几秒后,它会亮成「已安装」。
再点开聊天窗发一句话,回工作台看这条消息到了没有。
登录过的,顺便看一眼客服那边有没有姓名。注意,传过去的资料要等客户点开聊天窗才发出去。所以先登录、点开聊天窗,再去工作台看。
都对了,再提交代码。聊天窗长什么样、欢迎语说什么,交给运营去调,聊天窗口的样式和欢迎语怎么设置单独写过。
常见问题
Nuxt 项目怎么放?
Nuxt 没有固定的 index.html。聊天窗又要用 document 和 window,只能在浏览器里跑。
那就放在 app.vue 这种整个应用只跑一次的地方,在 onMounted 里插一次:
<!-- app.vue,别放进会随路由反复挂载的组件 -->
<script setup>
onMounted(() => {
window.hecong = window.hecong || function (c) { (window.hecong.q = window.hecong.q || []).push(c) }
const s = document.createElement('script')
s.async = true
s.src = 'https://assets.aihecong.com/sdk/hecong.js'
s.dataset.channelId = '0190a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b'
document.body.appendChild(s)
})
</script>
React 项目也是这样接吗?
是。React 和 Vue 用的是同一段 script,同样放在 index.html 里。组件里在 useEffect 里调 window.hecong,打开聊天窗、传客户身份的写法和上面一样。换路由时,同样要在清理函数里退订。
Vue 项目能接 AI 客服吗?
能。聊天窗还是这一个,代码不用改。
在工作台点「设置」,找到「渠道管理」,选中这个渠道。左边点「AI 机器人」,给它选一个机器人。
这样客户的消息就先由机器人接待,答不上来再转人工。
要后端配合吗?
不用。接上聊天窗、打开聊天窗、传登录的客户,都在前端代码里做。传客户时用的 id,和上面说的一样,得是别人猜不到的值。