一、nuxt框架是一个前端框架,这个框架我的理解就是有利于seo,就是在被人百度的时候,会优先搜索到这个框架的网站。
二、主要问题:
1.登录
主要是在页面要先进行一些验证,数据请求的时候,必须携带正确的token才能请求数据,于是涉及到token的保存,需要通过接口获取到用户信息和token,再保存在store中,因为刷新页面,store就清空了,我就采用了localStorage保存信息。在localStorage中保存的只能在mounted中获取window对象,所以可能会有渲染延迟的现象,官方有个nuxt自带的nuxtServerInit方法,试了很久都不知道怎使用,我就暂时没有用。
首先是在page/login.vue获取用户信息和token
export default class AdminLogin extends Vue { private name: string = 'admin' private password: string = 'admin' // 登录 private userLogin () { const data: object = { name: this.name, password: Md5.hashStr(this.password) }; this.$axios.post('/api/v1/login', data).then((res: any) => { if (res.success) { this.$store.commit('SET_TOKEN', res.data.token); this.$store.commit('SET_USERINFO', { name: res.data.name }); window.localStorage.setItem('unserAllInfo', JSON.stringify(res.data)); this.$router.push('/admin/'); // 跳转 } else { this.$message.error({ message: '登录失败,请输入正确的用户名和密码' }); } }); } }
store/index.js
import Vuex from 'vuex'; const store = () => new Vuex.Store({ state: { userInfo: {}, token: '' }, mutations: { SET_TOKEN (state, data) { state.token = data || ''; }, SET_USERINFO (state, data) { state.userInfo = data || {}; } }, actions: { // nuxtServerInit ({ commit }, { req }) { // const cookie = req.headers.cookie; // } }, getters: { token: (state) => { return state.token; }, getuserInfo: (state) => { return state.userInfo; } } }); export default store;
在layout/admin.vue下面使用,防止刷新的时候store数据清空
private async mounted () { // 设置登录和token信息,防止刷新的时候store清空 const userInfo = window.localStorage.getItem('unserAllInfo') || null; if (userInfo) { const data = JSON.parse(userInfo); this.$store.commit('SET_TOKEN', data.token); this.$store.commit('SET_USERINFO', data); } else { this.$router.push('/admin/login'); } }
使用$store.getters.getuserInfo.name 可获取信息
如果要退出登录,清空localStorage即可
// 退出登录 // GoOut() { // window.localStorage.setItem('wmMonitorUsers', '') // this.$router.push('/admin/login') // }
在登录完成以后,我们每次发起数据请求的时候就需要带上token,于是在plugins下面对axios的请求进行了封装axios.js,需要在配置里面全局引用一下,在nuxt.config.js下加入以下代码
plugins: [ { src: '@/plugins/axios' }, ]
在plugins/axios.js写如下内容,都是抄的其他大神的。
export default function ({ $axios, redirect, store }) { // http request 拦截器 $axios.interceptors.request.use( (config) => { if (store.getters.token) { config.headers.Authorization = 'Bearer ' + store.getters.token; } else { config.headers.Authorization = ''; } return config; }, (err) => { return Promise.reject(err); }); // http response 拦截器 $axios.interceptors.response.use( (response) => { // 直接返回内容 if (response.success) { return response.data; } return response.data; }, (error) => { // store.commit(types.SET_LOAD, false); if (error.response) { const code = parseInt(error.response && error.response.status); switch (code) { case 401: sessionStorage.clear(); redirect('/admin/login'); console.log(401); break; case 403: sessionStorage.clear(); redirect('/admin/login'); console.log(403); break; case 404: sessionStorage.clear(); console.log(404); break; case 500: // Message.error('Server exception'); break; case 502: // Message.error('Bad Gateway'); break; case 503: // Message.error(error.message); break; case 504: // Message.error(error.message); break; default: break; } } // console.error(error.config.url, error.response.status) return Promise.reject(error); }); }
接下来就是在页面,直接发起请求即可,为什么直接发起请求就可以了呢,因为我重新对axios进行了封装,在配置文件加载的时候就行了了这个操作,于是接下来在各个页面直接请求即可。
例如在page下面的vue文件中发起请求:
this.$axios.post('/api/v1/接口', { data: data }).then((res: any) => { if (res.success) { this.$message.success('保存成功!'); } else { this.$message.error({ message: '保存失败!' }); } });
2.讲讲路由方面,我使用了<nuxt-link to="/admin/product"></nuxt-link>跳转,内容在<nuxt />中显示,跟vue的路由用起来一模一样。
nuxt的路由很方便,就是page下面的vue页面的名字,相当于他自动给你配置了路由,而你直接使用地址跳转就可以。layout里面放的是布局文件,就是你框架的整体结构,比如你从layout里面的index要跳转到page下面的product.vue,只需在to后面加上/product即可。
传参的路由,我要跳转到动态路由_id页面,我需要传参id过去,下面代码相当于admin/news/id,这个id是动态的,params是我传过去的id,跳转到的_id页面到时候路由显示就是admin/news/传过来的params里面的id
文件结构
<nuxt-link :to="{name:'admin-news-id', params:{id: item._id}}">{{ item.title }}</nuxt-link>
动态路由_id页面里面获取id:this.$route.params.id,然后在根据id请求一些需要的数据
3.配置文件nuxt.config.js,我主要是配置了这些。主要是对环境变量进行了配置,得到一个全局的服务器地址,比如,我要渲染从服务器拿到的图片或其他资源,我的写法是src=process.env.serverUrl + 服务器存数据的地址,例如'/public/img/a.img',这样就可以渲染出服务器上的图片了。
const env = require('./env'); module.exports = { mode: 'universal', /* ** Headers of the page ** ak=>百度地图 */ head: { title: '', meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', content: process.env.npm_package_description || '' } ], link: [ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' } ], script: [ { src: '/rem.js', type: 'text/javascript', charset: 'utf-8' } // { src: '/ueditor_node/ueditor.config.js', type: 'text/javascript', charset: 'utf-8' }, // { src: '/ueditor_node/ueditor.all.js', type: 'text/javascript', charset: 'utf-8' }, // { src: '/ueditor.parse.min.js', type: 'text/javascript', charset: 'utf-8' }, // { src: '/ueditor_node/lang/zh-cn/zh-cn.js', type: 'text/javascript', charset: 'utf-8' } ] }, /* ** Customize the progress-bar color */ loading: { color: '#fff' }, /* ** Global CSS */ css: [ 'element-ui/lib/theme-chalk/index.css', '~assets/css/basic.css', 'quill/dist/quill.snow.css', 'quill/dist/quill.bubble.css', 'quill/dist/quill.core.css' ], /* ** Plugins to load before mounting the App */ plugins: [ '@/plugins/element-ui', '~/plugins/vue-echarts', '~/plugins/awe-dnd', { src: '@/plugins/vue-quill-editor', ssr: false }, { src: '@/plugins/axios' }, { src: '@/plugins/gmap' } ], /* ** Nuxt.js dev-modules */ buildModules: ['@nuxt/typescript-build'], /* ** Nuxt.js modules */ modules: [ // Doc: https://axios.nuxtjs.org/usage '@nuxtjs/axios', ['@nuxtjs/proxy', { pathRewrite: { '^/api': '/' } }] ], proxy: { '/api': { target: env[process.env.NODE_ENV].ENV_API, // 目标接口域名 changeOrigin: true, // 表示是否跨域 pathRewrite: { '^/api': '' // 把 /api 替换成‘’ } } }, /* ** Axios module configuration ** See https://axios.nuxtjs.org/options */ axios: { // See https://github.com/nuxt-community/axios-module#options proxy: true, // 表示开启代理 prefix: '/api', // 表示给请求url加个前缀 /api credentials: true // 表示跨域请求时是否需要使用凭证 }, /* ** Build configuration */ env: { serverUrl: env[process.env.NODE_ENV].ENV_API }, build: { transpile: [/^element-ui/], /* ** You can extend webpack config here */ // eslint-disable-next-line @typescript-eslint/no-unused-vars extend (config, ctx) { } } };
env.js,开发环境和生产环境对应的接口
module.exports = { dev: { NODE_ENV: 'dev', ENV_API: 'http://172.16.5.248:7001' // 测试服务器地址 }, pro: { NODE_ENV: 'pro', ENV_API: 'http://172.16.5.248:7001' // 正式服务器地址 } } ;
package.json下面的script修改了一下,主要是对环境变量的配置
"scripts": { "dev": "cross-env NODE_ENV=dev nuxt", "start": "cross-env NODE_ENV=pro nuxt start", "build": "cross-env NODE_ENV=pro nuxt build", "test": "cross-env NODE_ENV=pro nuxt generate", "generate": "cross-env NODE_ENV=pro nuxt generate", "prod": "cross-env NODE_ENV=pro node server/index.js", "lint": "eslint --ext .js,.vue --ignore-path .gitignore ." },