ng-tour-guide
TypeScript icon, indicating that this package has built-in type declarations

1.0.5 • Public • Published

ng-tour-guide

一個基於 Angular 和 Ionic 的導覽指引元件,提供互動式的功能導覽體驗。

功能特點

  • 🎯 智能定位:自動計算並調整提示框位置
  • 🎨 完全可自定義的樣式
  • ⌨️ 支援鍵盤導航(方向鍵和 ESC)
  • ♿ 無障礙支援(ARIA 標籤)
  • 🔄 響應式設計:自動處理視窗大小變化
  • ✅ 進階驗證和條件控制
    • 即時驗證 (validate)
    • 步驟前檢查 (beforeNext)
    • 條件觸發 (triggerWhen)
  • 🔒 TypeScript 型別支援
  • 📱 支援 Ionic 框架
  • 🌐 支援 Angular 14-19 版本

安裝

npm install ng-tour-guide

基本使用

  1. 在你的模組中導入 TourComponent:
import { TourComponent } from "ng-tour-guide";

@NgModule({
  imports: [TourComponent], // 已經是 standalone component
})
export class YourModule {}
  1. 在組件中定義導覽步驟:
import { TourStep } from "ng-tour-guide";

export class YourComponent {
  isTourVisible = false;

  tourSteps: TourStep[] = [
    {
      target: '.title-button', // CSS 選擇器
      title: '開始按鈕',
      content: '點擊這裡開始使用系統',
      placement: 'bottom', // 提示框位置
      ariaLabel: '開始按鈕導覽', // 無障礙標籤
    },
    {
      target: '[data-tour="design-version"]',
      title: '版次清單',
      content: '這裡可以看到所有的版次',
      placement: 'right',
      validate: () => this.isMenuReady(), // 驗證函數
      beforeNext: async () => {
        // 下一步前的檢查
        return await this.checkMenuStatus();
      },
    }
  ];

  onTourFinish() {
    this.isTourVisible = false;
    console.log('導覽完成');
  }
}
  1. 在模板中使用:
<app-tour
  [steps]="tourSteps"
  [(visible)]="isTourVisible"
  (stepChange)="onStepChange($event)"
  (finishTour)="onTourFinish()"
>
</app-tour>


<ion-button class="title-button" [class.active-button]="num === 0" (click)="chTitle(0)">開始</ion-button>

<ion-button
    *ngIf="num === 0"
    class="title-button"
    (click)="titleChange(0)"
    data-tour="design-version"
    >設計版次</ion-button
>

API 詳解

TourStep 介面

interface TourStep {
  target: string;       // 目標元素的 CSS 選擇器
  title: string;        // 步驟標題
  content: string;      // 步驟內容
  placement?: "top" | "bottom" | "left" | "right"; // 提示框位置
  validate?: () => boolean; // 驗證函數
  beforeNext?: () => boolean | Promise<boolean>; // 下一步前的檢查
  triggerWhen?: () => boolean | Promise<boolean>; // 觸發條件
  ariaLabel?: string;   // 無障礙標籤
}

進階功能說明

✅ 1. validate 驗證函數

用於驗證當前步驟是否可以繼續。

📌 功能:

「這個步驟的 target 元素是否存在或顯示出來」的同步檢查。如果返回 false,下一步按鈕將被禁用。

🕒 何時執行?

在切換到這個步驟之前,會進行一次驗證,用來確認這個步驟的 DOM 目標是否「準備好」。

🔧 用途實例:

確保 .title-button:first-child 真的已經出現在 DOM 上

確保某個 tab 切換後才有的內容已經可見

example1
tourSteps: TourStep[] = [
  {
    target: "#form-submit",
    title: "表單提交",
    content: "填寫完表單後點擊提交",
    validate: () => {
      // 檢查表單是否已填寫
      return this.form.valid;
    }
  }
];
example2
validate: () => {
    const el = document.querySelector('.some-class');
    return el !== null && el.offsetParent !== null; // 避免導覽找不到目標
}

✅ 2. beforeNext 下一步檢查

📌 功能:

「當使用者點擊【下一步】前」,是否允許進入下一步(可加強互動,通常會是 非同步的確認或警告)

🕒 何時執行?

當你按下「下一步」按鈕時,在跳下一步之前會先執行它。

🔧 用途實例:

跳出確認視窗(是否已經了解這一步的重要性?)

做一些非同步檢查(例如確保資料填完或儲存成功)

