在 React 項(xiàng)目中優(yōu)雅實(shí)現(xiàn)新用戶引導(dǎo)HagiCode 的 driver.js 實(shí)踐指南
在 React 項(xiàng)目中優(yōu)雅實(shí)現(xiàn)新用戶引導(dǎo):HagiCode 的 driver.js 實(shí)踐
當(dāng)用戶第一次打開你的產(chǎn)品時,他們真的知道該從哪里開始嗎?這篇文章聊聊我們在 HagiCode 項(xiàng)目里用 driver.js 做新用戶引導(dǎo)的那些事兒,也算是拋磚引玉罷了。
背景
你有沒有遇到過這樣的場景:新用戶注冊了你的產(chǎn)品,打開頁面后一臉茫然,東張西望,不知道該點(diǎn)哪里、該做什么。作為開發(fā)者,我們總以為用戶會"自己探索",畢竟人的好奇心是無限的嘛??涩F(xiàn)實(shí)是——大部分用戶會在幾分鐘內(nèi)因?yàn)檎也坏饺肟诙那碾x開,就像故事開始得突然,結(jié)束得也自然。
新用戶引導(dǎo)是解決這個問題的重要手段,只是實(shí)現(xiàn)起來也不那么簡單。一個好的引導(dǎo)系統(tǒng)需要:
- 能夠精準(zhǔn)定位頁面元素并高亮顯示
- 支持多步驟引導(dǎo)流程
- 能夠記住用戶的選擇(完成/跳過)
- 不影響頁面性能和正常交互
- 代碼結(jié)構(gòu)清晰,易于維護(hù)
在開發(fā) HagiCode 的過程中,我們也遇到了同樣的挑戰(zhàn)。HagiCode 是一個 AI 代碼助手項(xiàng)目,核心工作流是"用戶創(chuàng)建提案 → AI 生成計(jì)劃 → 用戶審核 → AI 執(zhí)行"這樣一套 OpenSpec 流程。對于第一次接觸這個概念的用戶來說,這套流程是全新的,必須有一個好的引導(dǎo)來幫助他們快速上手。畢竟,新事物總是需要一點(diǎn)時間的。
關(guān)于 HagiCode
本文分享的方案來自我們在 HagiCode 項(xiàng)目中的實(shí)踐經(jīng)驗(yàn)。HagiCode 是一個基于 Claude 的 AI 代碼助手,通過 OpenSpec 工作流幫助開發(fā)者更高效地完成代碼任務(wù)。你可以在 GitHub 上查看我們的開源代碼。
為什么選擇 driver.js
在技術(shù)選型階段,我們評估了幾個主流的引導(dǎo)庫,怎么說呢,每個都有自己的特點(diǎn):
- Intro.js:功能強(qiáng)大但體積較大,樣式定制相對復(fù)雜
- Shepherd.js:API 設(shè)計(jì)很好,但對于我們的場景來說有點(diǎn)"重"
- driver.js:輕量、簡潔、API 直觀,且支持 React 生態(tài)
最終我們選擇了 driver.js,其實(shí)也沒什么特別的理由,主要基于以下幾點(diǎn)考慮:
- 輕量級:核心庫體積小,不會顯著增加打包體積
- API 簡潔:配置項(xiàng)清晰直觀,上手快
- 靈活性:支持自定義定位、樣式和交互行為
- 動態(tài)導(dǎo)入:可以按需加載,不影響首屏性能
選型這件事,其實(shí)沒有最好的,只有最合適的罷了。
技術(shù)實(shí)現(xiàn)
核心配置
driver.js 的配置非常直觀,以下是 HagiCode 項(xiàng)目中的核心配置:
import { driver } from 'driver.js';
import 'driver.js/dist/driver.css';
const newConversationDriver = driver({
allowClose: true, // 允許用戶關(guān)閉引導(dǎo)
animate: true, // 啟用動畫效果
overlayClickBehavior: 'close', // 點(diǎn)擊遮罩層關(guān)閉引導(dǎo)
disableActiveInteraction: false, // 保持元素可交互
showProgress: false, // 不顯示進(jìn)度條(我們有自定義進(jìn)度管理)
steps: guideSteps // 引導(dǎo)步驟數(shù)組
});這些配置背后的考慮是:
allowClose: true- 尊重用戶選擇,不強(qiáng)制完成引導(dǎo),畢竟強(qiáng)扭的瓜不甜disableActiveInteraction: false- 某些步驟需要用戶實(shí)際操作(如輸入文字),所以不能禁用交互overlayClickBehavior: 'close'- 給用戶一個快速的退出方式
狀態(tài)管理
引導(dǎo)狀態(tài)的持久化是關(guān)鍵——我們不希望每次刷新頁面都重新引導(dǎo),那樣挺煩人的。HagiCode 使用 localStorage 來管理引導(dǎo)狀態(tài):
export type GuideState = 'pending' | 'dismissed' | 'completed';
export interface UserGuideState {
session: GuideState;
detailGuides: Record<string, GuideState>;
}
// 讀取狀態(tài)
export const getUserGuideState = (): UserGuideState => {
const state = localStorage.getItem('userGuideState');
return state ? JSON.parse(state) : { session: 'pending', detailGuides: {} };
};
// 更新狀態(tài)
export const setUserGuideState = (state: UserGuideState) => {
localStorage.setItem('userGuideState', JSON.stringify(state));
};我們定義了三種狀態(tài):
pending:引導(dǎo)進(jìn)行中,用戶還未完成或跳過dismissed:用戶主動關(guān)閉了引導(dǎo)completed:用戶完成了所有步驟
對于提案詳情頁的引導(dǎo),我們還支持更細(xì)粒度的狀態(tài)追蹤(通過 detailGuides 字典),因?yàn)橐粋€提案可能會經(jīng)歷多個階段(草稿、審核、執(zhí)行完成),每個階段都需要不同的引導(dǎo)。畢竟,事情的狀態(tài)總是在變化的。
目標(biāo)元素定位
driver.js 使用 CSS 選擇器來定位目標(biāo)元素。HagiCode 采用了一個約定:使用 data-guide 自定義屬性來標(biāo)記引導(dǎo)目標(biāo):
const steps = [
{
element: '[data-guide="launch"]',
popover: {
title: '開始新對話',
description: '點(diǎn)擊這里創(chuàng)建一個新的對話會話...'
}
}
];在組件中這樣使用:
<button data-guide="launch" onClick={handleLaunch}>
新建對話
</button>這種做法的好處是:
- 避免與業(yè)務(wù)樣式類名沖突
- 語義清晰,一眼就能看出這個元素與引導(dǎo)相關(guān)
- 便于統(tǒng)一管理和維護(hù)
動態(tài)導(dǎo)入優(yōu)化
因?yàn)橐龑?dǎo)功能只在特定場景下才需要(比如新用戶第一次訪問),我們采用動態(tài)導(dǎo)入來優(yōu)化初始加載性能:
const initNewUserGuide = async () => {
// 動態(tài)導(dǎo)入 driver.js
const { driver } = await import('driver.js');
await import('driver.js/dist/driver.css');
// 初始化引導(dǎo)
const newConversationDriver = driver({
// ...配置
});
newConversationDriver.drive();
};這樣 driver.js 及其樣式文件只會在需要時才加載,不會影響首屏性能。畢竟,誰愿意為暫時用不到的東西付出等待的代價呢?
引導(dǎo)流程設(shè)計(jì)
HagiCode 實(shí)現(xiàn)了兩條引導(dǎo)路徑,覆蓋了用戶的核心使用場景。
會話引導(dǎo)(10步)
這條引導(dǎo)幫助用戶完成從創(chuàng)建對話到提交第一個完整提案的整個流程:
- launch - 啟動引導(dǎo),介紹"新建對話"按鈕
- compose - 引導(dǎo)用戶在輸入框中輸入請求
- send - 引導(dǎo)點(diǎn)擊發(fā)送按鈕
- proposal-launch-readme - 引導(dǎo)創(chuàng)建 README 提案
- proposal-compose-readme - 引導(dǎo)編輯 README 請求內(nèi)容
- proposal-submit-readme - 引導(dǎo)提交 README 提案
- proposal-launch-agents - 引導(dǎo)創(chuàng)建 AGENTS.md 提案
- proposal-compose-agents - 引導(dǎo)編輯 AGENTS.md 請求
- proposal-submit-agents - 引導(dǎo)提交 AGENTS.md 提案
- proposal-wait - 說明 AI 正在處理,請稍候
這條引導(dǎo)的設(shè)計(jì)思路是:通過兩個實(shí)際的提案創(chuàng)建任務(wù)(README 和 AGENTS.md),讓用戶親手體驗(yàn) HagiCode 的核心工作流。畢竟,紙上得來終覺淺,絕知此事要躬行。
下面這幾張圖,對應(yīng)的就是會話引導(dǎo)里的幾個關(guān)鍵節(jié)點(diǎn):

