Vue-SSR: head Mixin 實現頭部資訊管理

Anne木槿阿倫發表於2019-03-04

上週發了我第一篇技術部落格,傳送門1:JS中的陣列過濾,從簡單篩選到多條件篩選,感謝大家的支援,尤其是提出疑問,發現錯誤的同學,感謝你們。發完部落格以後,我用 hexo 搭了一個 github pages, 繫結了我之前買的域名,傳送門2: blog.yidol.cn/,以後我的部落格會在GitHub發一遍,然後掘金抄送一遍。

近兩個月都在忙著搭建 vue-ssr 的專案,因為公司產品是媒體類,SEO 很重要,第一週是嘗試用 nuxt 搭建了一個專案,nuxt 確實是開箱即用,比較爽,就是配置的時候可能要看看 nuxt 的文件,還要看看 webpack 的文件,很多人使用 vue-cli3 產生了同樣的感受。由於公司給的時間也夠,我決定參考尤雨溪的官方例子? 傳送門3: vue-hacknews-2.0 搭建了我司的新 PC 端專案,整個專案是用 webpack4+vue2+vue-ssr 從 0 到 1,踩過一些坑,多謝網上各個平臺的同學們貢獻的文章,我打算陸續寫文章分享專案搭建的過程,希望也能夠幫助到大家。

  下面進入這篇文章的主題,尤大大的例子裡是做了一個 tilte 的 Mixin 方法,可以修改各個頁面的 title,但是我司的需求可能是不同的頁面不僅是要不同的 title,還要不同的 description,author,keywords,網上有很多人使用 vue-meta, 感興趣的小夥伴可以搜尋一下用法,今天我想討論的是改造尤大大專案裡的 title mixin 為 head mixin,滿足我司需求。

尤大大的title mixin

  開啟 vue-hacknews 專案 src/util/title.js ,可以看到以下程式碼或者 傳送門4: vue SSR 指南 Head 管理

// 獲取模版裡的 title
function getTitle (vm) { 
  const { title } = vm.$options
  if (title) {
    return typeof title === `function`
      ? title.call(vm)
      : title
  }
}

// 如果有 title 了就載入新的 title,沒有就還有預設的頂著,預設的 title 在哪裡,稍後告訴你
// 下面倆一個是伺服器端渲染時呼叫,一個是客戶端渲染是呼叫,為啥倆不一樣,可檢視文末知識點

const serverTitleMixin = { 
  created () {
    const title = getTitle(this)
    if (title) {
      this.$ssrContext.title = `Vue HN 2.0 | ${title}`
    }
  }
}

const clientTitleMixin = { 
  mounted () {
    const title = getTitle(this)
    if (title) {
      document.title = `Vue HN 2.0 | ${title}`
    }
  }
}

export default process.env.VUE_ENV === `server`
  ? serverTitleMixin
  : clientTitleMixin

複製程式碼

  檔案 src/app.js 在這裡全域性引入 Mixin

...
import titleMixin from `./util/title`
...
// mixin for handling title
Vue.mixin(titleMixin)
...
複製程式碼

  這裡是預設 title 的地方src/server.js

...
//在render函式裡
  const context = {
    title: `Vue HN 2.0`, // default title
    url: req.url
  }
...
複製程式碼

  具體元件裡的用法 src/views/UserView.vue

export default {
  name: `user-view`,
  ...
  title () {
    return this.user
      ? this.user.id
      : `User not found`
  },
  ...
}
複製程式碼

Head Mixin的改造過程

  首先是明確我的需求,如文章開頭所說,僅僅是 title 是不符合我的需求的,我還需要能夠自定義 description,author,keywords。

元件裡用法

  尤大大的 title 是返回一個字串,我把我需要的塞到了一個物件裡,需要自定義的就 return 出去,不需要的就還是預設的就行。

export default {
  name: `article-list`,
  ...
  head(){
      return {
        `title`: `文章列表`,
        `author`: `大俠`
      };
    },
  ...
}

複製程式碼

預設的頭資訊

  同樣在 server.js

