iT邦幫忙

2025 iThome 鐵人賽

DAY 14
1
Modern Web

Line Bot × NestJS:30 天開發日記系列 第 14

Day 14:LINE Bot Template Message 訊息回覆

  • 分享至 

  • xImage
  •  

2025 鐵人賽背景圖

前言

經過前幾天的學習,我們已經成功掌握了 LINE Bot 六大基礎訊息類型的發送技巧,為訊息互動奠定了穩固的基礎。今天,我們將踏入更具挑戰性的進階應用領域!

在實際的 LINE Bot 開發場景中,除了六大基礎訊息類型外,LINE 官方還提供了三種進階訊息格式:Template MessageImagemap MessageFlex Message

今天,我們將深入探索第一種進階訊息格式 Template Message,學習如何運用預設的模板佈局,快速打造出視覺統一且互動豐富的訊息回覆。

本日程式碼的範例連結

Template Message

Day 13提到的訊息共通參數 SenderQuick Reply 同樣適用於所有進階訊息格式(Template Message、ImageMapMessage、FlexMessage)。

Template Message 可以理解為 LINE 官方預先設計的訊息模板佈局系統。開發者只需將所需參數代入模板中,即可快速產生具有統一視覺風格的互動式訊息。這種設計大幅提升了開發效率,但相對地在客製化程度上會有一定的限制。

模板訊息總共有四種:

  1. Buttons template
  2. Confirm template
  3. Carousel template
  4. Image carousel template

四種模板訊息的共通屬性
所有 Template Message 都必須包含 altText 屬性,作為 LINE 通知顯示的替代文字。當使用者收到推播通知時,會顯示此文字內容。

messageEventHandlerMap 型別調整

Message 型別是 LINE SDK 提供的所有訊息回覆類型的聯合型別

在先前的實作中,我們採用「輸入什麼型別,就回覆什麼型別」的對應模式。舉例來說:使用者輸入文字訊息,LINE Bot 就回應文字訊息。這種設計主要是為了方便展示六大基礎訊息類型的對照效果。

然而在實際開發場景中,我們不應該被這種限制束縛。當收到文字訊息時,我們應該能夠靈活回覆各種訊息類型,只要符合 LINE Bot 支援的回覆格式即可。因此,我們將型別調整為更通用的 Message 類型,讓訊息回覆更加靈活。

line-webhook/line-webhook.types.ts

export type MessageEventHandlerMap = {
  [K in EventMessage['type']]: (
    event: Extract<EventMessage, { type: K }>,
  ) => Message;  // 主要調整這個部分,讓回傳型別不被限制
};

Button Template

支援可選標題及縮圖配置,並提供 1-4 個按鈕的互動選項。

LINE Button Template Message

Step 1:新增模板訊息請求的型別

核心參數:

  • altText:Line 通知顯示的文字
  • text:顯示內文(如:「按鈕小精靈出來吧」)
  • action:按鈕陣列(支援 1-4 個按鈕)

可選參數:

  • title:模板標題
  • thumbnailImageUrl:模板縮圖(如圖中的狗狗圖片),預設使用rectangle(長寬比:1.51:1)顯示。

line-message/types/template-button-message.ts

import { Action } from '@line/bot-sdk';

type HttpsURL = `https://${string}`;

export type TemplateButtonMessageReq = {
  altText: string;
  text: string;
  action: Action[];
  title?: string;
  thumbnailImageUrl?: HttpsURL;
};

Step 2:新增模板訊息請求的型別

這裡透過 createButtonTemplateMessage 函式來封裝複雜的模板訊息結構,讓開發者只需專注在必要參數的配置上,簡化訊息建立流程。

line-message/line-message.service.ts

  createButtonTemplateMessage(
    templateButtonMessageReq: TemplateButtonMessageReq,
  ): TemplateMessage {
    const { altText, text, actions, thumbnailImageUrl, title } =
      templateButtonMessageReq;

    const buttonTemplateMessage: TemplateMessage = {
      type: MessageType.Template,
      altText,
      template: {
        type: MessageType.TemplateButton,
        text,
        actions,
        title,
        ...(thumbnailImageUrl && { thumbnailImageUrl }), // 可選參數的處理
      },
    };

    return buttonTemplateMessage;
  }