會話引導(dǎo)的第一步,先把用戶帶到“新建普通會話”的入口上。

接著引導(dǎo)用戶在輸入框里寫下第一句請求,降低第一次開口的門檻。

輸入完成后,再明確提示用戶發(fā)送第一條消息,讓操作路徑更連貫。

當(dāng)兩個提案都創(chuàng)建完成后,引導(dǎo)會回到會話列表,讓用戶知道接下來只需要等待系統(tǒng)繼續(xù)執(zhí)行和刷新。
提案詳情引導(dǎo)(3步)
當(dāng)用戶進(jìn)入提案詳情頁時,根據(jù)提案的當(dāng)前狀態(tài)觸發(fā)對應(yīng)的引導(dǎo):
- drafting(草稿階段)- 引導(dǎo)用戶查看 AI 生成的計(jì)劃
- reviewing(審核階段)- 引導(dǎo)用戶執(zhí)行計(jì)劃
- executionCompleted(完成階段)- 引導(dǎo)用戶歸檔計(jì)劃
這條引導(dǎo)的特點(diǎn)是狀態(tài)驅(qū)動——根據(jù)提案的實(shí)際狀態(tài)動態(tài)決定顯示哪個引導(dǎo)步驟。事物總是在變化,引導(dǎo)也應(yīng)該跟著變化才是。
下面這張圖展示的是提案詳情頁在“起草階段”的引導(dǎo)狀態(tài):

