iT邦幫忙

2026 iThome 鐵人賽

DAY 16
0
JavaScript

從看不懂到做出來,用 PawPal 走過前端新手村系列 第 16

Day 16|功能明明有反應,為什麼手機用起來還是不順?

  • 分享至 

  • xImage
  •  

今天的故事

平常開發和檢查 PawPal 時,大家比較常直接用電腦版操作,手機版相對比較少完整地走過一次流程。

所以有一次,我刻意從手機版重新操作醫院頁面,想看看換到不同裝置之後,實際用起來會不會有什麼不順的地方。

結果真的讓我發現了一個問題。

在手機版裡,我往下滑到醫院列表,點了一間醫院。

功能有反應。

醫院已經被選取,地圖上的狀態也跟著改變。

但我的畫面還停在下面的醫院列表。

如果想確認剛剛點的醫院到底有沒有成功選取,我還得自己再往上滑,回到地圖的位置才能看到結果。

那時候我的第一個想法就是:

這是一個 Bug。

它不是會跳出紅色錯誤訊息的 Bug,也不是 API 壞掉或資料沒有更新。

程式其實有成功執行。

但實際操作起來,就是不順。


功能明明成功了,問題到底在哪裡?

如果只從程式的角度來看,這個功能其實沒有壞掉。

大概可以把當時的流程想成:

點擊醫院卡片
↓
醫院成功被選取
↓
地圖狀態跟著更新
↓
功能完成

以前的我看到這裡,可能就會覺得:

「有成功啊,那應該沒問題。」

但真正從手機版走一次流程後,看到的卻是:

使用者往下滑到醫院列表
↓
點擊其中一間醫院
↓
醫院成功被選取
↓
地圖狀態更新
↓
畫面卻還停在列表
↓
使用者看不到剛剛發生的變化
↓
還要自己滑回地圖

問題就出在最後這幾步。

系統知道操作成功了,但使用者不一定知道。

PawPal 當時開的 Issue,就是要處理這個問題:手機版使用者點擊醫院卡片後,醫院雖然已經成功選取,但畫面仍停留在列表,還得手動滑回地圖才能看到結果。


沒有報錯,為什麼我還是把它當成 Bug?

以前檢查功能時,我很容易先看這些事情:

按鈕有沒有反應?
資料有沒有更新?
API 有沒有成功?
Console 有沒有 Error?

這些當然都很重要。

但這次的情況不太一樣。

因為:

事件有成功觸發
醫院選取狀態有更新
地圖也有對應變化

如果只看程式執行的結果,好像什麼都沒有錯。

可是站在使用者的角度,操作完之後卻看不到結果。

這讓我開始注意到:

程式有成功執行,不代表整個操作流程就已經完整。

如果我點了一個按鈕之後,系統其實已經完成操作,但畫面沒有讓我看到結果,我還是很可能會懷疑:

「我剛剛到底有沒有點成功?」

對使用者來說,這樣的流程就還有可以改善的地方。


我最後做的,是把操作流程補完整

確認問題之後,要處理的方向其實很直覺。

使用者既然是在下面的醫院列表選擇醫院,那選取成功之後,就應該讓他直接看到上方地圖的結果。

所以最後的流程變成:

點擊醫院卡片
↓
維持原本的醫院選取流程
↓
確認目前是不是堆疊版面
↓
把捲動安排在這一輪 DOM 更新之後
↓
取得地圖區塊
↓
把畫面平滑捲回地圖

在 PawPal 的實作裡,原本選取醫院的邏輯沒有被拿掉,而是在列表點擊的流程外,再補上捲動回地圖的處理。

這次主要碰到了三個東西:

template ref
nextTick()
scrollIntoView()

實際程式的捲動條件使用 (max-width: 1279px),所以最後不只手機,在部分平板或其他使用堆疊版面的寬度下也會套用這個處理。

下面是簡化概念

const stackedHospitalMapQuery = '(max-width: 1279px)'

const selectHospitalFromList = (hospitalId) => {
  selectHospital(hospitalId)

  const isStackedLayout = window.matchMedia(
    stackedHospitalMapQuery,
  ).matches

  if (!isStackedLayout) return

  nextTick(() => {
    mapSectionRef.value?.scrollIntoView({
      behavior: 'smooth',
      block: 'start',
    })
  })
}

以上為簡化概念,保留這次實作的主要流程與條件,不是 PawPal Repository 的完整原始程式碼。


template ref:先找到我要回去的位置

要讓畫面自動回到地圖,第一件事就是要知道:

地圖區塊到底在哪裡?

在 Vue 裡,可以透過 template ref 取得畫面上的特定元素。

概念上可以想成:

<section ref="mapSectionRef">
  地圖
</section>

有了這個 template ref,我就能取得地圖區塊,後面才有辦法把畫面捲到這個位置。

這次我不是要修改地圖本身,而是要先回答一個很單純的問題:

「使用者選完醫院之後,我要把畫面帶去哪裡?」


nextTick():為什麼把捲動安排在畫面更新之後?

這也是我在這次修改裡碰到的一個觀念。

