RemoteCursor 远端光标
把远端用户的光标 + 名字标签叠加到当前界面。位置接 WebSocket / WebRTC,颜色按 user id 哈希。
English translation pending This page hasn't been translated yet — falling back to Chinese. PRs welcome on GitHub.
基础用法
cursors 数组每项 { id, x, y, name?, color? },坐标是相对于父容器(positioning='absolute',默认)或视口('fixed')的像素值。CSS 用 transition 平滑插值,业务端只需以 60 Hz 推送数据。
背景 视口
这是协作编辑器 / 白板 / 看板的工作区,其他用户的光标会浮在表面。
把 cursors 数据接到 WebSocket / WebRTC 就能联动。
Alice
Bo
Chen
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { CfRemoteCursor, type RemoteCursorItem } from '@chufix-design/vue';
interface CursorBase {
id: string;
name: string;
baseX: number;
baseY: number;
phase: number;
}
const base: CursorBase[] = [
{ id: 'alice', name: 'Alice', baseX: 80, baseY: 60, phase: 0 },
{ id: 'bo', name: 'Bo', baseX: 220, baseY: 120, phase: 1.7 },
{ id: 'chen', name: 'Chen', baseX: 380, baseY: 90, phase: 3.1 },
];
const cursors = ref<RemoteCursorItem[]>(
base.map(({ id, name, baseX, baseY }) => ({ id, name, x: baseX, y: baseY })),
);
let raf: number | null = null;
const start = performance.now();
onMounted(() => {
function tick(t: number) {
const dt = (t - start) / 1000;
cursors.value = base.map(({ id, name, baseX, baseY, phase }) => ({
id,
name,
x: baseX + Math.sin(dt * 0.9 + phase) * 36,
y: baseY + Math.cos(dt * 0.7 + phase) * 24,
}));
raf = requestAnimationFrame(tick);
}
raf = requestAnimationFrame(tick);
});
onBeforeUnmount(() => {
if (raf != null) cancelAnimationFrame(raf);
});
</script>
<template>
<div class="rc-demo">
<div class="rc-demo__surface">
<p>这是协作编辑器 / 白板 / 看板的工作区,其他用户的光标会浮在表面。</p>
<p>把 cursors 数据接到 WebSocket / WebRTC 就能联动。</p>
<CfRemoteCursor :cursors="cursors" positioning="absolute" />
</div>
</div>
</template>
<style scoped>
.rc-demo {
width: 100%;
}
.rc-demo__surface {
position: relative;
min-height: 240px;
padding: 16px;
background: var(--bg-1);
border: 1px solid var(--line-1);
border-radius: var(--r-3);
color: var(--fg-2);
font-size: var(--t-13);
overflow: hidden;
}
.rc-demo__surface p {
margin: 0 0 8px;
}
</style> <script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { CfRemoteCursor } from '@chufix-design/vue';
const base= [
{ id: 'alice', name: 'Alice', baseX: 80, baseY: 60, phase: 0 },
{ id: 'bo', name: 'Bo', baseX: 220, baseY: 120, phase: 1.7 },
{ id: 'chen', name: 'Chen', baseX: 380, baseY: 90, phase: 3.1 },
];
const cursors = ref<RemoteCursorItem[]>(
base.map(({ id, name, baseX, baseY }) => ({ id, name, x, y: baseY })),
);
let raf= null;
const start = performance.now();
onMounted(() => {
function tick(t) {
const dt = (t - start) / 1000;
cursors.value = base.map(({ id, name, baseX, baseY, phase }) => ({
id,
name,
x: baseX + Math.sin(dt * 0.9 + phase) * 36,
y: baseY + Math.cos(dt * 0.7 + phase) * 24,
}));
raf = requestAnimationFrame(tick);
}
raf = requestAnimationFrame(tick);
});
onBeforeUnmount(() => {
if (raf != null) cancelAnimationFrame(raf);
});
</script>
<template>
<div class="rc-demo">
<div class="rc-demo__surface">
<p>这是协作编辑器 / 白板 / 看板的工作区,其他用户的光标会浮在表面。</p>
<p>把 cursors 数据接到 WebSocket / WebRTC 就能联动。</p>
<CfRemoteCursor :cursors="cursors" positioning="absolute" />
</div>
</div>
</template>
<style scoped>
.rc-demo {
width: 100%;
}
.rc-demo__surface {
position: relative;
min-height: 240px;
padding: 16px;
background: var(--bg-1);
border: 1px solid var(--line-1);
border-radius: var(--r-3);
color: var(--fg-2);
font-size: var(--t-13);
overflow: hidden;
}
.rc-demo__surface p {
margin: 0 0 8px;
}
</style> import { CfRemoteCursor } from '@chufix-design/react';
export default function Demo() {
const cursors = base.map(({ id, name, baseX, baseY }) => ({ id, name, x: baseX, y: baseY })),;
return (
<>
<CfRemoteCursor
cursors={[
{ id: 'alice', name: 'Alice', x: 80, y: 60 },
{ id: 'bo', name: 'Bo', x: 220, y: 120 },
]}
/>
</>
);
} import { CfRemoteCursor } from '@chufix-design/react';
export default function Demo() {
const cursors = base.map(({ id, name, baseX, baseY }) => ({ id, name, x, y: baseY })),;
return (
<>
<CfRemoteCursor
cursors={[
{ id: 'alice', name: 'Alice', x: 80, y: 60 },
{ id: 'bo', name: 'Bo', x: 220, y: 120 },
]}
/>
</>
);
} API
| 属性 | 类型 | 默认 | 说明 |
|---|---|---|---|
cursors | RemoteCursorItem[] | — | |
positioning | 'absolute' | 'fixed' | 'absolute' | 容器内 / 视口内 |
反馈与讨论
RemoteCursor 远端光标 · Discussion