紀錄工作經驗、相關知識,解決技術相關問題。

Javascript

[JS] Javascript 取得網址後面 #(錨點)名稱:location.hash 用法、去井字號與 hashchange 監聽

[JS] Javascript 取得網址後面 #(錨點)名稱:location.hash 用法、去井字號與 hashchange 監聽 特色圖片

在網址(URL)中接在井字號 # 後方的字串,通稱為「頁面錨點(Hash / Fragment Identifier)」。# 後面的名稱通常對應網頁中某個區塊的 id,能讓瀏覽器快速捲動定位到指定區塊,也常用於前端單頁狀態(如頁籤切換)。當 JavaScript 需要取得或修改目前網址後面的 #(錨點)名稱時,標準做法是使用 window.location.hash。

⚡ 快速跳轉(依實務情境選擇):

基本語法:使用 location.hash 取得網址 #(錨點)名稱

假設當前網址為:

https://www.seanacnet.com:8080/js/location-hash.html?id=111&t=9#template

使用範例:

let hash = window.location.hash;

console.log(hash);
// 輸出: "#template"

注意:

  1. location.hash 回傳的字串包含最前面的井字號 #(即 "#template")。
  2. 若當前網址完全沒有 # 錨點,或是網址結尾只有一個空的 #,location.hash 皆會回傳空字串 ""。

實用技巧:去除開頭 # 井字號與解碼中文錨點

在實務開發中,我們拿到 location.hash 後通常需要將開頭的 # 去除,才能拿純名稱去比對狀態或呼叫 document.getElementById();此外,若錨點包含中文字(如 #常見問題),瀏覽器會自動轉為百分比編碼(#%E5%B8%B8...),需搭配 decodeURIComponent() 還原:

// 假設當前網址為 https://www.seanacnet.com/post#section-2
// 1. 使用 slice(1) 或 replace(/^#/, '') 去除開頭的 # 號
const rawHashName = window.location.hash.slice(1);
console.log(rawHashName);
// 輸出: "section-2"

// 2. 安全解碼中文錨點並取得對應 DOM 元素
function getTargetElementByHash() {
  const hashName = decodeURIComponent(window.location.hash.slice(1));
  if (!hashName) return null;
  return document.getElementById(hashName);
}

實務場景一:監聽 hashchange 事件實現頁籤(Tabs)狀態同步

在製作產品介紹頁或後台設定頁的多頁籤(Tabs,如 #profile、#security、#billing)時,若將當前頁籤代稱記錄在 location.hash,使用者重新整理頁面或將網址分享給同事時,就能直接打開對應的頁籤。

透過監聽 window 的 hashchange 事件,可在網址 # 改變時即時切換畫面:

function syncTabWithHash() {
  // 取得不含 # 的頁籤名稱,若無則預設顯示 'profile'
  const activeTab = window.location.hash.slice(1) || 'profile';

  document.querySelectorAll('[data-tab-panel]').forEach((panel) => {
    const isCurrent = panel.dataset.tabPanel === activeTab;
    panel.hidden = !isCurrent;
  });
}

// 1. 頁面初次載入時執行一次,還原網址錨點指定的頁籤
window.addEventListener('DOMContentLoaded', syncTabWithHash);

// 2. 當使用者點擊錨點或按瀏覽器上一頁/下一頁改變 # 時自動觸發
window.addEventListener('hashchange', syncTabWithHash);

實務場景二:載入頁面時根據 location.hash 平滑捲動並扣除固定導覽列高度

許多網站頂部有固定定位(position: fixed 或 sticky)的導覽列。當使用者點擊帶有 #錨點 的連結進入頁面時,目標標題常會被頂部導覽列遮住。除了在 CSS 設定 scroll-margin-top 外,也可在 JS 中透過 location.hash 控制偏移捲動:

window.addEventListener('load', () => {
  const targetId = decodeURIComponent(window.location.hash.slice(1));
  if (!targetId) return;

  const targetEl = document.getElementById(targetId);
  if (targetEl) {
    const headerOffset = 80; // 頂部固定導覽列高度 (px)
    const elementPosition = targetEl.getBoundingClientRect().top + window.scrollY;
    window.scrollTo({
      top: elementPosition - headerOffset,
      behavior: 'smooth',
    });
  }
});

💡 補充:如何清除網址上的 #hash 而不留下多餘的 # 號?

若直接執行 location.hash = '',網址列最後方仍會殘留一個孤立的 # 符號,且會觸發頁面跳動。若想乾淨移除 #hash,建議使用 history.replaceState:

// 乾淨移除網址尾端的 #hash 與 # 符號,且不觸發頁面捲動
window.history.replaceState(
  null,
  '',
  window.location.pathname + window.location.search
);

要查看 location.hash 在各個瀏覽器的相容性,請參考:MDN Web Docs: Location.hash 瀏覽器相容性。

如果你還想進一步了解 JS 取得 URL 的其他參數,可前往以下專篇查詢:

發表迴響