Vue 的狀態改變後,相關的 DOM 更新會經過自己的更新流程。

而這次 PawPal 的實作,在醫院選取完成、又符合手機/平板等堆疊版面的情況下,會透過 nextTick() 把後面的捲動安排在這一輪 DOM 更新之後。

流程比較像:

選取醫院
↓
狀態改變
↓
確認是堆疊版面
↓
透過 nextTick() 安排後續動作
↓
捲回地圖

所以這裡可以先把 nextTick() 理解成:

「這次實作選擇等目前這一輪 DOM 更新處理後,再執行捲動。」

這不代表所有類似功能都一定要使用 nextTick(),而是在這次 PawPal 的實作裡,它被用來安排選取之後的捲動時機。

以前看到 nextTick(),我大概只知道「好像跟畫面更新有關」。

真的碰到這次的互動問題後,我才比較知道它可以在什麼情況下派上用場。


scrollIntoView():不是做動畫,而是讓結果被看見

最後真正負責把畫面移回地圖的是:

scrollIntoView()

這次使用的概念是:

mapSectionRef.value?.scrollIntoView({
  behavior: 'smooth',
  block: 'start',
})

behavior: 'smooth' 讓畫面平滑移動,而不是突然跳到另一個位置。

block: 'start' 則是讓目標區塊盡量出現在畫面上方。

一開始看到這段程式碼,很容易覺得:

「這不就是一個捲動畫面的效果嗎?」

但對我來說,這次真正重要的不是動畫。

而是:

讓使用者直接看到自己剛才操作造成的結果。

如果只是為了畫面好看,那它可能只是一個視覺效果。

但放在這個情境裡,它其實是在補完整使用者的操作流程。

這次修改也補了一個 regression test(回歸測試)作為保護。

這個測試會檢查 template ref、版面判斷、nextTick()scrollIntoView() 和列表事件綁定等關鍵結構是否還存在。

它不是完整模擬瀏覽器操作的 UI 測試,但可以降低之後修改程式時,不小心把這段重要連接移除或改壞的風險。


修完之後,我才重新理解「正常使用」

這次修改最讓我有感的,其實不是學會 scrollIntoView()

而是我開始重新想一個問題:

功能做出來之後,到底怎樣才算「正常使用」?

以前我比較容易從開發者的角度判斷:

功能有沒有做出來?
按鈕有沒有反應?
資料有沒有成功?
API 有沒有錯?

如果這些都正常,我可能就會覺得功能完成了。

可是修完這個手機版地圖問題後,我開始覺得還少了一件事情:

使用者到底能不能自然地完成這個操作?

如果使用者點完一個東西之後,還要自己去找:

「剛才發生什麼事?」

那即使程式邏輯沒有錯,整個使用體驗還是會受到影響。

也是修完這個問題之後,我才真的開始覺得,使用者體驗的好壞,本來就是「功能能不能正常使用」的一部分。

不是只有漂亮或不漂亮。

而是:

使用者能不能理解現在發生了什麼。


如果現在重新做一次

如果現在重新做一次類似的功能,我會比以前多做一件事情。

不只是把功能做完,而是真的從不同裝置把流程走一次。

例如:

功能完成
↓
用電腦版操作一次
↓
用手機版操作一次
↓
每完成一個操作都問自己:
「使用者現在看到的是什麼?」
↓
確認操作結果有沒有清楚呈現

以前我可能比較容易停在:

「程式有沒有正常跑?」

現在我會再多問一句:

「如果我完全不知道這段程式怎麼寫,只是一個第一次使用網站的人,我會知道剛剛操作成功了嗎?」

這個角度,是我做完這次修改之後才開始比較注意的事情。


本篇重點與心得

這次手機版醫院頁面的修改,讓我記住幾件事情:

  1. 功能有反應,不代表整個使用流程就完整。
  2. 手機版的畫面位置,也可能影響使用者能不能看到操作結果。
  3. template refnextTick()scrollIntoView() 這次不是單純拿來做畫面效果,而是用來補完整互動流程。
  4. 實際實作時,也要注意不同版面的使用情境。
  5. 程式執行成功,和使用者感受到操作成功,是兩件不同的事情。

以前我可能會覺得:

「能動就好了。」

但這次之後,我開始覺得真正要問的應該是:

它不只會動,使用者真的用得順嗎?


下一篇預告

這次的問題,是功能已經有反應,但使用者沒有馬上看到結果。

而在另一個功能裡,我遇到的問題剛好不太一樣:使用者送出了資料,但畫面上的其他資料也必須跟著一起更新。

下一篇,我會從第一次做醫院評論開始,整理一則留言送出去之後,評論、平均星等和畫面上的資料到底怎麼一起變化。

下一篇:

Day 17|第一次做醫院評論,留言送出後星等怎麼跟著變?


上一篇
Day 15|Debug 到懷疑人生的那一天
下一篇
Day 17|第一次做醫院評論,留言送出後星等怎麼跟著變?
系列文
從看不懂到做出來,用 PawPal 走過前端新手村20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言