iT邦幫忙

2025 iThome 鐵人賽

DAY 19
0
Modern Web

Modern Web × AI《拖延怪日記》:語錄陪伴擺脫拖延系列 第 19

【Day 19】— 入門 JavaScript 網頁架設:狀態追蹤(再次造訪的互動)

  • 分享至 

  • xImage
  •  

摘要
今天讓網站「記得你來過」。我們用 localStorage 追蹤是否曾造訪過,進場畫面會改成一句暖心問候:「今天的你,是不是不一樣了呢?」並依第一次/再次來訪呈現不同入口選項:

  • YES 分支(再次造訪):顯示「趁勝追擊」與「今天想先休息」。
  • NO 分支(第一次來或今天還沒開始):顯示「看看精神狀態」與「躺平」。

這讓體驗更貼近真實心境,也讓回訪者有被理解的感覺。

為什麼要做「狀態追蹤」?

  • 情境貼合:第一次來與第 N 次回來,使用者的心理不同,入口也應不同。
  • 行為動力:回訪時提供「趁勝追擊」能延續前一次的 momentum。
  • 溫柔退場:若今天不在狀態,也給「先休息/躺平」的友善選項,降低內疚感、提高回流率。

學習重點

  • localStorage 旗標檢查:visited_before(或 firstVisit/visitedBefore)。
  • 條件渲染:依「是否為同一天」與「是否曾來過」切換不同入口。
  • 體驗設計:YES/NO 之後再二分,提供四個輕量決策按鈕。

核心流程

  1. 載入時檢查 visited_before:
  • 未造訪 → 照舊顯示 Day 12 的共鳴畫面(首次體驗)。
  • 已造訪 → 隱藏 Day 12 文案,顯示 Day 19 的 YES/NO 互動。
  1. YES → 顯示「趁勝追擊 / 今天想先休息」;
    NO → 顯示「看看精神狀態 / 躺平」。
  2. 四個按鈕各自導向:
  • 趁勝追擊 → showPage('taskSchedule')
  • 今天想先休息 → 留在首頁,顯示安撫訊息
  • 看看精神狀態 → showPage('moodTest')
  • 躺平 → showPage('history')(回顧也算一種前進)

實作

假設已有:

  • Day 12 → showIntro()(已擴充為二訪判斷)、hideIntroShowForm()
  • Day 14 → showPage('moodTest')
  • Day 16 → showPage('taskSchedule')、任務安排頁骨架
  • Day 18 → renderArrangementSummary()(進任務安排時同步顯示溫暖總結)
  1. HTML:在 Day 12 區塊外觀維持,但加一個可隱藏的舊內文包裹與「二訪互動區」
    目的:能把舊的「你是不是也常常」整包隱藏,並切到新的 YES/NO UI。
<!-- [Day19-CHANGED] 給舊文案一個包裹,方便整包隱藏 -->
<section id="resonanceScreen" aria-labelledby="res-title" role="dialog" aria-modal="true">
  <div id="resonanceInner"> <!-- ★ 新增這個包裹 -->
    <h1 id="res-title">你是不是也常常…</h1>
    <ul>
      <li>看了一堆自我提升影片,結果還是沒開始?</li>
      <li>打開 IG/小紅書 想找靈感,結果一個多小時過去?</li>
      <li>明明有想做的事,卻又莫名其妙滑到半夜?</li>
    </ul>
    <p><strong>想想看,假日想做但沒做的事通常是什麼?</strong></p>
    <div><button id="btnStart">一起看看今天怎麼了 →</button></div>
  </div>

  <!-- [Day19-NEW] 二訪互動區(預設 hidden,回訪時才顯示) -->
  <div id="revisitIntro" hidden>
    <h1>今天的你,是不是不一樣了呢?</h1>

    <div style="display:flex; gap:.5rem; margin:.5rem 0;">
      <button id="btnRevisitYes" type="button">YES</button>
      <button id="btnRevisitNo" type="button">NO</button>
    </div>

    <!-- YES 分支 -->
    <div id="revisitBranchYes" hidden>
      <p>太好了!想要怎麼走?</p>
      <button id="btnGoChase" type="button" aria-controls="taskScheduleSection">趁勝追擊</button>
      <button id="btnRestToday" type="button">今天想先休息</button>
    </div>

    <!-- NO 分支 -->
    <div id="revisitBranchNo" hidden>
      <p>沒關係,我們可以輕鬆一點:</p>
      <button id="btnCheckMood" type="button" aria-controls="moodTestSection">看看精神狀態</button>
      <button id="btnLayFlat" type="button" aria-controls="historySection">躺平(先看看歷史)</button>
    </div>

    <p id="revisitFeedback" aria-live="polite" style="margin-top:.5rem;"></p>
  </div>
</section>
  1. JS:旗標、節點、初始化與顯示邏輯(YES/NO 分支清楚)
// [Day19-NEW] 造訪旗標
const VISITED_FLAG = 'visited_before';

// [Day19-NEW] 取得 / 設定造訪狀態
function hasVisitedBefore() { return localStorage.getItem(VISITED_FLAG) === '1'; }
function markVisited()      { localStorage.setItem(VISITED_FLAG, '1'); }