// 同樣也在render 函式裡
  const context = {
    `title`: `可愛王`, // 預設title
    `author`: `Anne`, // 預設author
    `keywords`: `我是keywords`, // 預設keywords
    `description`: `我是description`, //預設description 
    `url`: req.url // 我是重要的一行程式碼,但是我跟這篇文章沒關係
  };// 沒錯我很無聊,打了這麼多無聊的註釋
複製程式碼

引入全域性head mixin

  同樣在 src/main.js

import headMixin from `./utils/head`;
// head()
Vue.mixin(headMixin);
複製程式碼

定義head Mixin

  在 src/utils/head.js 裡,在這裡是判斷了是否有 head,是否有各個我需要的東西,有就載入新的,沒有就還是預設的。

function getHead (vm) {
  const { head } = vm.$options;

  if (head) {
    return typeof head === `function` ?
      head.call(vm) :
      head;
  }
}

const serverHeadMixin = {
  created () {
    const head = getHead(this);

    if (head) {
      if (head.title) this.$ssrContext.title = `${head.title}-可愛王`;
      if (head.author) this.$ssrContext.author = `${head.author}-可愛王`;
      if (head.keywords) this.$ssrContext.keywords = head.keywords;
      if (head.description) this.$ssrContext.description = head.description;
    }
  }
};

const clientHeadMixin = {
  mounted () {
    const head = getHead(this);

    if (head) {
      if (head.title) document.title = `${head.title}-可愛王`;
      if (head.author) document.querySelector(`meta[name="author"]`).setAttribute(`content`, `${head.author}-可愛王`);
      if (head.keywords) document.querySelector(`meta[name="keywords"]`).setAttribute(`content`, head.keywords);
      if (head.description) document.querySelector(`meta[name="description"]`).setAttribute(`content`, head.description);
    }
  }
};

export default process.env.VUE_ENV === `server` ?
  serverHeadMixin :
  clientHeadMixin;
複製程式碼

知識點一:混入 (mixins)

  在做這個專案之前,我沒有用過這個東西,傳送門5: vue官方文件對混入的介紹

混入 (mixins) 是一種分發 Vue 元件中可複用功能的非常靈活的方式。混入物件可以包含任意元件選項。當元件使用混入物件時,所有混入物件的選項將被混入該元件本身的選項。

  簡而言之,就是你可以自定義一個鉤子函式,在每一個 Vue 例項裡引用,比如這篇文章裡提到的 head() , 帥呆了。

知識點二:伺服器端渲染與客戶端渲染的生命週期不同

  在所有的生命週期鉤子函式裡,只有 beforeCreatecreated 會在伺服器端渲染過程中呼叫,官方文件有提到這個,所以在開發過程中要一定要注意這點。

完!

Vue-SSR: head Mixin 實現頭部資訊管理

題外話:關於未來文章的規劃

  ?如果你還在看的話,幫忙留個言吧! 上週的文章在掘金得到了一百多個贊,開心,特別感謝我的朋友 Dylan 同學的糾錯以及掘金網友 Auroral 提醒遞迴優化的例項程式碼與 deepclone 無關聯。前端從業兩年多,一直沒有輸出文章,上週突發奇想要整理出自己的部落格,能夠梳理自己的知識,分享出來也能夠幫助到大家, 也希望自己能夠堅持下去。想寫的太多,精力有限,我想列一些想寫的文章,一篇一篇的出,走過路過如果看到了這篇文章,可以評論一下哪篇是你想看的,民意比較多的我就先寫啦。<( ̄︶ ̄)>

  1. vue 單頁應用的多 layout 實現

  2. 從零到一:用 webpack4 搭一個 vue 專案

  3. 從零到一:用 vue-cli3 搭一個專案

  4. 從零到一:用 nuxt 搭一個 vue-ssr 專案

  5. 從零到一:用 github 和 hexo 搭一個自己的線上部落格

  6. Vue-ssr 系列 基於 vue-hacknhews 2.0 想到什麼寫什麼咯

  7. 前端開發中一些實用的工具類網站

    從零到一已經有很多人寫過啦,但我還是列到了列表裡,如果不幸勝出了,我就盡力寫的不同一些吧。

相關文章