example1
tourSteps: TourStep[] = [
    {
        target: '[data-tour="design-version"]', // 設計版次按鈕
        title: '設計版次',
        content: '在這裡可以查看和管理不同版本的設計',
        placement: 'bottom',
        // 進入下一步前確認用戶已了解設計版次的重要性
        beforeNext: async () => {
            const confirmed = await this.presentAlert({
                header: '重要提醒',
                message: '設計版次管理對於追蹤設計變更非常重要,您確定要繼續嗎?',
                buttons: ['取消', '確定'],
            });
            return confirmed;
        },
    },
];

async presentAlert(alertOptions: { header: string; message: string; buttons: string[] }) {
    const alert = await this.alertCtrl.create({
        header: alertOptions.header,
        message: alertOptions.message,
        buttons: [
            {
                text: alertOptions.buttons[0],
                role: 'cancel',
                cssClass: 'secondary'
            },
            {
                text: alertOptions.buttons[1],
                handler: () => {
                    return true;
                }
            }
        ],
        cssClass: 'custom-alert',
        backdropDismiss: false
    });

    await alert.present();

    const { role } = await alert.onDidDismiss();
    return role !== 'cancel';
}

✅ 3. triggerWhen 觸發條件

📌 功能:

「是否進入這個步驟」的條件判斷(可以是非同步)。只有當返回 true 或 Promise 解析為 true 時,該步驟才會顯示。

🕒 何時執行?

在導覽流程還沒顯示這個步驟時,就會執行這個函式來判斷「是否跳過這個步驟」。

🔧 用途實例:

登入檢查(導覽只能在登入狀態下執行)

等待某些資料或元件載入完成(例如圖表、地圖)

example1
triggerWhen: async () => {
    return await this.isReady(); // 等待某項前置條件
}
example2
tourSteps: TourStep[] = [
  {
    target: "#advanced-feature",
    title: "進階功能",
    content: "這是進階功能說明",
    triggerWhen: async () => {
      // 檢查用戶權限
      const hasPermission = await this.checkUserPermission();
      return hasPermission;
    }
  }
];

組合使用示例

export class YourComponent {
    tourSteps: TourStep[] = [
        {
            target: '.title-button:first-child', // 規劃設計按鈕
            title: '功能選擇',
            content: '這裡可以選擇不同的功能區域:規劃設計、監造測試、使用檢修',
            placement: 'bottom',
            // 確保用戶已經登入才能開始導覽
            triggerWhen: () => {
                // return this.authService.isLoggedIn();
                return this.login_name !== '';
            },
            // 確保按鈕元素已經完全載入
            validate: () => {
                const button = document.querySelector('.title-button:first-child') as HTMLElement;
                return button !== null && button.offsetParent !== null;
            },
        },
        {
            target: '[data-tour="design-version"]', // 設計版次按鈕
            title: '設計版次',
            content: '在這裡可以查看和管理不同版本的設計',
            placement: 'bottom',
            // 基本驗證:確保在規劃設計模式
            validate: () => {
                return this.num === 0;
            },
            // 進入下一步前確認用戶已了解設計版次的重要性
            beforeNext: async () => {
                const confirmed = await this.presentAlert({
                    header: '重要提醒',
                    message: '設計版次管理對於追蹤設計變更非常重要,您確定要繼續嗎?',
                    buttons: ['取消', '確定'],
                });
                return confirmed;
            },
        },
        {
            target: '[data-tour="analysis-tools"]', // 分析工具按鈕
            title: '分析工具',
            content: '這裡提供各種分析工具',
            placement: 'bottom',
            // 基本驗證:確保在規劃設計模式
            validate: () => {
                return this.num === 0;
            },
            // 等待分析工具載入完成
            triggerWhen: async () => {
                // 假設有一個方法檢查分析工具是否已載入
                const toolsLoaded = await this.checkAnalysisToolsLoaded();
                return toolsLoaded;
            },
            // 進入下一步前確認用戶已了解分析工具的使用方式
            beforeNext: async () => {
                const confirmed = await this.presentAlert({
                    header: '使用提示',
                    message: '分析工具需要正確的數據才能提供準確的分析結果,您確定要繼續嗎?',
                    buttons: ['取消', '確定'],
                });
                return confirmed;
            },
        },
    ];
}

最佳實踐

  1. validate 使用建議

    • 用於即時驗證,如表單驗證
    • 避免執行耗時操作
    • 返回結果應該立即可用
  2. beforeNext 使用建議

    • 用於執行必要的操作,如保存數據
    • 可以包含異步操作
    • 適合處理需要用戶確認的操作
  3. triggerWhen 使用建議

    • 用於控制步驟的顯示時機
    • 可以根據用戶權限或系統狀態決定
    • 適合實現條件性導覽流程
  4. 錯誤處理

    • 在 beforeNext 中妥善處理錯誤
    • 提供適當的錯誤提示
    • 考慮重試機制
  5. 性能優化

    • 避免在 validate 中執行耗時操作
    • 合理使用異步操作
    • 考慮使用緩存機制

