您現在的位置是:首頁 > 藝術
Vue 服務端渲染原理解析與入門實戰
渲染資料是什麼意思
開篇
在開始之前我們需要先來搞清楚一個問題:什麼是服務端渲染 ?
在以往的概念裡,渲染的工作更多的是放在客戶端進行的,那麼為什麼現在我們要讓服務端來做這個工作?
服務端渲染和客戶端渲染有什麼不同之處嗎?
其實服務端渲染的工具有很多,看著手冊很快就能上手,並沒有什麼難度,關鍵在於,我們什麼場景下需要使用服務端渲染,什麼樣的渲染方案更適合我們的專案;知其然,知其所以然,我們需要先搞清楚服務端渲染的基本概念和原理,服務端渲染為什麼會出現,到底解決了我們的什麼問題,掌握整體的渲染邏輯和思路,我們才能在學習工具使用時,輕鬆自在,而即便以後工具有了變化和更新,我們也能得心應手,不會再說 “學不動” 了;
這個邏輯就是所謂的道、法、術、器的概念;不要僅僅停留在工具的使用和一些工具的奇技淫巧中,更多的要向法、道的層面成長;
什麼是 SSR ?
現代化的前端專案,大部分都是單頁應用程式,也就是我們說的 SPA ,整個應用只有一個頁面,透過元件的方式,展示不同的頁面內容,所有的資料透過請求伺服器獲取後,在進行客戶端的拼裝和展示;這就是目前前端框架的預設渲染邏輯,我們稱為:客戶端渲染方案( Client Side Render 簡稱:CSR );
載入渲染過程如下:HTML/CSS 程式碼 ——> 載入 JavaScript 程式碼 ——> 執行 JavaScript 程式碼 ——> 渲染頁面資料
SPA 應用的客戶端渲染方式,最大的問題有兩個方面:
1:白屏時間過長,使用者體驗不好;
2:HTML 中無內容,SEO 不友好;
這個問題的原因在於,首次載入時,需要先下載整個 SPA 指令碼程式,瀏覽器執行程式碼邏輯後,才能去獲取頁面真正要展示的資料,而 SPA 指令碼的下載需要較長的等待和執行時間,同時,下載到瀏覽器的 SPA 指令碼是沒有頁面資料的, 瀏覽器實際並沒有太多的渲染工作,因此使用者看到的是沒有任何內容的頁面,不僅如此,因為頁面中沒有內容,搜尋引擎的爬蟲爬到的也是空白的內容,也就不利於 SEO 關鍵字的獲取;
相較於傳統的站點,瀏覽器獲取到的頁面都是經過伺服器處理的有內容的靜態頁面,有過後端程式設計經驗的可能會比較熟悉一些,頁面結構和內容,都是透過伺服器處理後,返回給客戶端;
全宇宙首發動圖,全流程展現
兩相比較我們會發現,傳統站點的頁面資料合成在後臺伺服器,而 SPA 應用的頁面資料合成在瀏覽器,但是無論那種,最終的渲染展示,還是交給瀏覽器完成的,所以,不要誤會,我們這裡所說的 服務端渲染 和 客戶端渲染,指的是頁面結構和資料合成的工作,不是瀏覽器展示的工作;
那麼能不能借助傳統網站的思路來解決 SPA 的問題又能夠保留SPA的優勢呢?不管是白屏時間長還是 SEO 不友好,實際都是首屏的頁面結構先回到瀏覽器,然後再獲取資料後合成導致的問題,那麼,首屏的頁面結構和資料,只要像傳統站點一樣,先在服務端合成後再返回,同時將 SPA 指令碼的載入依然放到首屏中,此時返回的頁面就是結構和資料都有的完整內容了,這樣瀏覽器在展示首頁資料的同時也能載入 SPA 指令碼,搜尋引擎的爬蟲同樣也能獲取到對應的資料,解決 SEO 的問題;為了更好的理解這個邏輯,我畫了一個流程圖:
沒錯,這就是我們所說的 服務端渲染的基本邏輯,服務端渲染也就是 SSR (Server Side Rendering) ;
白屏時間過長的問題得以解決,因為首次載入時,伺服器會先將渲染好的靜態頁面返回,在靜態頁面中再次載入請求 SPA 指令碼;
基本原理:首頁內容及資料,在使用者請求之前生成為靜態頁面,同時加入 SPA 的指令碼程式碼引入,在瀏覽器渲染完成靜態頁面後,請求 SPA 指令碼應用,之後的頁面互動依然是客戶端渲染;
明白了其中的原理,也就是到了道、法的境界,接下來,讓我們下凡進入術、器的應用層面感受一下;
其中 Vue 框架和 React 框架都有對應的比較成熟的 SSR 解決方案,React對應的是 Next。js 框架,Vue 對應的就是 Nuxt。js,當然,如果你對這些都不感興趣,也可以自己實現一個 SSR 的服務端應用,我自己之前也寫過一個,如果你感興趣,想看看我實現的程式碼,可以留言給我,回頭做成教程發出來;
我們以 Vue 對應的 Nuxt。js 為例,來具體感受服務端渲染;
Nuxt。js 應用
Nuxt。js 是一個基於 Vue。js 的通用應用框架。Nuxt。js 預設了利用 Vue。js 開發
服務端渲染
的應用所需要的各種配置,為基於 Vue。js 的應用提供生成對應的靜態站點的功能。開啟 Nuxt。js官網:https://www。nuxtjs。cn/ ,學習指南寫的非常詳細且通俗易懂,根據指南,我們可以看到有兩種安裝方式,一種使用 create-nuxt-app 腳手架工具,另一種是自己手動建立;
安裝
腳手架安裝
接下來我們分別嘗試不同的安裝方式,先使用腳手架進行安裝,執行命令 :npx create-nuxt-app creact-nuxt
接著,在命令列中會有很多的選擇項,分別有專案名稱、開發語言、UI元件庫、伺服器框架、測試框架、HTTP請求庫等等,可以根據自己的需要進行不同的選擇,安裝成功過後,命令列中會給出對應的提示資訊。
我們可以根據提示資訊,執行專案,專案有開發環境和生產環境兩種執行方式,開發環境下直接使用 npm run dev 即可,而要執行生產環境,則需要先進行 build 編譯,編譯成功後才能開啟專案執行;
因為專案是剛剛初始化的,我們並沒有寫任何內容,所以,不管使用那種執行方式,我們能看到的都是下面這個頁面內容;
手動安裝
不同於腳手架安裝,手動安裝需要我們自己建立專案並安裝所需擴充套件和外掛,還需要我們自己寫好元件程式碼,然後配置執行命令,才能啟動執行,但是,手動建立更加考驗大家對專案的整體把控能力;
執行命令:mkdir nuxtnpm 建立資料夾後,切換目錄:cd nuxtnpm ;
然後執行命令:npm init -y 建立專案並生成 package。json 檔案;
使用命令:npm install nuxt ——save 安裝 Nuxt。js 框架;
在 nuxtnpm 目錄中,建立 pages 目錄及 pages/index。vue 元件檔案,在元件檔案中,寫如下程式碼,打聲招呼:
嗨 Nuxt。js
exportdefault {
}
最後,我們還要在 package。json 檔案中,配置執行命令的指令碼引數:
“scripts”: {
“test”: “echo \”Error: no test specified\“ && exit 1”,
“dev”: “nuxt”,
“build”: “nuxt build”,
“start”: “nuxt start”,
“generate”: “nuxt generate”
},
配置好命令引數後,就和前面的執行套路是一樣的了:
npm run dev 啟動一個熱載入的 Web 伺服器(開發模式)
npm run build 編譯專案,利用 webpack 編譯應用,壓縮 JS 和 CSS 資源(釋出用);
npm run start 以生產模式啟動一個 Web 伺服器 (需要先進行專案編譯)。
專案執行後,我們就可以看到剛剛寫的元件內容了;
需要注意的是,pages 目錄是必須的,Nuxt。js 框架會自動讀取該目錄下所有的 。vue 檔案並自動生成對應的路由配置。
路由
基礎路由
基礎路由不需要配置,Nuxt。js 會根據 pages 中的資料夾及檔案,自動生成的路由配置
假設 pages 的目錄結構如下:
pages/
——| user/
——-| index。vue
——-| one。vue
——| index。vue
那麼,Nuxt。js 自動生成的路由配置如下:
router: {
routes: [
{
name: ‘index’,
path: ‘/’,
component: ‘pages/index。vue’
},
{
name: ‘user’,
path: ‘/user’,
component: ‘pages/user/index。vue’
},
{
name: ‘user-one’,
path: ‘/user/one’,
component: ‘pages/user/one。vue’
}
]
}
同樣的,在 /。nuxt/router。js 檔案中,我們也能夠看到相關內容;
路由導航
Nuxt 中的路由導航有三種方式,一種就是普通的 a 標籤跳轉,太過於基礎這裡就不說了,兩外兩種分別是 nuxt-link 元件和程式設計式導航,nuxt-link 元件用於在頁面中新增連結跳轉到其他頁面,目前
而程式設計式導航的用法,同樣與 Vue 中的使用方式一致:
nuxt-link 跳轉:
程式設計式導航 跳轉:
importaxiosfrom‘axios’
exportdefault {
methods:{
clickBtn(){
this。$router。push(‘/user’)
}
}
}
動態路由
在 Nuxt。js 裡面定義帶引數的動態路由,需要建立對應的
以下劃線作為字首
的 Vue 檔案 或 目錄。
下劃線後面的名字隨意命名,但是在獲取動態路由引數時,檔案的名字就是獲取的關鍵字,用法與 Vue-Router 基本一致:
\pages\user_kk.vue
動態路由-route
<!—— 獲取引數,列印 ——>
獲取引數,列印:{{$route。params。kk}}
控制檯也有輸出
exportdefault {
mounted(){
// 獲取路由引數,控制檯列印
console。log(this。$route。params。kk)
}
}
。mis{
background: coral;
}
訪問:http://localhost:3000/user/3
在 Nuxt。js 執行 generate 命令時,動態路由會被忽略,(後面重點講)
巢狀路由
你可以透過 vue-router 的子路由建立 Nuxt。js 應用的巢狀路由。建立內嵌子路由,需要新增一個 Vue 檔案,同時新增一個
與該檔案同名
的目錄用來存放子檢視元件。在父元件(。vue檔案) 內增加
父元件檔案內容
\pages\order.vue
巢狀路由
<!—— 用於顯示子檢視內容 ——>
exportdefault {
}
巢狀子元件檔案及內容
\pages\order\index.vue
巢狀元件預設顯示,訪問路徑:http://localhost:3000/order
巢狀子路由 - index
exportdefault {
}
\pages\order\info.vue
訪問路徑:http://localhost:3000/order/info
order->info
\pages\order\list.vue
訪問路徑:http://localhost:3000/order/list
order-> list
{{dataObj[0]。name}}
importaxiosfrom‘axios’
exportdefault {
asyncasyncData({ params }) {
// 傳送請求,獲取資料
const { data } =awaitaxios。get(`http://127。0。0。1`);
// 解析資料
constdataObj=JSON。parse(data);
// 返回資料後,Nuxt 會合並data方法的資料給元件,無需額外程式碼
return { dataObj };
},
}
非同步資料-asyncData
Nuxt。js 擴充套件了 Vue。js,增加了一個叫 asyncData 的方法,使得我們可以在設定元件的資料之前能非同步獲取或處理資料。asyncData 方法會在元件(
限於頁面元件
)每次載入之前被呼叫。它可以在服務端或路由更新之前被呼叫。Nuxt。js 會將 asyncData 返回的資料融合元件 data 方法返回的資料一併返回給當前元件。
user-index page
<!—— 遍歷展示資料 ——>
{{ v。name }}
importaxiosfrom“axios”;
exportdefault {
asyncasyncData({ params }) {
// 傳送請求,獲取資料
const { data } =awaitaxios。get(`http://127。0。0。1`);
// 解析資料
constdataObj=JSON。parse(data);
// 返回資料後,Nuxt 會合並data方法的資料給元件,無需額外程式碼
return { dataObj };
},
};
Nuxt。js 對 SSG 的支援
在開始之前,我們需要先了解 SSG 的含義,SSG(
Static Site Generators
):靜態站點生成。
就是將應用中用到的所有頁面,全部生成靜態檔案的方案;靜態站點生成方案,更適合 CDN、快取、內容資料無變化的頁面,比如:宣傳頁、部落格文章、幫助文件、新聞頁面、電商產品列表等眾多應用場景;因為頁面都是事先生成好的,一次構建,反覆使用,訪問速度快。
那麼,在 Nuxt。js 中如何將應用靜態化匯出呢?npm run generate 命令就是用來專門做靜態匯出的,這個命令執行後,Nuxt 會根據路由配置,將應用的全部內容生成對應的 HTML 靜態站點資源,這個命令會建立一個 dist 資料夾,所有靜態化後的資原始檔均在其中。
前面說
在 Nuxt.js 執行 generate 命令時,動態路由會被忽略。
動態路由手動配置
如果想讓 Nuxt。js 為動態路由也生成靜態檔案,需要指定動態路由引數的值,並配置到 routes 陣列中去。
我們可以在 nuxt。config。js 中為 /users/:id 路由配置如下:
module。exports= {
generate: {
routes: [‘/users/1’, ‘/users/2’, ‘/users/3’]
}
}
動態路由資料生成
但是如果路由
動態引數
的值是動態的而不是固定的,應該怎麼做呢?
可以使用一個返回 Promise 物件型別的 函式,意思就是,傳送請求獲取所有資料,根據返回的資料,生成所有可能的路由,再根據所有路由,生成全部的靜態檔案
nuxt.config.js
constaxios=require(‘axios’)
module。exports= {
generate: {
// 生成路由檔案,而不是目錄
subFolders:false,
routes() {
// 請求資料
returnaxios。get(‘http://127。0。0。1:80/three’)。then(res=> {
constresData=JSON。parse(res。data);
returnresData。map(user=> {
// 拼裝路由
return‘/user/’+user。id
})
})
}
}
}
非同步資料-asyncData 與 mounted 的區別
mounted 在靜態站點生成時,不會執行獲取資料,程式碼會被編譯進靜態生成的 JS 中,瀏覽器渲染時才會被執行,
asyncData 在匯出靜態站點時,會執行程式碼,並將資料直接編譯進 HTML 中,程式碼不會編譯到靜態檔案的 JS 中;
相關文章
推薦文章
- 自己花自己的錢還是被丈夫說,這種男人是什麼心理?
所以,你買什麼、你老公都會覺得很奢侈...
- 描繪美麗城鎮“五美”新圖景
據悉,自美麗城鎮建立以來,鹽官鎮共安置農戶594戶,目前,多個公寓房專案正在同時建設,預計可提供農戶安置房1700餘套...
- 再次還原江直樹與袁湘琴愛情故事,甜到牙縫裡!
哈嘍,大家好,我是你的風趣幽默的小編,我又來了,現在有有部電視劇不知道各位小夥伴們看過沒有,那就是《一吻定情》,大家不知道有沒有看過電視劇版的《惡作劇之吻》,哇哦,那部電視劇也著實太甜了,簡直看的時候小鹿亂撞的感覺有沒有,大家是不是也可喜歡...