npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ng-tour-guide

v1.0.5

Published

An Angular tour guide component with Ionic support

Readme

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

聯絡與支援

問題回報

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

貢獻指南

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

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