nuxt.js相關
Nuxt
簡單說,Nuxt
就是基於Vue
的一個應用框架,採用服務端渲染
,讓你的SPA應用(Vue)也可以擁有SEO
生命週期
Vue
的生命週期
全都跑在客戶端
(瀏覽器),而Nuxt
的生命週期有些在服務端(Node),客戶端,甚至兩邊都在:
生命週期流程圖,紅框內的是Nuxt的生命週期(運行在服務端)
,黃框內同時運行在服務端&&客戶端上
,綠框內則運行在客戶端
路由
Nuxt.js-路由文檔
Nuxt.js 依據 pages 目錄
結構自動生成
vue-router 模塊的路由配置。
要在頁面之間使用路由,建議使用 標籤。
<template>
<nuxt-link to="/">首頁</nuxt-link>
</template>
基礎路由
假設 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.js 裏面定義帶參數的動態路由,需要創建對應的以下劃線作爲前綴的 Vue 文件 或 目錄
。
以下目錄結構:
pages/
--| _slug/
-----| comments.vue
-----| index.vue
--| users/
-----| _id.vue
--| index.vue
Nuxt.js 生成對應的路由配置表爲:
router: {
routes: [
{
name: 'index',
path: '/',
component: 'pages/index.vue'
},
{
name: 'users-id',
path: '/users/:id?',
component: 'pages/users/_id.vue'
},
{
name: 'slug',
path: '/:slug',
component: 'pages/_slug/index.vue'
},
{
name: 'slug-comments',
path: '/:slug/comments',
component: 'pages/_slug/comments.vue'
}
]
}
你會發現名稱爲users-id
的路由路徑帶有 :id? 參數
,表示該路由是可選的
。如果你想將它設置爲必選的路由,需要在 users/_id 目錄內創建一個 index.vue 文件。
路由參數校驗、嵌套路由、動態嵌套路由等等可以直接看官方文檔,Nuxt.js-路由文檔
異步數據-asyncData方法
Nuxt.js 擴展了 Vue.js,增加了一個叫asyncData 的方法
,使得我們可以在設置組件的數據之前
能異步獲取或處理數據。
asyncData
方法會在組件(限於頁面組件
)每次加載之前
被調用
。它可以在服務端或路由更新之前被調用。
在這個方法被調用的時候,第一個參數
被設定爲當前頁面的上下文對象
,你可以利用 asyncData方法來獲取數據
Nuxt.js 會將 asyncData 返回的數據融合
組件 data 方法返回的數據一併返回給當前組件
。
注意:由於
asyncData方法
是在組件初始化前
被調用的,所以在方法內是沒有辦法通過 this 來引用
組件的實例對象。
Nuxt.js 提供了幾種不同的方法來使用 asyncData 方法,你可以選擇自己熟悉的一種來用:
如果項目中直接使用了node_modules中的axios,並且使用axios.interceptors添加攔截器對請求或響應數據進行了處理,確保使用 axios.create創建實例後再使用。否則多次刷新頁面請求服務器,服務端渲染會重複添加攔截器,導致數據處理錯誤。
import axios from 'axios'
const myaxios = axios.create({
// ...
})
myaxios.interceptors.response.use(function (response) {
return response.data
}, function (error) {
// ...
})
返回 Promise
export default {
asyncData ({ params }) {
return axios.get(`https://my-api/posts/${params.id}`)
.then((res) => {
return { title: res.data.title }
})
}
}
使用 async或await
export default {
async asyncData ({ params }) {
const { data } = await axios.get(`https://my-api/posts/${params.id}`)
return { title: data.title }
}
}
使用 回調函數
export default {
asyncData ({ params }, callback) {
axios.get(`https://my-api/posts/${params.id}`)
.then((res) => {
callback(null, { title: res.data.title })
})
}
}
返回 對象
如果組件的數據不需要異步獲取或處理,可以直接返回指定的字面對象作爲組件的數據。
export default {
data () {
return { foo: 'bar' }
}
}
數據的展示
asyncData 方法返回的數據在融合 data 方法返回的數據後,一併返回給模板進行展示,如:
<template>
<h1>{{ title }}</h1>
</template>
上下文對象
可通過 API context 來了解該對象的所有屬性和方法。
使用 req/res(request/response) 對象
在服務器端調用asyncData時,您可以訪問用戶請求的req和res對象。
export default {
async asyncData ({ req, res }) {
// 請檢查您是否在服務器端
// 使用 req 和 res
if (process.server) {
return { host: req.headers.host }
}
return {}
}
}
錯誤處理
Nuxt.js 在上下文對象context中提供了一個 error(params) 方法,你可以通過調用該方法來顯示錯誤信息頁面。params.statusCode 可用於指定服務端返回的請求狀態碼。
以返回 Promise 的方式舉個例子:
export default {
asyncData ({ params, error }) {
return axios.get(`https://my-api/posts/${params.id}`)
.then((res) => {
return { title: res.data.title }
})
.catch((e) => {
error({ statusCode: 404, message: 'Post not found' })
})
}
}
如果你使用 回調函數 的方式, 你可以將錯誤的信息對象直接傳給該回調函數, Nuxt.js 內部會自動調用 error 方法:
export default {
asyncData ({ params }, callback) {
axios.get(`https://my-api/posts/${params.id}`)
.then((res) => {
callback(null, { title: res.data.title })
})
.catch((e) => {
callback({ statusCode: 404, message: 'Post not found' })
})
}
}
Vuex狀態樹
對於每個大項目來說,使用狀態樹 (store) 管理狀態 (state) 十分有必要。這就是爲什麼 Nuxt.js 內核實現了 Vuex。
使用狀態樹
Nuxt.js 會嘗試找到應用根目錄下的 store 目錄
,如果該目錄存在,它將做以下的事情:
- 引用 vuex 模塊
- 將 vuex 模塊 加到 vendors 構建配置中去
- 設置 Vue 根實例的 store 配置項
Nuxt.js 支持兩種使用 store 的方式,你可以擇一使用:
- 模塊方式: store 目錄下的每個 .js 文件會被轉換成爲狀態樹指定命名的子模塊 (當然,index 是根模塊)
- Classic(不建議使用): store/index.js返回創建Vuex.Store實例的方法。.
無論使用那種模式,您的state的值
應該始終是function
,爲了避免返回引用類型,會導致多個實例相互影響。
普通方式
Nuxt.js允許您擁有一個 store 目錄,其中包含與模塊對應的每個文件。
首先,只需將狀態導出爲 函數,將變量和操作作爲 store/index.js 中的對象導出:
export const state = () => ({
counter: 0
})
export const mutations = {
increment (state) {
state.counter++
}
}
然後,您可以擁有 store/todos.js 文件:
export const state = () => ({
list: []
})
export const mutations = {
add (state, text) {
state.list.push({
text,
done: false
})
},
remove (state, { todo }) {
state.list.splice(state.list.indexOf(todo), 1)
},
toggle (state, todo) {
todo.done = !todo.done
}
}
Vuex將如下創建
new Vuex.Store({
state: () => ({
counter: 0
}),
mutations: {
increment (state) {
state.counter++
}
},
modules: {
todos: {
namespaced: true,
state: () => ({
list: []
}),
mutations: {
add (state, { text }) {
state.list.push({
text,
done: false
})
},
remove (state, { todo }) {
state.list.splice(state.list.indexOf(todo), 1)
},
toggle (state, { todo }) {
todo.done = !todo.done
}
}
}
}
})
在您的 pages/todos.vue 中,使用 todos 模塊:
<template>
<ul>
<li v-for="todo in todos">
<input type="checkbox" :checked="todo.done" @change="toggle(todo)">
<span :class="{ done: todo.done }">{{ todo.text }}</span>
</li>
<li><input placeholder="What needs to be done?" @keyup.enter="addTodo"></li>
</ul>
</template>
<script>
import { mapMutations } from 'vuex'
export default {
computed: {
todos () {
return this.$store.state.todos.list
}
},
methods: {
addTodo (e) {
this.$store.commit('todos/add', e.target.value)
e.target.value = ''
},
...mapMutations({
toggle: 'todos/toggle'
})
}
}
</script>
<style>
.done {
text-decoration: line-through;
}
</style>
模塊方法也適用於頂級定義,而無需在 store 目錄中實現子目錄
示例:您創建文件 store/state.js 並添加以下內容
export default () => ({
counter: 0
})
相應的可以在文件夾中添加 store/mutations.js
export default {
increment (state) {
state.counter++
}
}
模塊文件
您可以將模塊文件分解爲單獨的文件:state.js,actions.js,mutations.js和getters.js。如果您使用index.js來維護state,getters,actions和mutations,同時具有單個單獨的操作文件,那麼仍然可以正確識別該文件。
注意:在使用拆分文件模塊
時,必須記住使用箭頭函數功能
, this 在詞法上可用。詞法範圍this意味着它總是指向引用箭頭函數的所有者。如果未包含箭頭函數
,那麼this將是未定義的(undefined)
。解決方案是使用 “normal” 功能,該功能會將this指向自己的作用域,因此可以使用。
fetch 方法
fetch 方法會在渲染頁面前被調用
,作用是填充狀態樹 (store) 數據
,與 asyncData 方法類似,不同的是fetch不會設置組件的數據
。
nuxtServerInit 方法
如果在狀態樹中指定了 nuxtServerInit 方法,Nuxt.js 調用它的時候會將頁面的上下文對象
作爲第2個參數
傳給它(服務端調用時纔會生效)。當我們想將服務端的一些數據傳到客戶端時,這個方法是灰常好用的。
舉個例子,假設我們服務端的會話狀態樹裏可以通過 req.session.user 來訪問當前登錄的用戶。將該登錄用戶信息傳給客戶端的狀態樹,我們只需更新 store/index.js 如下:
actions: {
nuxtServerInit ({ commit }, { req }) {
if (req.session.user) {
commit('user', req.session.user)
}
}
}
如果你使用_狀態樹模塊化_的模式,只有主模塊
(即 store/index.js)適用設置該方法(其他模塊設置了也不會被調用)。
nuxtServerInit 方法接收的上下文對象和 fetch 的一樣,但不包括 context.redirect() 和 context.error()。
注意:異步nuxtServerInit操作必須返回Promise來通知nuxt服務器等待它們。
actions: {
async nuxtServerInit({ dispatch }) {
await dispatch('core/load')
}
}
創建nuxt項目(實戰項目)
使用nuxt官網提供的腳手架
// nuxt-learn 是項目名
npx create-nuxt-app nuxt-learn
項目目錄
兼容es6語法(import)
初始化的項目使用了nodemon監聽和熱刷新腳本,僅支持require語法,不支持es6的imoort語法
使用nodemon
可以監聽文件修改,然後讓服務器自行重啓。
// package.json
"scripts": {
"dev": "cross-env NODE_ENV=development nodemon server/index.js --watch server",
"build": "nuxt build",
"start": "cross-env NODE_ENV=production node server/index.js",
"generate": "nuxt generate"
},
// 正常
const Koa = require('koa')
// 改爲import 報錯
import Koa from 'koa'
babel-node依賴包
使用 babel-node
可以在 node 端自行編譯並運行
es6 甚至 es7。安裝方法如下:
npm i @babel/core @babel/cli @babel/preset-env @babel/node -D
// 或者使用 yarn
注意:我這裏是局部安裝的,全局安裝的方法請自行看官方文檔。
然後我們需要在項目的根目錄下面創建 .babelrc 文件
:
// .babelrc文件
{
"presets": ["@babel/preset-env"]
}
最後修改 package.json
// package.json文件 在dev和start後面加上--exec babel-node
"scripts": {
"dev": "cross-env NODE_ENV=development nodemon server/index.js --watch server --exec babel-node",
"build": "nuxt build",
"start": "cross-env NODE_ENV=production node server/index.js --exec babel-node",
"generate": "nuxt generate"
},
說明一下爲什麼要加 --exec
這個參數:這個參數是讓 nodemon 能運行非 node 程序
比如運行 py 文件nodemon --exec “python -v” ./app.py。在這裏因爲我們是用 nodemon 運行 babel-node,而不是 server.js,所以需要加 --exec 這個參數。
這樣就支持import語法了,可以重新跑一下服務
npm run dev
兼容sass語法
// pages/index.vue
<style lang="scss">
</style>
不處理直接使用會報錯
引入兩個依賴包sass-loader和node-sass
npm install sass-loader
npm install node-sass
// 如果node-sass安裝失敗 可以嘗試使用淘寶鏡像安裝
// 如果沒有淘寶鏡像 可以先安裝cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install node-sass
安裝好兩個依賴包後,就能兼容sass語法了
入口文件
vue-cli
入口文件是app.vue
,在nuxt
開發當中則是./layout/default.vue
<template>
<div id="app">
<!-- 公共頭部組件 -->
<xxx-header></xxx-header>
<!-- 路由視圖,相當於router-view -->
<nuxt/>
<!-- 公共底部組件 -->
<xxx-footer></xxx-footer>
</div>
</template>
登錄註冊功能(服務端)
驗證碼通過qq郵箱發送
QQ郵箱 設置 賬戶
得到一個授權碼,需要寫進配置文件裏
配置文件
import 引入的包可以通過
npm install 名字 去獲取
server/dbs/config.js
export default {
// mongodb數據庫地址 端口號默認 27017 student爲數據組名稱
dbs: 'mongodb://127.0.0.1:27017/student',
// redis 用來存驗證碼 效率比較高
redis: {
get host() {
return '127.0.0.1'
},
get port() {
// 默認端口號
return 6379
}
},
// smtp服務 發驗證碼郵件
smtp: {
get host() {
// 騰訊郵箱
return 'smtp.qq.com'
},
get user() {
return '[email protected]'
},
// 通過qq郵箱設置 得到的授權碼
get pass() {
return 'ersetxsjtpuxijae'
},
get code() {
return () => {
// 隨機生成四位驗證碼
return Math.random().toString(16).slice(2, 6).toUpperCase()
}
},
get expire() {
// 過期時間 1分鐘
return ()=> {
return new Date().getTime() + 60 * 60 * 1000
}
}
}
}
創建mongoose模型user
server/dbs/models/users.js
import mongoose from 'mongoose'
const Schema = mongoose.Schema
const UserSchema = new Schema({
username: {
type: String,
// true表示唯一
unique: true,
// 必填
require: true
},
password: {
type: String,
require: true
},
email: {
type: String,
require: true
}
})
export default mongoose.model('User', UserSchema)
server\interface\utils\axios.js
簡單封裝axios
import axios from 'axios'
const instance = axios.create({
baseURL: `http://${process.env.HOST || 'localhost'}:${process.env.PORT || 3000}`,
// 超時
timeout: 1000,
// 默認頭部
headers: {
}
})
export default instance
server\interface\utils\passport.js
用來驗證用戶密碼
import passport from 'koa-passport'
import LocalStrategy from 'passport-local'
import UserModel from '../../dbs/models/users'
passport.use(new LocalStrategy(async (username, password, done) => {
let where = {
username
}
let result = await UserModel.findOne(where)
if (result != null) {
if (result.password === password) {
// 用戶輸入密碼跟數據庫密碼一致
return done(null, result)
} else {
return done(null, false, '密碼錯誤')
}
} else {
return done(null, false, '用戶不存在')
}
}))
// 用戶每次進來 自動通過session驗證
// 在每次請求時 會從session中讀取用戶對象 用戶通過驗證後serializeUser會將用戶數據存在session中
// 序列化
passport.serializeUser((user, done) => {
done(null, user)
})
// 反序列化
passport.deserializeUser((user, done) => {
done(null, user)
})
export default passport
server\interface\users.js
users下相關接口實現
import Router from 'koa-router'
import Redis from 'koa-redis'
// nodemailer支持node發郵件
import nodeMailer from 'nodemailer'
import User from '../dbs/models/users'
import Passport from './utils/passport'
import Email from '../dbs/config'
import axios from './utils/axios'
// 路由前綴
let router = new Router({
prefix: '/users'
})
// 獲取redis客戶端
let Store = new Redis().client
// 註冊接口
router.post('/signup', async(ctx) => {
const {
username,
password,
email,
code
} = ctx.request.body
// 校驗驗證碼 nodemailer發驗證碼時會存進redis裏 這裏從redis裏拿出對比
if (code) {
// Store.hget(`nodemail:${username}`, 'code') redis是key-value存儲 nodemail表示屬於哪個模塊 username用來匹配 減值code
const saveCode =await Store.hget(`nodemail:${username}`, 'code')
// 過期時間
const saveExpire = await Store.hget(`nodemail:${username}`, 'expire')
if (code === saveCode) {
if (new Date().getTime() - saveExpire > 0) {
ctx.body = {
code: -1,
msg: '驗證碼已過期,請重新嘗試'
}
return false
}
} else {
ctx.body = {
code: -1,
msgL: '請填寫正確的驗證碼'
}
}
} else {
ctx.body = {
code: -1,
msg:'請填寫驗證碼'
}
}
let user = await User.find({
username
})
if (user.length) {
ctx.body = {
code: -1,
msg: '已被註冊'
}
return
}
// 寫庫操作
let nuser = await User.create({
username,
password,
email
})
if (nuser) {
// 寫庫成功
let res = await axios.post('/users/signin', {
username,
password
})
if (res.data && res.data.code ===0) {
ctx.body = {
code: 0,
msg: '註冊成功',
user: res.data.user
}
} else {
ctx.body = {
code: -1,
msg: 'error'
}
}
} else {
ctx.body = {
code: -1,
msg: '註冊失敗'
}
}
})
// 登錄接口
router.post('/signin', async (ctx, next) => {
return Passport.authenticate('local', function(err, user, info, status) {
if (err) {
ctx.body = {
code: -1,
msg: err
}
} else {
if (user) {
ctx.body = {
code: 0,
msg: '登錄成功',
user
}
return ctx.login(user)
} else {
// 異常
ctx.body = {
code: 1,
msg: info
}
}
}
})(ctx, next)
})
// 驗證碼驗證
router.post('/verify', async (ctx, next) => {
let username = ctx.request.body.username
const saveExpire = await Store.hget(`nodemail:${username}`, 'expire')
if (saveExpire && new Date().getTime() - saveExpire > 0) {
ctx.body = {
code: -1,
msg: '驗證請求過於頻繁,1分鐘內1次'
}
return false
}
// 驗證郵件相關
// 發送對象
let transporter = nodeMailer.createTransport({
host: Email.smtp.host,
port: 587,
// secure: true 則監聽405端口 false 爲其他端口
secure: false,
// 權限校驗
auth: {
user: Email.smtp.user,
pass: Email.sntp.pass
}
})
// 接手對象
let ko = {
code:Email.smtp.code(),
expire:Email.smtp.expire(),
email: ctx.request.body.email,
user: ctx.request.body.username
}
// 郵件顯示內容
let mailOptions = {
// 標題
from: `"認證郵件" <${Email.smtp.user}>`,
to: ko.email,
// 主題
subject: '《慕課網高仿美團網全棧實戰》註冊碼',
html: `您在《慕課網高仿美團網全棧實戰》課程中註冊,您的邀請碼是&{ko.code}`
}
// 發送郵件
await transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log('error')
} else {
// 存到redis哈希表裏
Store.hmset(`nodemail:${ko.user}`, 'code', ko.code, 'expire', ko.expire, 'email', ko.email)
}
})
ctx.body = {
code: 0,
msg: '驗證碼已發送,可能會有延時,有效期1分鐘'
}
})
// 退出接口
router.get('/exit', async (ctx, next) => {
await ctx.logout()
// isAuthenticated 這個API由passport包提供
if (!ctx.isAuthenticated()) {
// 檢查當前是不是登錄狀態 不是的話 說明退出成功
ctx.body = {
code:0
}
} else {
ctx.body = {
code: -1
}
}
})
// 獲取用戶名
router.get('/getUser', async (ctx) => {
// isAuthenticated 這個API由passport包提供 user也是登錄成功時passport這個包存進session裏的
if (ctx.isAuthenticated()) {
const {username, email} = ctx.session.passport.user
ctx.body = {
user: username,
email
}
} else {
ctx.body = {
user: '',
email: ''
}
}
})
// 導出路由
export default router
server\index.js
引入相關包,配置
// const Koa = require('koa')
import Koa from 'koa'
const consola = require('consola')
const { Nuxt, Builder } = require('nuxt')
import mongoose from 'mongoose'
// 用來處理post請求相關 沒有這個包就無法通過ctx.request.body獲取post請求參數
import bodyParser from 'koa-bodyparser'
// 存session cookie相關的 包
import session from 'koa-generic-session'
import Redis from 'koa-redis'
// 解決服務端向客戶端發json 格式美化
import json from 'koa-json'
// 數據庫相關配置
import dbConfig from '../server/dbs/config'
import passport from './interface/utils/passport'
import users from '../server/interface/users'
const app = new Koa()
// Import and Set Nuxt.js options
const config = require('../nuxt.config.js')
config.dev = app.env !== 'production'
async function start () {
// Instantiate nuxt.js
const nuxt = new Nuxt(config)
const {
host = process.env.HOST || '127.0.0.1',
port = process.env.PORT || 3000
} = nuxt.options.server
app.keys = ['mt', 'keyskeys']
app.proxy = true
// 客戶端存的是cookie 服務端是session
app.use(session({
key: 'mt',
prefix: 'mt:uid',
// session 相關存到redis
store: new Redis()
}))
app.use(bodyParser({
extendTypes: ['json', 'form', 'text']
}))
app.use(json())
// 連接數據庫
mongoose.connect(dbConfig.dbs, {
useNewUrlParser: true
})
// 處理登錄相關
app.use(passport.initialize())
app.use(passport.session())
await nuxt.ready()
// Build in development
if (config.dev) {
const builder = new Builder(nuxt)
await builder.build()
}
// 引入路由
app.use(users.routes()).use(users.allowedMethods())
app.use((ctx) => {
ctx.status = 200
ctx.respond = false // Bypass Koa's built-in response handling
ctx.req.ctx = ctx // This might be useful later on, e.g. in nuxtServerInit or with nuxt-stash
nuxt.render(ctx.req, ctx.res)
})
app.listen(port, host)
consola.ready({
message: `Server listening on http://${host}:${port}`,
badge: true
})
}
start()
啓動redis服務
redis-server
啓動mongodb服務
mongo
// 或者 看你的mongo名稱
mongod
跑一下項目服務
npm run dev
前端調用即可以用
城市服務相關接口
獲取定位接口
server\interface\geo.js
import Router from "koa-router";
import axios from "./utils/axios";
// 路由前綴
let router = new Router({
prefix: "/geo"
});
const sign = 'abcd'
router.get('/getPosition', async (ctx) => {
let {
status,
data: {
province,
city
}
} = await axios.get(`http://cp-tools.cn/geo/getPosition?sign=${sign}`)
if (status === 200) {
ctx.body = {
province,
city
}
} else {
ctx.body={
province: '',
city: ''
}
}
})
export default router
server\index.js
導入路由
import users from '../server/interface/users'
import geo from '../server/interface/geo'
app.use(users.routes()).use(users.allowedMethods())
app.use(geo.routes()).use(geo.allowedMethods())
nuxtServerInit方法跟vuex
通過nuxtServerInit方法實現ssr渲染獲取到的定位
store\modults\geo.js
const state = () => {
position: {}
}
const mutations = {
setPosition(state, val) {
console.log('geo mutations val:')
console.log(val)
state.position = val
}
}
const actions = {
setPosition: ({
commit
}, position) => {
commit('setPosition', position)
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
store\index.js
import Vue from 'vue'
import Vuex from 'vuex'
import geo from './modults/geo'
Vue.use(Vuex)
const store = () => new Vuex.Store({
modules: {
geo
},
actions: {
async nuxtServerInit({
commit
}, {req, app}) {
console.log('nuxtServerInit:')
const {status, data: {province, city}} = await app.$axios.get('/geo/getPosition')
console.log(province, city)
// 這裏的檢查是在客戶端做的
commit('geo/setPosition', status === 200 ? {city, province} : {province:'', city: ''})
}
}
})
export default store
前端頁面
components\public\header\geo.vue
// 獲取到服務端存放在vuex的定位
{{$store.state.geo.position.city}}
獲取菜單接口
server\dbs\models\menu.js
import mongoose from 'mongoose'
const Schema = mongoose.Schema
const Menu = new Schema({
menu: {
type: Array,
require: true
}
})
export default mongoose.model('Menu', Menu)
server\interface\geo.js
import Router from "koa-router";
import axios from "./utils/axios";
import Menu from '../dbs/models/menu'
import Proviece from '../dbs/models/province'
// 路由前綴
let router = new Router({
prefix: "/geo"
});
const sign = 'abcd'
router.get('/getPosition', async (ctx) => {
let {
status,
data: {
province,
city
}
} = await axios.get(`http://cp-tools.cn/geo/getPosition?sign=${sign}`)
if (status === 200) {
ctx.body = {
province,
city
}
} else {
ctx.body={
province: '',
city: ''
}
}
})
router.get('/getMenu', async (ctx) => {
// 數據庫操作
const result = await Menu.findOne()
ctx.body = {
menu: result.menu || []
}
// 線上接口
// let {status, data: {menu}} = await axios.get(`http://cp-tlls.cn/geo/menu?sign=${sign}`)
// if (status = 200) {
// ctx.body = {
// menu: munu
// }
// } else {
// ctx.body = {
// menu: []
// }
// }
})
export default router
store\modults\home.js
const state = () => ({
menu: []
})
const mutations = {
setMenu(state, val) {
state.menu = val
}
}
const actions = {
setMenu: ({
commit
}, menu) => {
commit('setMenu', menu)
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
store\index.js
import Vue from 'vue'
import Vuex from 'vuex'
import geo from './modults/geo'
import home from './modults/home'
Vue.use(Vuex)
const store = () => new Vuex.Store({
modules: {
geo,
home
},
actions: {
async nuxtServerInit({
commit
}, {req, app}) {
console.log('nuxtServerInit:')
// geo
const {status, data: {province, city}} = await app.$axios.get('/geo/getPosition')
commit('geo/setPosition', status === 200 ? {city, province} : {province:'', city: ''})
// home
const {status:status2,data: {menu}} = await app.$axios.get('/geo/getMenu')
commit('home/setMenu', status2 === 200 ? menu : [])
}
}
})
export default store
前端頁面通過
// 獲取menu值
this.$store.state.home.menu
謝謝你閱讀到了最後
期待你,點贊、評論、交流