個(gè)人博客開發(fā)系列文章:
- 博客前端展示總結(jié):http://www.lxweimin.com/p/1348bcd1e716
- 后臺管理系統(tǒng)總結(jié):http://www.lxweimin.com/p/53c75476be44
- 服務(wù)端總結(jié):http://www.lxweimin.com/p/c25b5432d6f5
- Travis CI持續(xù)集成:http://www.lxweimin.com/p/4e7a06e18bd5
- 使用Nginx配置HTTPS和反向代理:http://www.lxweimin.com/p/c779e54c9f85
全棧開發(fā)—博客前端展示(Nuxt.js)
這個(gè)開發(fā)的想法是這樣來的,大概兩個(gè)月前,騰訊云的工作人員打電話給我,說我的域名沒有解析到騰訊云的服務(wù)器上,而且頁腳也沒有備案號。我當(dāng)時(shí)就震驚了,居然會打電話給我,然而我的大學(xué)時(shí)代買的服務(wù)器已經(jīng)過期了...于是為了拯救我的域名,拯救我申請了很久的備案號,決意要全棧打造一個(gè)屬于自己的博客系統(tǒng)。
- 博客地址:shirmy
- 項(xiàng)目地址:smile-blog-nuxt
主要技術(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)各種前端效果
劣勢
- 首屏渲染慢,需要下載
JS
和CSS
文件 - 不利于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)站使用客戶端渲染
對比圖
如何實(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
的值為dark
或light
給--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.scss
和mixin.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)容,在通過clipboardData
的setData()
方法在復(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');
`
}
]
}
}
參考文檔