// [Day19-NEW] Day 12 舊文案包裹 & 二訪 UI 節點
const resonanceInner   = document.getElementById('resonanceInner');
const revisitIntro     = document.getElementById('revisitIntro');
const btnRevisitYes    = document.getElementById('btnRevisitYes');
const btnRevisitNo     = document.getElementById('btnRevisitNo');
const branchYes        = document.getElementById('revisitBranchYes');
const branchNo         = document.getElementById('revisitBranchNo');
const btnGoChase       = document.getElementById('btnGoChase');
const btnRestToday     = document.getElementById('btnRestToday');
const btnCheckMood     = document.getElementById('btnCheckMood');
const btnLayFlat       = document.getElementById('btnLayFlat');
const revisitFeedback  = document.getElementById('revisitFeedback');

// [Day19-NEW] 顯示二訪介面(隱藏舊文案)
function showRevisitIntro() {
  if (resonanceInner)  resonanceInner.hidden = true;
  if (revisitIntro)    revisitIntro.hidden   = false;

  // 初始時收合兩個分支
  if (branchYes) branchYes.hidden = true;
  if (branchNo)  branchNo.hidden  = true;

  // 顯示進場區塊、隱藏其他主區塊
  if (introEl)         introEl.hidden         = false;
  if (formSection)     formSection.hidden     = true;
  if (historySection)  historySection.hidden  = true;
}

// [Day19-CHANGED] 覆寫 showIntro:依造訪狀態切換
function showIntro() {
  const visited = hasVisitedBefore();

  // 顯示進場區塊
  if (introEl)        introEl.hidden = false;
  if (formSection)    formSection.hidden = true;
  if (historySection) historySection.hidden = true;

  if (visited) {
    // 回訪:隱藏舊文案、顯示 YES/NO 互動
    showRevisitIntro();
  } else {
    // 首訪:顯示 Day 12 舊文案
    if (resonanceInner) resonanceInner.hidden = false;
    if (revisitIntro)   revisitIntro.hidden   = true;
  }
}

// [Day19-NEW] 首次按下「一起看看今天怎麼了 →」就視為已造訪
startBtn?.addEventListener('click', () => {
  markVisited();
  hideIntroShowForm();
});

// [Day19-NEW] YES / NO 的分支切換(只顯示一個分支)
btnRevisitYes?.addEventListener('click', () => {
  if (branchYes) branchYes.hidden = false;
  if (branchNo)  branchNo.hidden  = true;
});
btnRevisitNo?.addEventListener('click', () => {
  if (branchNo)  branchNo.hidden  = false;
  if (branchYes) branchYes.hidden = true;
});

// [Day19-NEW] 四個行動按鈕的導向
btnGoChase?.addEventListener('click', () => {
  showPage('taskSchedule');        // 直接進任務安排
  renderArrangementSummary?.();    // 若已安排,顯示 Day 18 的溫暖總結
});

btnRestToday?.addEventListener('click', () => {
  revisitFeedback.textContent = '好,先照顧好自己也是很棒的選擇✨';
  // 可進階:觸發「建立提醒」或顯示微任務建議
});

btnCheckMood?.addEventListener('click', () => {
  showPage('moodTest');            // 去做 Day 14 小測驗
});

btnLayFlat?.addEventListener('click', () => {
  showPage('history');             // 躺平=先看看自己走了多少路
});

🔎 註:如果你希望「一開站就算造訪」而不是點 Start 才算,也可以在 init() 裡頭直接 markVisited() 一次(但通常我建議把「有明確互動」才算作造訪,比較符合實際使用)。

  1. JS:初始化掛載(延續既有 init(),僅補註解重點)
// [Day19-NOTE] init() 本體已存在,維持,但現在 showIntro() 會依旗標切換
(function init(){
  showIntro(); // ← 回訪者會直接看到 YES/NO 互動;首訪者看到 Day 12 舊引導
  if (sortSelect)   sortSelect.value = currentSort;
  if (filterSelect) filterSelect.value = currentFilter;
})();

驗證

  1. 首次造訪(或清除 localStorage 的 visited_before)
  • 顯示 Day 12 的「你是不是也常常」
  • 點「一起看看今天怎麼了 →」→ 進入表單頁,且之後再次開站會走二訪流程
  1. 回訪(visited_before = '1')
  • 進場直接顯示「今天的你,是不是不一樣了呢?」+ YES/NO
  • YES → 顯示「趁勝追擊 / 今天想先休息」
    點 趁勝追擊 → 進入任務安排頁
  • NO → 顯示「看看精神狀態 / 躺平」
    • 點 看看精神狀態 → 進入小測驗頁
    • 點 躺平 → 進入歷史回顧
  1. 刷新或隔天:仍保持二訪流程(旗標還在)。

常見錯誤 & 排查

  1. 回訪仍看到舊文案
  • 檢查 localStorage.getItem('visited_before') 是否為 '1'。
  • 是否把 showIntro() 覆寫為 Day 19 版(含旗標判斷)?
  1. YES/NO 按了沒反應
  • 檢查 #btnRevisitYes、#btnRevisitNo 是否在 DOM 中(HTML 是否貼在 #resonanceScreen 內)。
  • 事件監聽器是否掛載在相同的 id 上。
  1. 分支同時顯示
  • 初始要把 #revisitBranchYes、#revisitBranchNo 設為 hidden。
  • 切分支時要互斥:顯示一個就把另一個 hidden = true。
  1. 首次點 Start 不算造訪
    請確認 startBtn click 事件裡有 markVisited()(Day 19 新增的那行)。

上一篇
【Day 18】— 入門 JavaScript 網頁架設:navigator.share(溫暖總結與分享引導)
系列文
Modern Web × AI《拖延怪日記》:語錄陪伴擺脫拖延19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言