全棧開發(fā)—博客前端展示(Nuxt.js)

個(gè)人博客開發(fā)系列文章:

全棧開發(fā)—博客前端展示(Nuxt.js)

這個(gè)開發(fā)的想法是這樣來的,大概兩個(gè)月前,騰訊云的工作人員打電話給我,說我的域名沒有解析到騰訊云的服務(wù)器上,而且頁腳也沒有備案號。我當(dāng)時(shí)就震驚了,居然會打電話給我,然而我的大學(xué)時(shí)代買的服務(wù)器已經(jīng)過期了...于是為了拯救我的域名,拯救我申請了很久的備案號,決意要全棧打造一個(gè)屬于自己的博客系統(tǒng)。

主要技術(shù)

  • Nuxt.js
  • Axios
  • marked + highlight.js
  • scss

項(xiàng)目特點(diǎn)

  • 適配多個(gè)分辨率,移動端到桌面端無縫切換
  • 支持白晝黑夜主題切換(試試點(diǎn)擊shirmy的太陽或月亮)
  • 文章圖片懶加載
  • 評論、留言、搜索、點(diǎn)贊、多個(gè)作者
  • SSR服務(wù)端渲染(seo)

技術(shù)總結(jié)

什么是服務(wù)端渲染(server side render)?

服務(wù)端渲染則把Ajax請求放到服務(wù)端,頁面加載到瀏覽器或客戶端前就已經(jīng)把數(shù)據(jù)填充到頁面模板行程完整的頁面。

優(yōu)勢

  • 減少首次http請求,在服務(wù)端請求首屏數(shù)據(jù),直接渲染html
  • 利于SEO,網(wǎng)絡(luò)爬蟲可以抓取到完整的頁面信息

劣勢

  • 服務(wù)端壓力大
  • 需要掌握從前端到服務(wù)端的開發(fā)(多學(xué)點(diǎn)不好嗎?)

什么是客戶端渲染(client side render)?

客戶端渲染就是就是在客戶端通過Ajax請求獲取數(shù)據(jù),然后在客戶端生成DOM插入到html

優(yōu)勢

  • 前后端分離,各司其職
  • 局部刷新,無需重新刷新頁面
  • 服務(wù)器壓力小
  • 更好的實(shí)現(xiàn)各種前端效果

劣勢

  • 首屏渲染慢,需要下載JSCSS文件
  • 不利于SEO,爬蟲抓取不到完整的頁面數(shù)據(jù)

SSR vs CSR

門戶網(wǎng)站、博客網(wǎng)站等需要SEO優(yōu)化的網(wǎng)站使用服務(wù)端渲染,管理后臺等內(nèi)部系統(tǒng)或不需要SEO優(yōu)化的網(wǎng)站使用客戶端渲染

對比圖

服務(wù)端渲染
前端渲染

如何實(shí)現(xiàn)白晝黑夜主題切換?

在這里,要使用CSS3變量配合scss進(jìn)行控制,通過控制<body>標(biāo)簽的id來約束白晝或黑夜的顏色值,再給相應(yīng)的屬性加上transition屬性實(shí)現(xiàn)顏色切換時(shí)的過渡,請看下面的示例:

@mixin theme(
  $theme-primary
) {
  --theme-primary: #{$theme-primary}
}

body {
  &#light {
    @include theme(
      #theme-primary: #fff,
    )
  }

  &#dark {
    @include theme(
      #theme-primary: #000,
    )
  }
}

全局引入上面的scss文件,這樣就可以直接通過設(shè)置<body>標(biāo)簽的id的值為darklight--theme-primary賦予不同的顏色值,此時(shí)就能直接在需要應(yīng)用該顏色的元素上進(jìn)行如下設(shè)置:

.example-class {
  color: var(--theme-primary);
}

在我的博客shirmy中點(diǎn)擊月亮/太陽即可看到效果,亦可用同樣的方式定義多套主題色。

切換頁面改變頁面title

Nuxt內(nèi)置了head屬性配置,head配置直接修改根目錄下的nuxt.config.js文件就可以了,并且還內(nèi)置vue-meta插件,因此想要在不同頁面改變相應(yīng)的title,請看以下做法:

// nuxt.config.js
module.exports = {
  head: {
    // 組件中的 head() 方法返回的字符串會替換 %s
    titleTemplate: '%s | shirmy',
  }
}

// 文章詳情頁 pages/article/_id.vue
export default {
  head() {
    return {
      title: this.article.title
    }
  }
}

如此一來,當(dāng)查看某篇文章詳情的時(shí)候就會觸發(fā)head()方法,title顯示為article title | shirmy

切換頁面讓頁面滾動保持在頂部

只要修改nuxt.config.js配置即可,并且可以根據(jù)傳入的參數(shù)做一些自定義的配置。

