接入开发
接入方式
script 标签、npm 包、React Hook、Vue 3 composable 四种接入写法,以及生命周期与状态处理。
最后更新
四种方式用的是同一套公开 SDK,覆盖同样的流程: 连接 → 授权 → 选打印机 → 上传内容 → 打印或预览 → 离开时断开。
获取 SDK
PrintLink 自己分发浏览器版,页面里加一行即可(全局 PrintLink):
<script src="http://127.0.0.1:17888/sdk/printlink.js"></script>原生 script
<script src="http://127.0.0.1:17888/sdk/printlink.js"></script>
<script type="module">
const client = new PrintLink.PrintLinkClient({ appName: '我的网页应用' });
try {
await client.connect(); // 连接本机 PrintLink
await client.ensureAuthorized(); // 首次触发配对,等用户在电脑上确认
const { queues } = await client.listPrinters();
const queueId = (queues.find((q) => q.isSystemDefault) ?? queues[0]).queueId;
const job = await client.compose({ queueId }).addPdf(file).printAndWait();
console.log('终态:', job.status);
} catch (err) {
if (err.code === 'PAIRING_PENDING') {
// 不是故障:等用户在电脑上点同意后,重试 ensureAuthorized()
} else {
console.warn(err.code, err.message, 'retryable =', err.retryable);
}
} finally {
client.close(); // 离开页面务必断开
}
</script>React
import { useEffect, useRef, useState } from 'react';
import { PrintLinkClient } from '@printlink/sdk';
import type { PrinterQueueInfo } from '@printlink/types';
type State =
| { status: 'connecting' }
| { status: 'ready'; queues: PrinterQueueInfo[] }
| { status: 'pending' } // 等用户在电脑上确认授权
| { status: 'error'; code: string };
export function usePrintLink() {
const clientRef = useRef<PrintLinkClient | null>(null);
const [state, setState] = useState<State>({ status: 'connecting' });
useEffect(() => {
const client = new PrintLinkClient({ appName: 'My React App' });
clientRef.current = client;
let disposed = false;
void (async () => {
try {
await client.connect();
await client.ensureAuthorized();
const { queues } = await client.listPrinters();
if (!disposed) setState({ status: 'ready', queues });
} catch (err) {
const code = (err as { code?: string }).code ?? 'INTERNAL';
if (!disposed) {
setState(code === 'PAIRING_PENDING' ? { status: 'pending' } : { status: 'error', code });
}
}
})();
return () => {
disposed = true;
client.close(); // 组件卸载一定断连
};
}, []);
return { client: clientRef, state };
}打印动作放在事件回调里:
async function onPrint(client: PrintLinkClient, queueId: string, doc: PrintDocument) {
const job = await client.compose({ queueId }).addDocument(doc).printAndWait();
return job.status; // 'completed' | 'failed' | 'canceled'
}Vue 3
import { onMounted, onUnmounted, ref } from 'vue';
import { PrintLinkClient } from '@printlink/sdk';
import type { PrinterQueueInfo } from '@printlink/types';
export function usePrintLink() {
const status = ref<'connecting' | 'ready' | 'pending' | 'error'>('connecting');
const queues = ref<PrinterQueueInfo[]>([]);
let client: PrintLinkClient | null = null;
onMounted(async () => {
client = new PrintLinkClient({ appName: 'My Vue App' });
try {
await client.connect();
await client.ensureAuthorized();
queues.value = (await client.listPrinters()).queues;
status.value = 'ready';
} catch (err) {
status.value = (err as { code?: string }).code === 'PAIRING_PENDING' ? 'pending' : 'error';
}
});
onUnmounted(() => client?.close());
return { status, queues, client: () => client };
}客户端参数
const client = new PrintLinkClient({
appName: '我的业务系统', // 显示在配对确认与站点列表里
channel: 'erp', // 可选:区分同一台机器上的不同业务程序
endpoint: 'ws://127.0.0.1:17888/ws', // 可选,默认即此
requestTimeoutMs: 30_000, // 可选,单次请求超时
});channel 是给你自己看的标签,用来在任务列表和报表里区分「哪个程序打的」
(比如 erp / wms / cashier)。只能是小写字母开头、由小写字母/数字/_/-
组成、不超过 64 字符。它不参与权限判断,非法值会直接报错而不是被忽略。
必须处理的四件事
- 没安装或没启动:先用
PrintLink.detect()探测,installed === false时 引导安装,而不是直接connect()然后报错。 - 等待授权:
PAIRING_PENDING是正常的中间状态,提示用户去电脑上点同意, 然后重试ensureAuthorized()。 - 离开时断开:
close()释放连接与订阅。单页应用切路由、组件卸载都要调用。 - 按 code 处理错误:所有失败都是
code+message+retryable的结构化错误, 请按code分支,不要解析message文本。
端口被改过怎么办
用户在控制台改了端口后,已连接的页面会收到 system.serviceMigrated 事件。
收到后应停止发起新请求,并引导用户用新地址重新进入,不要在旧地址上默默重试:
client.onServiceMigrated((event) => {
showReconnectPrompt(event.endpoint);
});