Step 3:在接收到訊息 button 回傳模板按鈕訊息

Button Template Message Action 最多只能四個!!

在 Action 類型的選擇上,常用的有三種::message(訊息回傳)、postback(資料回傳)及 uri(開啟連結),本範例先以 message 類型進行示範。

當使用者傳送 button 文字時,我們會回覆事先準備好的 Button Template 訊息。

line-webhook/line-webhook.service

private async handleMessageEvent(event: MessageEvent): Promise<void> {
     const messageEventHandlerMap = {
      text: (message) {
        const { text } = message;
        // text 是使用者傳送的文字內容
        if (text === 'button') {
          return this.lineMessageService.createButtonTemplateMessage({
            altText: '按鈕小精靈通知',
            thumbnailImageUrl: 'https://res.cloudinary.com/dseg0uwc9/image/upload/v1753953684/2025%20IT%20%E9%90%B5%E4%BA%BA%E8%B3%BD/dog_icon_grxcsl.jpg',
            title: '標題',
            text: '按鈕小精靈出來吧',
            actions: [
              {
                type: 'message',
                label: '我是按鈕 1',
                text: '我是按鈕 1 號',
              },
              {
                type: 'message',
                label: '我是按鈕 2',
                text: '我是按鈕 2 號',
              },
              {
                type: 'message',
                label: '我是按鈕 3',
                text: '我是按鈕 3 號',
              },
              {
                type: 'message',
                label: '我是按鈕~',
                text: '我是按鈕 4 號',
              },
            ],
          });
        }
      },
    } satisfies Partial<MessageEventHandlerMap>;
}

Confirm Template

專為決策判斷場景設計的模板訊息,必須且只能擁有兩個按鈕

Confirm Template 是最簡潔的模板格式,適用於需要使用者做出「是/否」、「確認/取消」等二選一決策的情境。與 Button Template 不同,Confirm Template 沒有標題縮圖功能

LINE Bot Confirm Template 訊息回覆

型別定義

透過 Tuple 型別明確定義需要兩個 Action,編譯時期避免參數數量錯誤的情況發生

line-message/types/template-confirm-message

import { QuickReplyItem, Sender } from '@line/bot-sdk';

export type TemplateConfirmMessageReq = {
  altText: string;
  text: string;
  actions: [Action, Action];
  sender?: Sender;
  quickReplyItems?: Omit<QuickReplyItem, 'type'>[];
};

處理函式

line-message/line-message.service.ts

  createConfirmTemplateMessage(
    templateConfirmMessageReq: TemplateConfirmMessageReq,
  ): TemplateMessage {
    const { altText, text, actions } =
      templateConfirmMessageReq;

    const templateConfirmMessage: TemplateMessage = {
      type: MessageType.Template,
      altText,
      template: {
        type: MessageType.TemplateConfirm,
        text,
        actions,
      },
    };

    return templateConfirmMessage;
  }

Carousel Template

常被使用的模板訊息 ⭐⭐⭐

支援最多 10 張卡片,每張卡片最多 3 個按鈕,且所有卡片的按鈕數量必須相同。

LINE Bot Carousel Template

型別定義

建議可以限制一下 action 數量,避免 action 數量不一致的行為

這裡透過泛型約束的方式,讓原先的函數能夠在編譯時期驗證每張卡片的按鈕數量是否一致,確保所有卡片的 action 數量都符合 Carousel Template 的規範要求。

line-message/types/template-carousel-message.ts

import { QuickReplyItem, Sender, TemplateColumn } from '@line/bot-sdk';

type FixedArray<T, N extends number> = T[] & { length: N };

type LimitedActionColumn<N extends number> = Omit<
  TemplateColumn,
  'defaultAction' | 'imageBackgroundColor' | 'actions'
> & {
  actions: FixedArray<TemplateColumn['actions'][number], N>;
};

export type TemplateCarouselMessageReq<N extends number = number> = {
  altText: string;
  cards: LimitedActionColumn<N>[];
  sender?: Sender;
  quickReplyItems?: Omit<QuickReplyItem, 'type'>[];
};

處理函式

Carousel TemplateButton Template 的主要差異在於 cards 參數,每張卡片支援以下配置:

