Day 14:LINE Bot Template Message 訊息回覆
6.4k 字,約 6 分鐘
2025 iThome 鐵人賽:Line Bot × NestJS:30 天開發日記。 原文發表於 iThome,也可以在下方留言。
文章目錄
前言
經過前幾天的學習,我們已經成功掌握了 LINE Bot 六大基礎訊息類型的發送技巧,為訊息互動奠定了穩固的基礎。今天,我們將踏入更具挑戰性的進階應用領域!
在實際的 LINE Bot 開發場景中,除了六大基礎訊息類型外,LINE 官方還提供了三種進階訊息格式:Template Message、Imagemap Message 及 Flex Message。
今天,我們將深入探索第一種進階訊息格式 Template Message,學習如何運用預設的模板佈局,快速打造出視覺統一且互動豐富的訊息回覆。
本日程式碼的範例連結
Template Message
Day 13提到的訊息共通參數
Sender及Quick Reply同樣適用於所有進階訊息格式(Template Message、ImageMapMessage、FlexMessage)。
Template Message 可以理解為 LINE 官方預先設計的訊息模板佈局系統。開發者只需將所需參數代入模板中,即可快速產生具有統一視覺風格的互動式訊息。這種設計大幅提升了開發效率,但相對地在客製化程度上會有一定的限制。
模板訊息總共有四種:
- Buttons template
- Confirm template
- Carousel template
- 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 個按鈕的互動選項。
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(開啟連結):點擊後會開啟指定的網址
當使用者傳送 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 沒有標題和縮圖功能
型別定義
透過 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 個按鈕,且所有卡片的按鈕數量必須相同。
型別定義
建議可以限制一下 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 Template 與 Button 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:互動按鈕(限定一個)
型別定義
定義上會跟 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 無法直接實現。這種標準化的限制,讓模板訊息比較難凸顯獨特的設計特色。
留言
留言使用 GitHub 帳號登入(Giscus),留言會存在 GitHub Discussions。