非同期読み込みと複数のチャットルーム

uchat.jsが読み込まれる前にイベントを登録する方法、1ページの複数のチャットルームにイベントを分けて登録する方法、SPAでチャットルームを設置・後片付けする方法、右下のフローティングウィジェットを設置する方法を説明します。

最終更新 2026年10月20日

このページ

uchat.js は async で読み込むため、ページスクリプトとの実行順序は決まっていません。このページでは、読み込み順序に関係なくイベントを登録する方法、複数のチャットルームを扱う方法、SPAでチャットルームを付け外しする方法を扱います。

事前登録コード

次のコードを**uchat.js より前に**入れます。uchat.js の準備ができる前に登録したイベントを U.events に保管しておき、準備ができたらそのまま使います。

<script>U=window.U=window.U||{},U.events=U.events||[],U.chat=function(n){return{on:function(e,t){U.events.push([n,e,t])},off:function(e){for(var t=U.events.length;t>0;)U.events[--t][0]==n&&U.events[t][1]==e&&U.events.splice(t,1)}}};</script>
<script async src="https://client.uchat.io/uchat.js"></script>

uchat.js の準備ができると、U.chat は本物の関数に置き換わります。前と後の違いは1つです。

準備前(事前登録コード) 準備後
on(name, callback) 保管 登録(すでに準備できたルームの after.create はすぐに呼び出し)
off(name) 名前が文字どおり同じものだけを削除 ラベル・イベント名で選んで削除(下記参照)

準備前に off('#label') のようにラベルだけを渡すと、何も削除されません。いつ呼ばれるかわからない後片付けのコードでは、on で使った名前全体('after.message#alarm')をそのまま off に渡してください。この方法は準備前と準備後のどちらでも動作します。

チャットルームを選ぶ

U.chat('*').on('after.join', handler);      // ページのすべてのチャットルーム
U.chat('room-a').on('after.join', handler); // room-aだけ
U.chat('room-b').on('after.join', handler); // room-bだけ
  • U.chat('room-id') はそのチャットルームだけに、U.chat('*') はページのすべてのチャットルーム(あとから追加されるチャットルームを含む)に登録します。
  • 複数のIDを一度に渡すことはできません。それぞれ登録するか、'*' で登録してコールバック内で room.id によって分岐してください。
  • チャットルームがすでに開いていれば、U.chat('room-id') はそのチャットルームの room オブジェクトを返します。まだなければ on・off だけを持つ登録用オブジェクトを返します。どちらの場合も on・off の使い方は同じです。→ U.chat() と room オブジェクト

ラベルと解除

イベント名の後ろに #label を付けると、あとでラベルで選んで解除できます。

U.chat('*').on('after.message#alarm', onMessage);
U.chat('*').on('after.user.join#alarm', onJoin);

U.chat('*').off('#alarm');              // ラベルがalarmのものすべて
U.chat('*').off('after.message');       // after.messageすべて(ラベルに関係なく)
U.chat('*').off('after.message#alarm'); // 両方に一致するものだけ