在這個階段,引導(dǎo)會把用戶注意力聚焦到“生成規(guī)劃”這個關(guān)鍵動作上,避免第一次進(jìn)入詳情頁時不知道該先做什么。
元素渲染重試機(jī)制
在 React 應(yīng)用中,引導(dǎo)目標(biāo)元素可能還沒渲染完成(比如等待異步數(shù)據(jù)加載)。為了處理這種情況,HagiCode 實(shí)現(xiàn)了一個重試機(jī)制:
const waitForElement = (selector: string, maxRetries = 10, interval = 100) => {
let retries = 0;
return new Promise<HTMLElement>((resolve, reject) => {
const checkElement = () => {
const element = document.querySelector(selector) as HTMLElement;
if (element) {
resolve(element);
} else if (retries < maxRetries) {
retries++;
setTimeout(checkElement, interval);
} else {
reject(new Error(`Element not found: ${selector}`));
}
};
checkElement();
});
};
在初始化引導(dǎo)前調(diào)用這個函數(shù),確保目標(biāo)元素已經(jīng)存在。有時候,多等待一下也是值得的。
最佳實(shí)踐總結(jié)
基于 HagiCode 的實(shí)踐經(jīng)驗(yàn),這里分享幾個關(guān)鍵的最佳實(shí)踐:
1. 引導(dǎo)應(yīng)該是"可逃離的"
不要強(qiáng)制用戶完成引導(dǎo)。有些用戶是探索型的,他們更喜歡自己摸索。提供清晰的"跳過"按鈕,并記住用戶的選擇,下次不再打擾。畢竟,美的事物或人,不一定要占有,只要她還是美的,自己好好看著她的美就好了。
2. 引導(dǎo)內(nèi)容要簡潔有力
每個引導(dǎo)步驟應(yīng)該聚焦于單一目標(biāo):
- Title:簡短清晰,不超過 10 個字
- Description:直擊要點(diǎn),告訴用戶"這是啥"和"為啥要用"
避免長篇大論的說明——用戶在引導(dǎo)階段的注意力是很有限的。話說多了,反而沒人愿意看。
3. 選擇器要穩(wěn)定
使用穩(wěn)定的、不頻繁變化的元素標(biāo)記方式。data-guide 自定義屬性是一個好選擇,避免依賴 class 名或 DOM 結(jié)構(gòu),因?yàn)檫@些很容易在重構(gòu)中變化。代碼總是在變化的,但有些東西應(yīng)該盡量保持穩(wěn)定。
4. 測試你的引導(dǎo)
HagiCode 為引導(dǎo)功能編寫了完整的測試用例:
describe('NewUserConversationGuide', () => {
it('應(yīng)該正確初始化引導(dǎo)狀態(tài)', () => {
const state = getUserGuideState();
expect(state.session).toBe('pending');
});
it('應(yīng)該正確更新引導(dǎo)狀態(tài)', () => {
setUserGuideState({ session: 'completed', detailGuides: {} });
const state = getUserGuideState();
expect(state.session).toBe('completed');
});
});測試可以確保在重構(gòu)代碼時不會不小心破壞引導(dǎo)功能。畢竟,誰也不希望改點(diǎn)代碼就把之前的功能搞壞了。
5. 性能優(yōu)化
- 使用動態(tài)導(dǎo)入延遲加載引導(dǎo)庫
- 避免在用戶已經(jīng)完成引導(dǎo)后仍然初始化引導(dǎo)邏輯
- 考慮引導(dǎo)動畫的性能影響,低端設(shè)備上可以關(guān)閉動畫
性能這東西,就像生活一樣,該省的地方還是要省的。
總結(jié)
新用戶引導(dǎo)是提升產(chǎn)品用戶體驗(yàn)的重要環(huán)節(jié)。在 HagiCode 項(xiàng)目中,我們使用 driver.js 構(gòu)建了一套完整的引導(dǎo)系統(tǒng),覆蓋了從會話創(chuàng)建到提案執(zhí)行的整個工作流。
通過本文的分享,我們希望傳達(dá)的核心觀點(diǎn)是:
- 技術(shù)選型要匹配需求:driver.js 不是最強(qiáng)的,但對我們來說是最合適的
- 狀態(tài)管理很關(guān)鍵:用 localStorage 持久化引導(dǎo)狀態(tài),避免重復(fù)打擾用戶
- 引導(dǎo)設(shè)計(jì)要聚焦:每個步驟解決一個問題,不要貪多
- 代碼結(jié)構(gòu)要清晰:分離引導(dǎo)配置、狀態(tài)管理和 UI 邏輯,便于維護(hù)
如果你正在為自己的項(xiàng)目添加新用戶引導(dǎo)功能,希望本文的實(shí)踐經(jīng)驗(yàn)?zāi)軐δ阌兴鶐椭?。其?shí)技術(shù)這東西,也沒什么神秘的,多嘗試,多總結(jié),慢慢就好了......
參考資料
原文與版權(quán)說明
感謝您的閱讀,如果您覺得本文有用,歡迎點(diǎn)贊、收藏和分享支持。
本內(nèi)容采用人工智能輔助協(xié)作,最終內(nèi)容由作者審核并確認(rèn)。
- 本文作者: newbe36524
- 原文鏈接: https://docs.hagicode.com/go?platform=cnblogs&target=%2Fblog%2F2026-04-01-new-user-guide-with-driverjs%2F
- 版權(quán)聲明: 本博客所有文章除特別聲明外,均采用 BY-NC-SA 許可協(xié)議。轉(zhuǎn)載請注明出處!
到此這篇關(guān)于在 React 項(xiàng)目中優(yōu)雅實(shí)現(xiàn)新用戶引導(dǎo)HagiCode 的 driver.js 實(shí)踐指南的文章就介紹到這了,更多相關(guān)React HagiCode 的 driver.js內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React+hook實(shí)現(xiàn)聯(lián)動模糊搜索
這篇文章主要為大家詳細(xì)介紹了如何利用React+hook+antd實(shí)現(xiàn)聯(lián)動模糊搜索功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-02-02
React Router 5.1.0使用useHistory做頁面跳轉(zhuǎn)導(dǎo)航的實(shí)現(xiàn)
本文主要介紹了React Router 5.1.0使用useHistory做頁面跳轉(zhuǎn)導(dǎo)航的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11
React+Vite中利用Fetch將CSV數(shù)據(jù)轉(zhuǎn)成JSON字符串
在一些小型項(xiàng)目中,前端可能需要直接處理 CSV 文件數(shù)據(jù),將其轉(zhuǎn)換為 JSON 字符串后再進(jìn)行邏輯操作和展示,本文將會介紹兩種方法,需要的朋友可以參考下2025-12-12
react.js使用webpack搭配環(huán)境的入門教程
本文主要介紹了react 使用webpack搭配環(huán)境的入門教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-08-08
react用Redux中央倉庫實(shí)現(xiàn)一個todolist
這篇文章主要為大家詳細(xì)介紹了react用Redux中央倉庫實(shí)現(xiàn)一個todolist,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-09-09