元件輸入屬性

屬性 類型 描述
steps TourStep[] 導覽步驟陣列
visible boolean 控制導覽的顯示/隱藏

元件輸出事件

事件 類型 描述
visibleChange EventEmitter 可見性變更事件
stepChange EventEmitter 步驟變更事件
finishTour EventEmitter 導覽完成事件

樣式自定義

你可以通過覆蓋以下 CSS 類別來自定義樣式:

基礎樣式

.tour-overlay {
  // 覆蓋層樣式
  // 預設: 半透明黑色背景
  background: rgba(0, 0, 0, 0.4);
  z-index: 9999;
}

.tour-highlight {
  // 高亮區域樣式
  // 包含脈衝動畫效果
  &::after {
    border: 2px solid #007bff;
    animation: pulse 2s infinite;
  }
}

// 脈衝動畫效果
@keyframes pulse {
  0% {
    box-shadow: 0 0 0 0 rgba(0, 123, 255, 0.4);
  }
  70% {
    box-shadow: 0 0 0 10px rgba(0, 123, 255, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(0, 123, 255, 0);
  }
}

提示框樣式

.tour-popup {
  // 提示框基本樣式
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(10px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  
  // 不同位置的變體
  &.placement-top {
    transform-origin: bottom center;
  }
  &.placement-bottom {
    transform-origin: top center;
  }
  &.placement-left {
    transform-origin: right center;
  }
  &.placement-right {
    transform-origin: left center;
  }
}

.tour-header {
  // 標題區域樣式
  border-bottom: 1px solid #eee;
  
  h3 {
    font-size: 18px;
    color: #333;
  }
  
  .close-button {
    // 關閉按鈕樣式
    opacity: 0.6;
    &:hover {
      opacity: 1;
    }
  }
}

按鈕和進度指示器

.tour-button {
  // 基本按鈕樣式
  border: 1px solid #ddd;
  background: white;
  
  &:hover {
    background: #f5f5f5;
  }
  
  &.primary {
    // 主要按鈕樣式
    background: linear-gradient(45deg, #007bff, #0056b3);
    color: white;
    box-shadow: 0 2px 4px rgba(0, 123, 255, 0.2);
    
    &:hover {
      background: linear-gradient(45deg, #0056b3, #004094);
      transform: translateY(-1px);
    }
  }
}

.tour-progress {
  .progress-dot {
    // 進度點樣式
    background: #ddd;
    
    &.active {
      background: linear-gradient(45deg, #007bff, #0056b3);
      box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.2);
    }
  }
}

無障礙和動畫

// 無障礙焦點樣式
:focus {
  outline: 2px solid #007bff;
  outline-offset: 2px;
}

// 動畫效能優化
.tour-overlay,
.tour-popup,
.tour-highlight {
  will-change: transform, opacity;
}

自定義主題

你可以通過修改以下顏色和效果來自定義主題:

  1. 主色調:修改 #007bff 為你的品牌色
  2. 背景透明度:調整 rgba(0, 0, 0, 0.4) 的透明度
  3. 陰影效果:調整 box-shadow 參數
  4. 動畫時間:修改 transitionanimation 的持續時間

鍵盤支援

  • Enter:下一步
  • :上一步
  • Esc:關閉導覽

瀏覽器支援

  • Chrome (最新版)
  • Firefox (最新版)
  • Safari (最新版)
  • Edge (最新版)

注意事項

  1. 確保目標元素在導覽開始時是可見的
  2. 建議在元素完全渲染後再啟動導覽
  3. 使用 validatebeforeNext 來確保更好的用戶體驗
  4. 考慮使用 ariaLabel 來提供更好的無障礙支援

授權

MIT SHIH MING

聯絡與支援

問題回報

如果您發現任何問題或有改進建議,請透過以下方式聯繫我們:

貢獻指南

我們歡迎任何形式的貢獻,包括但不限於:

  • 代碼貢獻
  • 文檔改進
  • 問題回報
  • 功能建議

Readme

Keywords

none

Package Sidebar

Install

npm i ng-tour-guide

Weekly Downloads

3

Version

1.0.5

License

MIT

Unpacked Size

112 kB

Total Files

10

Last publish

Collaborators

  • ars37137