U.chat('*').off(...) は、'*' で登録したものだけでなく、チャットルームごとに登録したものまですべて削除します。ほかのスクリプト(プラグイン、ほかのウィジェット)が登録したイベントまで削除しないよう、自分のコードのイベントには重ならないラベル(#my-widget など)を付け、ラベルで解除してください。

after.createと準備のタイミング

after.create はチャットルームの画面(スキン)の準備ができたときに発生します。入室より先に来るので、スキンUI APIとチャンネルの登録はこの中で行います。

すでに準備ができたチャットルームに after.create を登録すると、待たずにすぐ1回呼び出されます。そのため、スクリプトの実行が遅れても取りこぼしません。

U.chat('*').on('after.create#my-widget', function (room) {
	if (room.id !== 'my-room') return;
	// room.skin, room.pluginを使用
});

タグの追加・削除と属性の変更

uchat.js はページの <u-chat> タグを監視しています。

  • <u-chat> をページに入れるとチャットルームが開き、削除するとチャットルームが閉じます。
  • チャットルームが閉じると、そのチャットルームIDで登録したイベントも一緒に削除されます。'*' で登録したイベントは残ります。タグを入れ直したときにもイベントが必要なら、もう一度登録するか '*' で登録してください。
  • 同じ room IDのタグはページに1つだけ開きます。2つ目のタグは無視され、最初のタグを削除しても2つ目のタグが代わりに開くことはありません。
  • room、user_data などの**属性の変更は検知しません。**値を変えるには、タグを削除して新しい属性で入れ直してください。
function replaceRoom(container, roomId) {
	container.replaceChildren(); // 既存の<u-chat>を削除 → チャットルームが閉じる
	var tag = document.createElement('u-chat');
	tag.setAttribute('room', roomId);
	tag.style.cssText = 'display:block; width:100%; height:500px;';
	container.appendChild(tag); // 新しいチャットルームが開く
}

SPAで使う

SPAでは、画面にチャットルームが入るときに uchat.js を一度だけ読み込み、画面を離れるときに自分が登録したイベントを後片付けします。<u-chat> タグはフレームワークが削除すると、チャットルームも一緒に閉じます。

次の uchat() 関数は事前登録コードと同じ働きをするので、uchat.js より先に実行されても問題ありません。

// uchat.js — フレームワークに関係なく使えるヘルパー
export function uchat(roomId) {
	const U = (window.U = window.U || {});
	U.events = U.events || [];
	if (!U.chat) {
		U.chat = (n) => ({
			on: (e, t) => U.events.push([n, e, t]),
			off: (e) => {
				for (let t = U.events.length; t > 0; )
					U.events[--t][0] == n && U.events[t][1] == e && U.events.splice(t, 1);
			}
		});
	}
	if (!document.querySelector('script[data-uchat]')) {
		const s = document.createElement('script');
		s.src = 'https://client.uchat.io/uchat.js';
		s.async = true;
		s.dataset.uchat = '';
		document.head.appendChild(s);
	}
	return U.chat(roomId);
}

React:

import { useEffect } from 'react';
import { uchat } from './uchat';

export default function ChatRoom({ roomId }) {
	useEffect(() => {
		const name = 'after.message#my-widget-' + roomId;
		uchat('*').on(name, (room, data) => {
			if (room.id !== roomId) return;
			console.log(data.user.nick, data.content);
		});
		return () => uchat('*').off(name);
	}, [roomId]);

	// keyを変えるとタグが新しく作られるので、別のチャットルームに切り替わる
	return <u-chat key={roomId} room={roomId} style={{ display: 'block', width: '100%', height: '500px' }} />;
}
  • イベントは '*' で登録し、room.id で分岐します。チャットルームIDで登録したイベントはタグが削除されるときに一緒に削除されるため、再マウント時に順序が乱れません。
  • 後片付けのときは、on で使った名前全体を off に渡します。uchat.js の準備がまだでも削除されます。
  • room 属性だけを変えてもチャットルームは切り替わらないので、key でタグを新しく作ります。

Vueでは onMounted で on、onUnmounted で off を呼び、u-chat をカスタム要素として登録します(5分で設置参照)。Svelteでは onMount で on を登録し、返す後片付け関数で off を呼びます。チャットルームを切り替えるときは、Vueは :key、Svelteは {#key roomId} ブロックでタグを新しく作ります。

フローティングウィジェット

チャットルームをページ右下のボタンとして設置するには、npm パッケージ @u-chat/embed のウィジェットを使います。閉じているときは新着メッセージをプレビューと未読数で知らせ、押すとチャット画面が開きます。管理ページの設置コード画面の フローティングウィジェット タブでもこのコードを作れ、下の属性と位置・サイズはその画面の ウィジェット設定 で選べます。

バンドラーを使わないサイト(HTML、グヌボード、WordPress など)は <script> 1行で読み込みます。uchat.js をすでに設置したページにそのまま追加できます。

<script src="https://cdn.jsdelivr.net/npm/@u-chat/embed@latest/dist/widget.global.js"></script>
<u-chat-widget launcher-text="現在 {user_count}人">
	<u-chat room="my-room"></u-chat>
</u-chat-widget>

jsDelivr の代わりにチャットサーバーから読み込むには https://client.uchat.io/widget.js を使います。独立サーバーはそのサーバーの widget.js を使い、ウィジェットが同じサーバーの uchat.js に接続するので src 属性は不要です。

React(npm install @u-chat/react):

import { UchatWidget } from '@u-chat/react';

export default function App() {
	return <UchatWidget room="my-room" launcherText="現在 {user_count}人" />;
}

Svelte 5(npm install @u-chat/svelte):

<script>
	import { UchatWidget } from '@u-chat/svelte';
</script>

<!-- 波かっこが Svelte の式として読まれないよう、文字列を {'...'} で渡します -->
<UchatWidget room="my-room" launcherText={'現在 {user_count}人'} />

Vue 3(npm install @u-chat/vue)。isCustomElement の設定は不要です。

<script setup>
import { UchatWidget } from '@u-chat/vue';
</script>

<template>
	<UchatWidget room="my-room" launcher-text="現在 {user_count}人" />
</template>

ウィジェットの属性(React・Svelteでは launcherText のようなキャメルケース):

属性 説明
launcher-text ボタンの文字。{user_count} は接続者数、{unread_count} は未読数に置き換わります
variant bubble(既定、丸いボタン)、bar(下端の長いバー。開くと下からせり上がります)または side(右端のサイドバー。最初から画面の高さいっぱいに開いてページ本文を左に押し、たたむと右端に縦のタブだけが残ります。768pxより狭い画面はたたんだ状態で始まり、開くと上に重なります)
launcher-color, launcher-image ボタンの背景色、背景画像のURL(画像が優先)
panel-title 開いた画面の上のタイトル
preview-duration 新着メッセージのプレビューを表示する時間(ms、既定 5000)
lang ウィジェットのボタン・案内文の言語(ko、en、ja)。なければ内側の <u-chat lang> → ページの <html lang> → ブラウザーの言語の順で、それ以外の言語は英語
src uchat.js のURL。独立サーバーはそのサーバーのURLを入れます
  • 会員連携のルームは、内側の <u-chat> に user_data を入れます(React・Svelte・Vue は userData)。設置コード画面で 設置の形 → フローティングウィジェット を選ぶと、署名入りのウィジェットコードが出ます。
  • ページを開くとすぐチャットルームに接続します。そのため閉じていてもプレビューと接続者数が表示されます。過去の会話(after.message の past)と自分のメッセージは未読数に入りません。
  • 画面の × で隠すと接続を切り、このチャットルームに限って隠した状態を覚えます。右下に小さなオンにするボタンが残ります。
  • スクリプトからは open()、close()、toggle()、maximize()、restore()、hide()、show()、destroy() を呼びます。React・Vue・Svelte ではコンポーネントに ref(Svelte は bind:this)を付けて同じ名前で呼びます。
  • uchat.js を読み込めないと、ウィジェットに uchat-widget-error イベントが届きます(event.detail がエラー)。

タグではなくスクリプトで作るときは createUchatWidget(入れる要素, 設定) を使います。1行のスクリプトで読み込んだ場合は window.UchatEmbed、npm の場合は @u-chat/embed/widget にあります。

const widget = UchatEmbed.createUchatWidget(document.body, {
	chat: { room: 'my-room', user_data: signedUserData },
	widget: { launcherText: '現在 {user_count}人', variant: 'bar' },
});
widget.addEventListener('uchat-widget-error', (event) => console.error(event.detail));
widget.open();

位置と大きさは CSS 変数で変えます。

u-chat-widget {
	--uchat-widget-right: 20px;
	--uchat-widget-bottom: 20px;
	--uchat-widget-panel-width: 380px;
	--uchat-widget-panel-height: 640px;
	--uchat-widget-side-width: 360px;
	--uchat-widget-accent: #ff7e25;
	--uchat-widget-z-index: 2147483000;
}

読んでもよくわからない場合は お問い合わせ掲示板に質問を書き込んでください。

商号 UCHAT · 代表者 김경욱 · 事業者登録番号 141-05-32832
所在地 경기도 파주시 와석순환로 61 · 通信販売業届出番号 2013-경기파주-4485호
代表電話 010-8677-8633 · メール support@uchat.io

ⓒ 2013–2026 UCHAT. All rights reserved.