摘要:根據(jù)官方文檔在文件下面創(chuàng)建兩個文件,分別是和。在中可以直接使用,并且是默認(rèn)啟用命名空間的。在中觸發(fā)熱更新。使用中間件中間件沒有給出具體的使用文檔,而是放入了一個編輯器。對配置有興趣的可以在官方文檔找到渲染文檔。
Nuxt是解決SEO的比較常用的解決方案,隨著Nuxt也有很多坑,每當(dāng)突破一個小技術(shù)點的時候,都有很大的成就感,在這段時間里著實讓我痛并快樂著。在這里根據(jù)個人學(xué)習(xí)情況,所踩過的坑做了一個匯總和總結(jié)。
Nuxt開發(fā)跨域
項目可以使用Nginx來反向代理,將外來的請求(這里也注意下將Linux的防火墻放行相應(yīng)端口)轉(zhuǎn)發(fā)的內(nèi)部Nuxt默認(rèn)的3000端口上,最簡單的配置文件如下:
nuxtjs.config.js
{ modules: [ "@nuxtjs/axios", "@nuxtjs/proxy" ], proxy: [ [ "/api", { target: "http://localhost:3001", // api主機 pathRewrite: { "^/api" : "/" } } ] ] }
@nuxtjs/proxy需要手動多帶帶安裝。
Nuxt Store 使用
在Nuxt中使用Vuex跟傳統(tǒng)在Vue中使用Vuex還不太一樣,首先Nuxt已經(jīng)集成了Vuex,不需要我們進行二次安裝,直接引用就好,在默認(rèn)Nuxt的框架模板下有一個Store的文件夾,就是我們用來存放Vuex的地方。
Nuxt官方也提供了相關(guān)文檔,可以簡單的過一下,但是官方文檔我看來比較潦草。
根據(jù)官方文檔在store文件下面創(chuàng)建兩個.js文件,分別是index.js和todo.js。并在pages文件夾下面創(chuàng)建index.vue。
store - index.js
export const state = () => ({ counter: 0 }) export const mutations = { increment (state) { state.counter++ } }
store - todo.js
export const state = () => ({ list: [] }) export const mutations = { add (state, text) { state.list.push({ text: text, done: false }) }, remove (state, { todo }) { state.list.splice(state.list.indexOf(todo), 1) }, toggle (state, todo) { todo.done = !todo.done } }
pages - index.vue
{{counter}}
- {{item.text}}
在Nuxt中可以直接使用this.$store,并且是默認(rèn)啟用命名空間的。再看一下computed中的代碼,在使用mapState的時候,counter屬性是直接獲取出來的,然而todos屬性則是通過命名空間才獲取到的。這又是怎么回事?
Nuxt把store中的index.js文件中所有的state、mutations、actions、getters都作為其公共屬性掛載到了,store實例上,然而其他的文件則是使用的是命名空間,其對應(yīng)的命名空間的名字就是其文件名。
運行項目的時候可以在.nuxt文件夾內(nèi)找到store.js看下是怎么完成的。簡單的解釋一下代碼作用,以及做什么用的。
.nuxt - store.js
// 引入vue import Vue from "vue" // 引入vuex import Vuex from "vuex" // 作為中間件 Vue.use(Vuex) // 保存console 函數(shù) const log = console // vuex的屬性 const VUEX_PROPERTIES = ["state", "getters", "actions", "mutations"] // store屬性容器 let store = {} // 沒有返回值的自執(zhí)行函數(shù) void (function updateModules() { // 初始化根數(shù)據(jù),也就是上面所說的index文件做為共有數(shù)據(jù) store = normalizeRoot(require("@/store/index.js"), "store/index.js") // 如果store是函數(shù),提示異常,停止執(zhí)行 if (typeof store === "function") { // 警告:經(jīng)典模式的商店是不贊成的,并將刪除在Nuxt 3。 return log.warn("Classic mode for store is deprecated and will be removed in Nuxt 3.") } // 執(zhí)行存儲模塊 // store - 模塊化 store.modules = store.modules || {} // 解決存儲模塊方法 // 引入todos.js 文件,即數(shù)據(jù) // "todos.js" 文件名 resolveStoreModules(require("@/store/todos.js"), "todos.js") // 如果環(huán)境支持熱重載 if (process.client && module.hot) { // 無論何時更新Vuex模塊 module.hot.accept([ "@/store/index.js", "@/store/todos.js", ], () => { // 更新的根。模塊的最新定義。 updateModules() // 在store中觸發(fā)熱更新。 window.$nuxt.$store.hotUpdate(store) }) } })() // 創(chuàng)建store實例 // - 如果 store 是 function 則使用 store // - 否則創(chuàng)建一個新的實例 export const createStore = store instanceof Function ? store : () => { // 返回實例 return new Vuex.Store(Object.assign({ strict: (process.env.NODE_ENV !== "production") }, store)) } // 解決存儲模塊方法 // moduleData - 導(dǎo)出數(shù)據(jù) // filename - 文件名 function resolveStoreModules(moduleData, filename) { // 獲取導(dǎo)出數(shù)據(jù),為了解決es6 (export default)導(dǎo)出 moduleData = moduleData.default || moduleData // 遠(yuǎn)程store src +擴展(./foo/index.js -> foo/index) const namespace = filename.replace(/.(js|mjs|ts)$/, "") // 空間名稱 const namespaces = namespace.split("/") // 模塊名稱(state,getters等) let moduleName = namespaces[namespaces.length - 1] // 文件路徑 const filePath = `store/${filename}` // 如果 moduleName === "state" // - 執(zhí)行 normalizeState - 正常狀態(tài) // - 執(zhí)行 normalizeModule - 標(biāo)準(zhǔn)化模塊 moduleData = moduleName === "state" ? normalizeState(moduleData, filePath) : normalizeModule(moduleData, filePath) // 如果是 (state,getters等)執(zhí)行 if (VUEX_PROPERTIES.includes(moduleName)) { // module名稱 const property = moduleName // 存儲模塊 // 獲取存儲模塊 const storeModule = getStoreModule(store, namespaces, { isProperty: true }) // 合并屬性 mergeProperty(storeModule, moduleData, property) // 取消后續(xù)代碼執(zhí)行 return } // 特殊處理index.js // 模塊名稱等于index const isIndexModule = (moduleName === "index") // 如果等于 if (isIndexModule) { // 名稱空間彈出最后一個 namespaces.pop() // 獲取模塊名稱 moduleName = namespaces[namespaces.length - 1] } // 獲取存儲模塊 const storeModule = getStoreModule(store, namespaces) // 遍歷 VUEX_PROPERTIES for (const property of VUEX_PROPERTIES) { // 合并屬性 // storeModule - 存儲模塊 // moduleData[property] - 存儲模塊中的某個屬性數(shù)據(jù) // property - 模塊名稱 mergeProperty(storeModule, moduleData[property], property) } // 如果moduleData.namespaced === false if (moduleData.namespaced === false) { // 刪除命名空間 delete storeModule.namespaced } } // 初始化根數(shù)據(jù) // moduleData - 導(dǎo)出數(shù)據(jù) // filePath - 文件路徑 function normalizeRoot(moduleData, filePath) { // 獲取導(dǎo)出數(shù)據(jù),為了解決es6 (export default)導(dǎo)出 moduleData = moduleData.default || moduleData // 如果導(dǎo)入的數(shù)據(jù)中存在commit方法,則拋出異常 // - 應(yīng)該導(dǎo)出一個返回Vuex實例的方法。 if (moduleData.commit) { throw new Error(`[nuxt] ${filePath} should export a method that returns a Vuex instance.`) } // 如果 moduleData 不是函數(shù),則使用空隊形進行合并處理 if (typeof moduleData !== "function") { // 避免鍵入錯誤:設(shè)置在覆蓋頂級鍵時只有g(shù)etter的屬性 moduleData = Object.assign({}, moduleData) } // 對模塊化進行處理后返回 return normalizeModule(moduleData, filePath) } // 正常狀態(tài) // - 模塊數(shù)據(jù) // - 文件路徑 function normalizeState(moduleData, filePath) { // 如果 moduleData 不是function if (typeof moduleData !== "function") { // 警告提示 // ${filePath}應(yīng)該導(dǎo)出一個返回對象的方法 log.warn(`${filePath} should export a method that returns an object`) // 合并 state const state = Object.assign({}, moduleData) // 以函數(shù)形式導(dǎo)出state return () => state } // 對模塊化進行處理 return normalizeModule(moduleData, filePath) } // 對模塊化進行處理 // moduleData - 導(dǎo)出數(shù)據(jù) // filePath - 文件路徑 function normalizeModule(moduleData, filePath) { // 如果module數(shù)據(jù)的state存在并且不是function警告提示 if (moduleData.state && typeof moduleData.state !== "function") { // “state”應(yīng)該是返回${filePath}中的對象的方法 log.warn(`"state" should be a method that returns an object in ${filePath}`) // 合并state const state = Object.assign({}, moduleData.state) // 覆蓋原有state使用函數(shù)返回 moduleData = Object.assign({}, moduleData, { state: () => state }) } // 返回初始化數(shù)據(jù) return moduleData } // 獲取store的Model // - storeModule store數(shù)據(jù)模型 // - namespaces 命名空間名稱數(shù)組 // - 是否使用命名空間 默認(rèn)值 為false function getStoreModule(storeModule, namespaces, { isProperty = false } = {}) { // 如果 namespaces 不存在,啟動命名空間,命名空間名稱長度1 if (!namespaces.length || (isProperty && namespaces.length === 1)) { // 返回model return storeModule } // 獲取命名空間名稱 const namespace = namespaces.shift() // 保存命名空間中的數(shù)據(jù) storeModule.modules[namespace] = storeModule.modules[namespace] || {} // 啟用命名空間 storeModule.modules[namespace].namespaced = true // 添加命名數(shù)據(jù) storeModule.modules[namespace].modules = storeModule.modules[namespace].modules || {} // 遞歸 return getStoreModule(storeModule.modules[namespace], namespaces, { isProperty }) } // 合并屬性 // storeModule - 存儲模塊 // moduleData - 存儲模屬性數(shù)據(jù) // property - 模塊名稱 function mergeProperty(storeModule, moduleData, property) { // 如果 moduleData 不存在推出程序 if (!moduleData) return // 如果 模塊名稱 是 state if (property === "state") { // 把state數(shù)據(jù)分到模塊空間內(nèi) storeModule.state = moduleData || storeModule.state } else { // 其他模塊 // 合并到對應(yīng)的模塊空間內(nèi) storeModule[property] = Object.assign({}, storeModule[property], moduleData) } }
以上就是編譯后的store文件,大致的意思就是對store文件進行遍歷處理,根據(jù)不同的文件使用不同的解決方案,使用命名空間掛載model。
頁面loading
Nuxt有提供加載Loading組件,一下是配置。
nuxtjs.config.js
module.exports = { loading: { color: "#3B8070" } }
Nuxt提供的loading不能滿足項目需求,可能有的項目不需要這樣加載動畫,so~,就需要自己手動配置一個。添加一個loading組件 (官方示例如下,詳情可看官方文檔)引用該組件。
nuxtjs.config.js
module.exports = { loading: "~components/loading.vue" }
一個小插曲在Nuxt中,~與@都指向的是根目錄。
components/loading.vue
Loading...
第三方組件庫
項目開發(fā)過程中,難免會用到組件庫,與在Vue中使用的時候是太一樣的,需要添加一些依賴才能正常使用。
plugins - element-ui.js
import Vue from "vue"; import Element from "element-ui"; import locale from "element-ui/lib/locale/lang/en"; export default () => { Vue.use(Element, { locale }) };
nuxtjs.config.js
module.exports = { css: [ "element-ui/lib/theme-chalk/index.css" ], plugins: [ "@/plugins/element-ui", "@/plugins/router" ] };
使用中間件
中間件Nuxt沒有給出具體的使用文檔,而是放入了一個編輯器。這一點我感覺到了一絲絲的 差異。為什么要這樣。。。簡單的研究了一下,弄明白了大概。
在middleware中創(chuàng)建想要的中間件。這里借用一下官網(wǎng)的例子。
middleware - visits.js
export default function ({ store, route, redirect }) { store.commit("ADD_VISIT", route.path) }
向上面這樣就創(chuàng)建好了一個中間件,但是應(yīng)該怎么使用呢?在使用的時候有兩種方式,一種是全局使用,另一種是在頁面中多帶帶使用,文件名會作為其中間件的名稱。
++全局使用++
nuxtjs.config.js
export default { router: { middleware: ["visits"] } }
頁面中多帶帶使用
export default { middleware: "auth" }
官網(wǎng)中在頁面中的asyncData中有一段這樣的代碼。
export default { asyncData({ store, route, userAgent }) { return { userAgent } } }
持續(xù)更新。。。
總結(jié)
Nuxt的學(xué)習(xí)曲線非常小,就像Vue框架一樣,已經(jīng)是一個開箱即用的狀態(tài),我們可以直接跨過配置直接開發(fā)。對配置有興趣的可以在Vue官方文檔找到SSR渲染文檔。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/103711.html
摘要:為了解決問題,推出了服務(wù)端預(yù)渲染,以便提高對優(yōu)化。應(yīng)用,到了,單頁面應(yīng)用優(yōu)秀的用戶體驗,逐漸成為了主流,頁面整體式渲染出來的,稱之為客戶端渲染。客戶端接收數(shù)據(jù),然后完成最終渲染。通過對客戶端服務(wù)端基礎(chǔ)框架的抽象組織,主要關(guān)注的是應(yīng)用的渲染。 現(xiàn)在前端開發(fā)一般都是前后端分離,mvvm和mvc的開發(fā)框架,如Angular、React和Vue等,雖然寫框架能夠使我們快速的完成開發(fā),但是由于前...
摘要:前面既然說到了會把文件夾下面的所有文件編譯成路由,那么子路由需要使用文件夾嵌套才行。客戶端首次訪問的頁面會在服務(wù)端做輸出,一旦渲染完成之后,則不會再在服務(wù)端輸出,則會一直在客戶端進行輸出了。 服務(wù)端預(yù)渲染之Nuxt - 使用 現(xiàn)在大多數(shù)開發(fā)都是基于Vue或者React開發(fā)的,能夠達(dá)到快速開發(fā)的效果,也有一些不足的地方,Nuxt能夠在服務(wù)端做出渲染,然后讓搜索引擎在爬取數(shù)據(jù)的時候能夠讀到...
摘要:同比與去年同期的同比變化率。我們對調(diào)查報告進行分析數(shù)據(jù)統(tǒng)計時間與本文時間差距較遠(yuǎn),數(shù)據(jù)存在延后。這意味著你可以獲得語法高亮,支持以及更容易使用預(yù)處理器如或。的是一個類似語法的可選預(yù)處理器,并可在中進行編譯。 一些歷史 Angular 是基于 TypeScript 的 Javascript 框架。由 Google 進行開發(fā)和維護,它被描述為超級厲害的 JavaScript MVW 框架...
摘要:最近簡單的研究了一下,對已經(jīng)有了一個簡單的認(rèn)知,主要應(yīng)用于單頁面應(yīng)用,是很不錯的框架。創(chuàng)建好之后,在命令行直接輸入即可,當(dāng)控制臺顯示服務(wù)已啟動則表示該服務(wù)已經(jīng)啟動成功了。配置參數(shù)中有一項為這項配置的就是我們即將使用的模板。 最近簡單的研究了一下SSR,對SSR已經(jīng)有了一個簡單的認(rèn)知,主要應(yīng)用于單頁面應(yīng)用,Nuxt是SSR很不錯的框架。也有過調(diào)研,簡單的用了一下,感覺還是很不錯。但是還是...
閱讀 1416·2021-11-09 09:45
閱讀 1785·2021-11-04 16:09
閱讀 1448·2021-10-14 09:43
閱讀 1813·2021-09-22 15:24
閱讀 1588·2021-09-07 10:06
閱讀 1596·2019-08-30 14:15
閱讀 980·2019-08-30 12:56
閱讀 1562·2019-08-29 17:22