// nuxt.config.js
module.exports = {
  router: {
    scrollBehavior: function (to, from, savedPosition) {
      return { x: 0, y: 0 }
    }
  },
}

Nuxt中的fetch()

fetch()Nuxt中獨(dú)有的方法,它會在組件初始化前被調(diào)用,因此無法通過this獲取組件對象。比如進(jìn)入首頁或從首頁切換到歸檔頁,在進(jìn)入頁面前會先執(zhí)行fetch()方法,為了異步獲取數(shù)據(jù),fetch()方法必須返回Promise,因此可以直接返回一個(gè)Promise或者使用async await(async await其本質(zhì)就是返回Promise)。

該方法不會設(shè)置組件的數(shù)據(jù),如果想要設(shè)置組件的數(shù)據(jù),或者使用context上下文,可以使用asyncData

export default {
  // 雖然無法通過 this.$nuxt.$route 獲取路由參數(shù),但是可以通過 params 來獲取
  async fetch({ store, params }) {
    await store.dispatch('about/getAuthor', params.id)
    await store.dispatch('about/getArticles', {
      authorId: params.id,
      page: 0
    })
  }
}

這樣就能確保內(nèi)容已經(jīng)渲染好再下載到瀏覽器,如果使用mounted等生命周期鉤子,則是在頁面下載到瀏覽器后再獲取數(shù)據(jù),起不到SSR服務(wù)端渲染的效果。

style-resource

為了方便統(tǒng)一管理scss變量,通常會在目錄中創(chuàng)建variables.scssmixin.scss,但是我們寫的vue文件這么多,如果都要一個(gè)個(gè)導(dǎo)入豈不是吃力不討好,這時(shí)可以借助style-resource

npm install -S @nuxtjs/style-resources

修改nuxt.config.js文件:

// nuxt.config.js
module.exports = {
  styleResources: {
    scss: ['./assets/scss/variables.scss', './assets/scss/mixin.scss']
  }
},

圖片懶加載

圖片懶加載的關(guān)鍵是使用IntersectionObserver,IE瀏覽器不兼容,需要使用polyfill。該WebAPI用于監(jiān)聽元素是否出現(xiàn)在頂級文檔視窗中。

通過這個(gè)WebAPI,我們可以把<img>標(biāo)簽的src屬性地址先掛在data-src屬性上,當(dāng)該元素出現(xiàn)在視窗時(shí)就會觸發(fā)IntersectionObserver的的回調(diào)方法,此時(shí)再給<img>標(biāo)簽的src屬性賦予先前掛在data-src上的地址

復(fù)制時(shí)攜帶轉(zhuǎn)載聲明

監(jiān)聽copy事件,然后通過getSelection()方法獲取復(fù)制的內(nèi)容,在通過clipboardDatasetData()方法在復(fù)制內(nèi)容上加上轉(zhuǎn)載信息:

if (process.env.NODE_ENV === 'production') {
  const copyText = `

---------------------
作者:shirmy
鏈接:${location.href}
來源:https://www.shirmy.me
商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。`

  document.addEventListener('copy', e => {
    if (!window.getSelection) {
      return
    }
    const content = window.getSelection().toString()

    e.clipboardData.setData('text/plain', content + copyText)
    e.clipboardData.setData('text/html', content + copyText)
    e.preventDefault()
  })
}

markdown防止XSS攻擊

如果讀者在評論中輸入<script>alert('xss')</script>,那么進(jìn)入文章詳情頁時(shí)就會觸發(fā)這段代碼,這時(shí)候,我們就需要把script過濾掉,當(dāng)然XSS還有許多類似的方式,但是萬變不離其宗

在這里,我借助了DOMPurify

npm install dompurify -S
DOMPurify.sanitize(html)

使用谷歌分析服務(wù)

首先進(jìn)入官網(wǎng)Google 統(tǒng)計(jì)分析服務(wù),并注冊你的賬號,得到一個(gè)格式如GA_MEASUREMENT_ID的媒體資源ID

然后直接修改nuxt.config.js,當(dāng)然也可以自定義(gtag.js開發(fā)指南):

// nuxt.config.js
module.exports = {
  head: {
    // 其它配置...
    script: [
      // 其它配置...
      {
        async: 'async',
        type: 'text/javascript',
        // GA_MEASUREMENT_ID 替換為你剛剛注冊得到的媒體資源ID
        src: 'https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID'
      },
      {
        // Global site tag (gtag.js) - Google Analytics
        type: 'text/javascript',
        // GA_MEASUREMENT_ID 替換為你剛剛注冊得到的媒體資源ID
        innerHTML: `
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());

          gtag('config', 'GA_MEASUREMENT_ID');
        `
      }
    ]
  }
}

參考文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,983評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內(nèi)容