核心參數:

  • text:卡片內文
  • actions:卡片按鈕陣列(最多 3 個)

可選參數:

  • title:卡片標題
  • thumbnailImageUrl:卡片縮圖

卡片的參數配置與 Button Template 基本相同,但透過陣列形式支援多張卡片的輪播展示。

line-message.service/line-message.service.ts

  createTemplateCarouselMessage<N extends number>(
    templateCarouselMessageReq: TemplateCarouselMessageReq<N>,
  ): TemplateMessage {
    const { altText, cards, sender, quickReplyItems } =
      templateCarouselMessageReq;

    const templateCarouselMessage: TemplateMessage = {
      type: MessageType.Template,
      altText,
      template: {
        type: MessageType.TemplateCarousel,
        columns: [...cards],
      },
    };

    return templateCarouselMessage;
  }

透過泛型參數指定每張卡片的按鈕數量,實現編譯時期的靜態檢查:

line-webhook.service/line-webhook.service.ts

// 指定每張卡片只能有 1 個按鈕
this.lineMessageService.createTemplateCarouselMessage<1>({
    altText: '最新活動消息!!',
    cards: [
      {
        text: '新生代狗狗寵物展',
        thumbnailImageUrl:
          'https://res.cloudinary.com/dseg0uwc9/image/upload/v1753953684/2025%20IT%20%E9%90%B5%E4%BA%BA%E8%B3%BD/dog_icon_grxcsl.jpg',
        actions: [
          {
            type: 'message',
            label: '搶先第一手資訊',
            text: '可愛狗狗展',
          },
        ],
      },
      {
        text: '可愛貓貓展',
        thumbnailImageUrl:
          'https://res.cloudinary.com/dseg0uwc9/image/upload/v1753953684/2025%20IT%20%E9%90%B5%E4%BA%BA%E8%B3%BD/dog_icon_grxcsl.jpg',
        actions: [
          {
            type: 'message',
            label: '搶先第一手資訊',
            text: '可愛貓貓展',
          },
        ],
      },
    ],

ImageCarousel Template

實務開發中的熱門選擇 ⭐⭐⭐

以圖片為主軸的輪播卡片模板,版型固定,只能調整圖片及按鈕。

每張卡片均必須填寫以下配置:

  • imageUrl:卡片背景圖片
  • action:互動按鈕(限定一個)

LINE ImageCarousel Message

型別定義

定義上會跟 Carousel Template 蠻類似的,但是這邊因為只能設定一個按鈕,所以會相對單純。

import { QuickReplyItem, Sender, TemplateImageColumn } from '@line/bot-sdk';

export type TemplateImageCarouselMessageReq = {
  altText: string;
  cards: TemplateImageColumn[]; // 這邊的型別跟 Carousel Template 不同喔!!!
  sender?: Sender;
  quickReplyItems?: Omit<QuickReplyItem, 'type'>[];
};

處理函式

使用上與 Carousel Template 相似,但 ImageCarousel Template 的每張卡片都必須設置圖片和按鈕。

  createTemplateImageCarouselMessage(
    templateImageCarouselMessageReq: TemplateImageCarouselMessageReq,
  ): TemplateMessage {
    const { altText, cards, sender, quickReplyItems } =
      templateImageCarouselMessageReq;

    const templateImageCarouselMessage: TemplateMessage = {
      type: MessageType.Template,
      altText,
      template: {
        type: MessageType.TemplateImageCarousel,
        columns: [...cards],
      },
      ...this.buildCommonMessageProps(sender, quickReplyItems),
    };
    return templateImageCarouselMessage;
  }

本日結語

今天我們完成了第一種進階回覆訊息 Template Message 的實作。這類模板的使用方式相當直觀,只需準備好必要參數,就能快速產生對應的模板訊息。

然而,正如開頭提到的,Template Message 的客製化程度有限。例如想為商品模板加上「特價標籤」或其他個性化元素,Template Message 無法直接實現。這種標準化的限制,讓模板訊息比較難凸顯獨特的設計特色。


上一篇
Day 13:LINE Bot 客製化 Sender 與 Quick Reply 功能實作
系列文
Line Bot × NestJS:30 天開發日記14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言