# 🏅 Day 11 - Global head Settings 與 useHead
## 今日學習目標
- 在 **nuxt.config.ts** 設定全域的 SEO 設定
- 使用 useHead 組合函式設定單一頁面的SEO 設定
## 全域 head 設定 (Global head Settings)
Global head Settings 是用來設定網站所有頁面共用的 `<head>` 資訊,確保所頁面的 SEO 設定一致,並避免在各頁面重複寫相同的 `<head>` 資訊。
### 撰寫 Global head 的語法
可以在 `nuxt.config.ts` 中的 `app.head` 屬性內以**物件**的方式定義全部頁面的 head 資訊。
```jsx
// nuxt.config.ts
export default defineNuxtConfig({
app: {
head: {
// 在 head 物件內定義 head 資訊
},
},
});
```
head 資訊是基於 [Unhead](https://unhead.harlanzw.com/) 套件的格式進行撰寫。因為 Nuxt3 整合了 [Unhead](https://unhead.harlanzw.com/) 套件,所以就可以更方便地控制各頁面的 `<head>` 資訊,定義 SEO 相關的 meta tags、外部資源的載入、樣式設定等。接下來將使用範例的方式針對經常使用的屬性進行解說,更多的屬性可以至 [Unhead 官方文件](https://unhead.harlanzw.com/) 閱讀 。
### 範例
```jsx
// nuxt.config.ts
export default defineNuxtConfig({
// ...其他設定
app: {
head: {
viewport: "width=device-width, initial-scale=1", // 渲染出 <meta name="viewport" content="width=device-width, initial-scale=1">
title: "全域 - Nuxt3 Day11 Global head 練習", // 渲染出 <title>全域 - Nuxt3 Day11 Global head 練習</title>
charset: "utf-8", // 渲染出 <meta charset="UTF-8">
meta: [
// 渲染出 <meta name="description" content="透過今天的學習,將會學習到 Nuxt3 Global head 的設定方法">
{
name: "description",
content: "透過今天的學習,將會學習到 Nuxt3 Global head 的設定方法 ",
},
// 渲染出 <meta property="og:title" content="Nuxt3 Day11 Global head 練習">
{ property: "og:title", content: "Nuxt3 Day11 Global head 練習" },
{ property: "og:url", content: "http://localhost:3000/" },
{
property: "og:description",
content: "透過今天的學習,將會學習到 Nuxt3 Global head 的設定方法",
},
],
script: [
// 從外部載入 lodash 套件
// 渲染出 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.js"></script>
{
src: "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.js",
// 用於調整 script 標籤渲染的位置,值可以是 'head' | 'bodyClose' | 'bodyOpen'
tagPosition: 'head'
},
],
link: [
// 從外部載入 google 字體
// 渲染 <link rel="preconnect" href="https://fonts.googleapis.com">
{ rel: "preconnect", href: "https://fonts.gohogleapis.com" },
// 渲染 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
{
rel: "preconnect",
href: "https://fonts.gstatic.com",
crossorigin: "",
},
// 渲染 <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+TC:wght@100..900&display=swap" rel="stylesheet">
{
rel: "stylesheet",
href: "https://fonts.googleapis.com/css2?family=Noto+Sans+TC:wght@100..900&display=swap",
},
],
style: [
// 渲染出 <style>h1{ color: red }</style>
{ children: "h1{ color: red }" },
],
noscript: [
// 渲染出 <noscript>此網頁需要支援 JavaScript 才能正確運行,請先至你的瀏覽器設定中開啟 JavaScript。</noscript>
{
children:
"此網頁需要支援 JavaScript 才能正確運行,請先至你的瀏覽器設定中開啟 JavaScript。",
},
],
},
},
});
```
範例中使用了 `viewport`、`title`、`charset`、`meta`、`script`、`link`、`style` 和 `noscript` 屬性 :
- title : 設定全域的標題,在所有頁面元件都套用這個標題。
- viewport : 設定全域網頁的可見區域以及縮放比例。
- charset : 設定 HTML 的字元編碼為 utf-8 。
- meta: 設定 meta 標籤,例如 og:title 。
- script: 載入外部的 JavaScript 資源。其中調整 script 標籤渲染的位置可以使用 [tagPosition](https://unhead.unjs.io/usage/guides/positions#tagposition) 屬性,允許的值有 'head' ( 渲染在 `<head>` 標籤內,預設值) 、 'bodyClose' ( 渲染在 `</body>` 結尾標籤前面 ) 、'bodyOpen’ ( 渲染在 `<body>` 起始標籤前面 )
- link: 載入外部的 CSS 資源。
- style: 定義內嵌樣式,渲染`<style></style>`標籤。
- noscript: 定義在 JavaScript 被禁用時顯示的內容,渲染 `<noscript></noscript>` 。
當設定 `meta`、`script`、`link`、`style` 和 `noscript` 屬性時,這些屬性的值都是以陣列格式呈現,且陣列中的每個元素都是物件格式。
在渲染時,`meta`、`script`、`link` 屬性會渲染相應的 HTML 標籤。陣列內的每個物件代表一個對應的 HTML 標籤,並包含該標籤的屬性和值。例如,`link` 屬性會渲染出 `link` 標籤,陣列中的每個物件都代表一個 `link` 標籤要設定的屬性,每個物件都會被渲染為一個 `link` 標籤,物件內的屬性會對應到 `link` 標籤的屬性。
而 `style` 和 `noscript` 屬性被渲染時,這些屬性名稱會分別生成 `<style>` 和 `<noscript>` 標籤。陣列中的每個元素都會創建一個相應的標籤。
### 渲染結果
加入全域設定後,在頁面可以透過 “檢視網頁原始碼” 查看 `/pages/index.vue` ( 首頁 ) 頁面渲染後的結果,如下圖。

## 單一頁面 head 設定 (useHead)
上一節在 `nuxt.config.ts` 中設定的 head 資訊屬於全域設定,若希望單獨調整頁面的 head 資訊,可以使用 Nuxt3 提供的 `useHead` Composable, 在單一頁面中設定 head 資訊。
```html
<script setup>
useHead({
// 在物件內定義 head 資訊
});
</script>
```
### 撰寫 useHead 的語法
因為 useHead 也是基於 [Unhead](https://unhead.harlanzw.com/) 套件的格式進行撰寫,所以屬性的用法與撰寫結構和全域 `app.head` 屬性相同。若在頁面元件以 `useHead` 設定了與全域相同的屬性,`useHead` 撰寫的屬性會覆蓋全域的屬性,其他屬性則會沿用全域設定。
### 範例
例如在 `/pages/index.vue` 使用 `useHead` 加入了首頁的 head 資訊,會覆蓋全域 `title` 和 `meta` 屬性的設定。
```html
<!-- /pages/index.vue -->
<script setup>
useHead({
title: "首頁 - Nuxt3 Day11 useHead() 練習",
meta: [
{
property: "og:title",
content: "首頁 - Nuxt3 Day11 useHead() 練習",
},
{ property: "og:image", content: "http://localhost:3000/share.jpg" },
{
property: "og:description",
content: "首頁 - 透過今天的學習,將會學習到 Nuxt3 useHead() 的使用方法 ",
},
{
name: "description",
content: "首頁 - 透過今天的學習,將會學習到 Nuxt3 useHead() 的使用方法 ",
},
],
});
</script>
<template>
<h1>Page: index</h1>
</template>
```
### 渲染結果
渲染的結果如下圖所示,左側是 `/pages/index.vue` 加入 useHead 之前以全域設定渲染的結果,右側是 `/pages/index.vue` 加入 useHead 之後渲染的結果。
在 `useHead()` 加入的 `title` 和 `meta` 會覆蓋全域 `title` 和 `meta` 的屬性。而其它在 `useHead()` 沒有寫入的屬性則是會繼續沿用全域的設定,例如 noscript、script、link 屬性。

### 傳入具響應性的資料
`useHead()` 中所有的屬性都可以使用具有響應性的資料,包括 `ref`、`reactive`、`computed getter`。以 `/pages/index.vue` 的 `useHead()` 為例,可以將 `title` 屬性以 `ref` 定義,在模板中可以對 input 綁定 v-model=”title” 來動態修改瀏覽器頁籤的標題。
```html
<!-- /pages/index.vue -->
<script setup>
const title = ref("首頁 - Nuxt3 Day11 useHead() 練習");
useHead({
title,
meta: [
{
property: "og:title",
content: "首頁 - Nuxt3 Day11 useHead() 練習",
},
{ property: "og:image", content: "http://localhost:3000/share.jpg" },
{
property: "og:description",
content: "首頁 - 透過今天的學習,將會學習到 Nuxt3 useHead() 的使用方法 ",
},
{
name: "description",
content: "首頁 - 透過今天的學習,將會學習到 Nuxt3 useHead() 的使用方法 ",
},
],
});
</script>
<template>
<h1>Page: index</h1>
<label for="title">
修改瀏覽器頁籤的標題
<input type="text" id="title" v-model="title" />
</label>
</template>
```
<br>
> 今日學習的[範例 Code - 資料夾: day11-nuxt-usehead-examplle](https://github.com/hexschool/nuxt-daily-tasks-2024)
## 題目
請 fork 這一份 [模板](https://github.com/jasonlu0525/nuxt3-live-question/tree/day11-usehead-seo),在 `nuxt.config.ts` 與 `/pages/room/index.vue` ,完成以下條件 :
- 在 `nuxt.config.ts` 中定義全域設定,確保以下 head 資訊被應用於所有頁面。
```html
<title>Freyja | 高雄頂級旅館 - 提供奢華住宿體驗</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="X-Content-Type-Options" content="nosniff">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="Freyja 旅館">
<meta name="keywords" content="Freyja,Freyja 訂房,高雄旅遊,訂房,住宿,住宿預訂,四人房,雙人房,景觀房">
<meta name="description" content="Freyja 旅館位於高雄,提供頂級的住宿體驗。享受絕美市景與高級設施,讓您的每一刻都充滿奢華與舒適。立即預訂,開啟難忘的住宿之旅!">
<meta name="theme-color" content="#ffffff">
<meta name="robots" content="index, follow">
<link rel="icon" href="/favicon.ico">
<link rel="canonical" href="https://freyja.travel.com.tw">
<meta property="fb:app_id" content="12345678" />
<meta property="og:locale" content="zh-TW" />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://freyja.travel.com.tw" />
<meta property="og:title" content="Freyja | 高雄頂級旅館 - 提供奢華住宿體驗" />
<meta property="og:image" content="https://freyja.travel.com.tw/images/og-image.jpg" />
<meta property="og:description" content="Freyja 旅館位於高雄,提供頂級的住宿體驗。享受絕美市景與高級設施,讓您的每一刻都充滿奢華與舒適。立即預訂,開啟難忘的住宿之旅!" />
```
- 在 `/pages/room/index.vue` 頁面中,使用 `useHead` 渲染以下 head 資訊,確保覆蓋全域設定中的對應屬性。
```html
<title>Freyja | 房型列表</title>
<meta name="description" content="探索 Freyja 頂級房型,從景觀尊榮家庭房到尊爵雙人房,享受絕美市景與舒適空間。立即預訂,享受獨特的住宿體驗!">
<meta property="og:title" content="Freyja | 高雄最頂級的旅館">
<meta property="og:description" content="探索 Freyja 的高雄頂級房型,從景觀尊榮家庭房到尊爵雙人房,享受絕美市景與舒適空間。立即預訂,享受獨特的住宿體驗!">
<meta property="og:image" content="https://raw.githubusercontent.com/hexschool/2022-web-layout-training/main/typescript-hotel/%E6%A1%8C%E6%A9%9F%E7%89%88/room2-1.png">
<meta property="og:url" content="https://freyja.travel.com.tw/room">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Freyja | 高雄最頂級的旅館">
<meta name="twitter:description" content="探索 Freyja 的高雄頂級房型,從景觀尊榮家庭房到尊爵雙人房,享受絕美市景與舒適空間。立即預訂,享受獨特的住宿體驗!">
<meta name="twitter:image" content="https://raw.githubusercontent.com/hexschool/2022-web-layout-training/main/typescript-hotel/%E6%A1%8C%E6%A9%9F%E7%89%88/room2-1.png">
```
- 確認 `/pages/room/index.vue` 頁面的 head 設定成功覆蓋了全域 head 中的相同屬性設定。
## 回報流程
將答案上傳至 GitHub 並複製 GitHub repo 連結貼至底下回報就算完成了喔 !
解答位置請參考下圖(需打開程式碼的部分觀看)

<!--
解答: https://github.com/jasonlu0525/nuxt3-live-answer/tree/day11-usehead-seo
-->
## 回報區
| Discord | Github / 答案 |
| --- | --- |
| LinaChen | [Github](https://github.com/Lina-SHU/nuxt3-live-question) |
| 眼睛 | [Github](https://github.com/Thrizzacode/nuxt3-live-question/tree/day11-usehead-seo) |
| kevinhes | [Github](https://github.com/kevinhes/nuxt-daily-mission/tree/day11) |
| hsin yu | [Github](https://github.com/dogwantfly/nuxt3-daily-task-live-question/tree/day11-usehead-seo) |
| Jim Lin | [Github](https://github.com/junhoulin/Nuxt3-hw-day-after10/tree/day11) |
| Stan | [Github](https://github.com/haoxiang16/nuxt3-live-question/tree/day11-usehead-seo) |
| Steven | [Github](https://github.com/y7516552/nuxt3-live-question/tree/day11) |
| dragon | [Github](https://github.com/peterlife0617/2024-nuxt-training-homework01/tree/feature/day11) |
| MY | [Github](https://github.com/ahmomoz/nuxt3-live-question/tree/day11-usehead-seo-hw) |
| Rocky | [Github](https://github.com/WuRocky/Nuxt-Day11-Global-head-Settings-useHead.git) |
| Ariel | [Github](https://github.com/Ariel0508/nuxtday6/tree/nuxtday11) |
| Tough life | [GitHub](https://github.com/hakuei0115/Nuxt_testing) |
| wei_Rio |[Github](https://github.com/wei-1539/nuxtDaily10/tree/Day-11---Global-head-Settings-%26-useHead)|
| runweiting | [Github](https://github.com/runweiting/2024-NUXT-Task/tree/day11) |
| Fabio20 | [Github](https://github.com/fabio7621/nuxt3-live-question-d2/tree/nuxt-live-day11) |
| tanuki狸 | [Github](https://github.com/tanukili/Nuxt-2024-week01-2/tree/day11-usehead-seo) |
| 阿塔 | [Github](https://github.com/QuantumParrot/2024-Hexschool-Nuxt-Camp-Daily-Task/commit/d6ebef785da8a65a0d64e177855b4a4be3aa2206) |
| Nielsen | [Github](https://github.com/asz8621/nuxt3-daily-task/tree/day11-usehead-seo) |
| barry1104 | [Github](https://github.com/barrychen1104/nuxt3-live-question/tree/day11-usehead-seo) |
| Johnson | [Github](https://github.com/tttom3669/2024_hex_nuxt_daily/tree/day11-usehead-seo) |
| lidelin | [Github](https://github.com/Lide/nuxt3-live-question/tree/day11-usehead-seo) |
<!--
快速複製
| --- | [Github]() |
-->