Signatur
Beschreibung
Das end-Ereignis meldet, dass eine WebXR-Sitzung (immersive-vr, immersive-ar oder inline) beendet ist. Es wird in zwei Fällen ausgelöst: wenn die Anwendung selbst XRSession.end() aufruft oder wenn der User Agent die Sitzung beendet. Das passiert zum Beispiel, wenn jemand das Headset abnimmt, mit der Systemtaste das immersive Erlebnis verlässt, die Seite wechselt oder das Gerät getrennt wird.
Das Ereignis ist vom Typ XRSessionEvent. Seine Eigenschaft session verweist auf die beendete Sitzung. Es bricht nicht ab (nicht cancelable) und steigt nicht auf (bubbelt nicht). Den Handler registrieren Sie mit addEventListener("end", …) oder über die Eigenschaft onend.
Nutzen Sie das Ereignis als zentrale Stelle zum Aufräumen: Referenzen auf die Sitzung und auf XRReferenceSpace-Objekte freigeben, eigene Zustände zurücksetzen, die Oberfläche anpassen (z. B. den Button „VR starten“ wieder anzeigen) und bei Bedarf die normale Render-Schleife mit window.requestAnimationFrame() fortsetzen. Weil die Sitzung auch ohne Zutun der Anwendung enden kann, reicht Aufräum-Code direkt nach end() nicht aus.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname, hier immer "end". |
|
| $handler Pflicht | (event: XRSessionEvent) => void | Callback, das ein XRSessionEvent erhält. event.session ist die beendete XRSession. |
|
| $options | boolean | AddEventListenerOptions | false | Optionale Listener-Optionen, z. B. { once: true }. Das ist hier sinnvoll, weil jede Sitzung nur einmal endet. |
Rückgabewert
addEventListener gibt nichts zurück. Der Handler erhält ein XRSessionEvent mit der Eigenschaft session.Beispiele
Sitzung starten und beim Ende aufräumen (addEventListener)
const button = document.querySelector('#enter-vr');
let xrSession = null;
const onSessionEnded = (event) => {
console.log('XR-Sitzung beendet:', event.session === xrSession);
xrSession = null;
button.textContent = 'VR starten';
};
button.addEventListener('click', async () => {
if (xrSession) {
await xrSession.end(); // löst später das end-Ereignis aus
return;
}
if (!navigator.xr || !(await navigator.xr.isSessionSupported('immersive-vr'))) {
console.warn('immersive-vr wird nicht unterstützt');
return;
}
xrSession = await navigator.xr.requestSession('immersive-vr');
xrSession.addEventListener('end', onSessionEnded, { once: true });
button.textContent = 'VR beenden';
});
onend-Eigenschaft und Rückkehr zur normalen Render-Schleife
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl2', { xrCompatible: true });
const drawScene = () => {
gl.clearColor(0.1, 0.1, 0.1, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
};
const windowLoop = () => {
drawScene();
windowFrameId = requestAnimationFrame(windowLoop);
};
let windowFrameId = requestAnimationFrame(windowLoop);
const startXR = async () => {
const session = await navigator.xr.requestSession('immersive-vr');
cancelAnimationFrame(windowFrameId); // Fenster-Loop pausieren
await session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
const refSpace = await session.requestReferenceSpace('local');
const xrLoop = (time, frame) => {
const pose = frame.getViewerPose(refSpace);
if (pose) drawScene();
session.requestAnimationFrame(xrLoop);
};
session.requestAnimationFrame(xrLoop);
session.onend = () => {
console.log('Zurück zur 2D-Ansicht');
windowFrameId = requestAnimationFrame(windowLoop);
};
};
document.querySelector('#start').addEventListener('click', startXR);
Listener gezielt wieder entfernen
const handleEnd = () => console.log('Sitzung vorbei');
const session = await navigator.xr.requestSession('inline');
session.addEventListener('end', handleEnd);
// Später, z. B. wenn eine andere Komponente die Verwaltung übernimmt:
session.removeEventListener('end', handleEnd);
await session.end(); // Promise erfüllt sich, handleEnd wird NICHT mehr aufgerufen
console.log('end() abgeschlossen');
// Wichtig · Fallstricke
- Nicht nur auf
end()verlassen: Der User Agent kann die Sitzung jederzeit beenden, etwa über die Systemtaste, durch Abnehmen des Headsets oder durch einen Seitenwechsel. Aufräumen gehört daher immer in denend-Handler. - Nach dem Ereignis ist die Sitzung endgültig beendet. Sie lässt sich nicht fortsetzen, und
session.requestAnimationFrame()-Callbacks laufen nicht mehr. Für eine neue Sitzung rufen Sie erneutnavigator.xr.requestSession()auf, wofür bei immersiven Sitzungen wieder eine Nutzeraktion nötig ist. - Das Promise von
XRSession.end()wird erfüllt, nachdem die Sitzung heruntergefahren ist. Verlassen Sie sich nicht auf eine bestimmte Reihenfolge zwischen der Promise-Auflösung und Ihrem Handler. Legen Sie die Aufräumlogik in den Handler. - Wird die Seite gerade entladen, ist nicht sicher, dass Ihr Handler noch vollständig ausgeführt wird. Verwenden Sie dort keine asynchrone Arbeit wie
fetch, die zuverlässig abschließen muss. Nutzen Sie dafür z. B.navigator.sendBeacon(). - Kompatibilität: WebXR steht nur in sicheren Kontexten (HTTPS) zur Verfügung und wird hauptsächlich von Chromium-Browsern und XR-Headset-Browsern unterstützt. Firefox und Desktop-Safari bieten es nicht an. Prüfen Sie deshalb vorher
navigator.xrundisSessionSupported(). In iframes ist die Permissions-Policyxr-spatial-trackingnötig.