菜鸡新手向,这是我在学习vue.js项目时遇到的一些小问题,用来记录一下自己的学习经历,大家一起加油^_^
1.axios的导入
设置axios的默认地址,再将axios挂载到Vue上,然后就可以愉快的使用this.$http.+请求发送网络请求啦
// 导入axios
import axios from 'axios'
axios.defaults.baseURL = '' //输入地址
Vue.prototype.$http =axios
2.登录功能中的token
首先是了解localStorage和sessionStorage,两者唯一一点区别就是localStorage属于永久性储存,而sessionStorage属于当对话结束的时候,sessionStorage中的值才会被清空
而token之应该再打开该网站时生效,因此在登陆功能中,
window.sessionStorage.setItem(key,value)
通过以上的方法可以将token存储再sessionStorage中,传入两个参数,第一个时自定义名,可以设置为“token”,第二个就是实际中token的值。
3.路由守卫
一个简单的路由守卫结构 ,如下(未涉及到token的验证)
// 挂载路由导航守卫
router.beforeEach((to,from,next)=>{
// to代表将要访问的路径
// from代表从哪个路径跳转而来
// next是一个函数,表示放行
// next()放行 next('/login')表示强制跳转至目标'/login'路径
if(to.path == '/login') return next()
// 先看路径,如果路径是登录页面,那直接放行,如果不是,那就先获取token
const tokenStr = window.sessionStorage.getItem('token')
if(!tokenStr) return next('/login')
next()
})
4.系统中的退出功能实现
通过清除sessionStorage中的token值实现退出,再指定跳转的页面即可
logout(){
window.sessionStorage.clear();
this.$router.push('/login')
}
5.在用户页面中,要使用需要授权的API,必须在请求头中使用Authorization字段提供token令牌才行,可以通过axios拦截器添加token验证,这样,每一次向浏览器发送需要授权的请求时,就会对进行token进行一次预验证
axios.interceptors.request.use(config => {
config.headers.Authorization = window.sessionStorage.getItem("token")
// 最后必须return(固定写法)
return config;
});
再将axios拦截器设置在 axios挂载之前,完美
axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1/'
axios.interceptors.request.use(config => {
config.headers.Authorization = window.sessionStorage.getItem("token")
// 最后必须return(固定写法)
return config;
});
Vue.prototype.$http = axios
6.this.$router 和 this.$route(转载 本文链接:https://blog.csdn.net/u014395524/article/details/88194842)
this.$router 相当于一个全局的路由器对象,包含了很多属性和对象(比如 history 对象),任何页面都可以调用其 push(), replace(), go() 等方法。
this.$route 表示当前路由对象,每一个路由都会有一个 route 对象,是一个局部的对象,可以获取对应的 name, path, params, query 等属性。
关于 push() 方法:
想要导航到不同的 URL,则使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。
当你点击 <router-link> 时,这个方法会在内部调用,所以说,点击 <router-link :to="..."> 等同于调用 router.push(...)。
push() 方法的调用:
//字符串
this.$router.push('home')
//对象
this.$router.push({path:'home'})
//命名的路由
this.$router.push({name:'user', params:{userId: '123'}})
//带查询参数,变成 /register?plan=private
this.$router.push({path:'register', query:{plan:private}})
注意:如果提供了 path,params 会被忽略,上述例子中的 query 并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name 或手写完整的带有参数的 path:
const userId = '123';
this.$router.push({path:`/user/${userId}`}); //->/user/123
this.$router.push({name:'user', params:{userId}}); //->/user/123
//这里的 params 不生效
this.$router.push({path:'/user', params:{userId}}); //->/user
params 传参,push 里面只能是 name:'xxx',不能是 path:'/xxx',因为 params 只能用 name 来引入路由,如果这里写成了 path ,接收参数页面会是 undefined。
7.element-ui中清空表单
通过resetFields()完成
比如说想要在关闭dialog后清空位于dialog中的数据
<el-dialog title="添加用户" :visible.sync="addDialogVisible" width="50%" @close='addDialogClosed'>
<!-- 内容主题区 -->
<el-form
:model="addForm"
:rules="addFormrules"
ref="addFormRef"
label-width="70px"
>
<el-form-item label="用户名" prop="username">
<el-input v-model="addForm.username"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="addForm.password" type="password"></el-input>
</el-form-item>
</el-form>
<!-- 底部按钮区 -->
<span slot="footer" class="dialog-footer">
<el-button @click="addDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="addDialogVisible = false"
>确 定</el-button
>
</span>
</el-dialog>
在dialog上添加一个@close='addDialogClosed',然后在methods中定义这个函数,用resetFields()方法清空即可
addDialogClosed(){
this.$refs.addFormRef.resetFields()
}
8.深拷贝Vue的运行依赖包lodash
在Vue依赖中下载lodash依赖包,然后再所需页面的script标签中导入
<script>
import _ from 'lodash'
然后使用lodash中的cloneDeep()就可以实现深拷贝了!!👇
const form = _.cloneDeep(this.addForm)
这样就可以把addForm深拷贝一份form了
9.babel配置中移除console.log()
在项目开发阶段保留console.log()用作调试,而在发布阶段需要移除项目中所有的console.log(),这是需要在项目的babel.config.js文件中进行简单的配置
首先要安装babel-plugin-transform-remove-console的开发依赖包
然后就可以在babel.config.js文件中进行相关的配置
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins: [
[
'component',
{
libraryName: 'element-ui',
styleLibraryName: 'theme-chalk'
}
],
'transform-remove-console'
]
}
在plugins的数组中加入'transform-remove-console'就可以了,但是这样写有弊端,无论是开发还是发布阶段,项目中的console.log()都会被移除,我们只希望在发布阶段移除console.log(),那就需要做一个判断
在项目开发阶段时运行,mode值为development,而在项目发布阶段时,mode值为production,基于mode的值,就可以进行判断
思路时先设置一个数组,然后再进行判断,最后把数组放到plugins中,搞定
const proPlugins = []
if(process.env.NODE_ENV === 'production'){
proPlugins.push('transform-remove-console')
}
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins: [
[
'component',
{
libraryName: 'element-ui',
styleLibraryName: 'theme-chalk'
}
],
...proPlugins
]
}
10.vue.config.js的配置
注意,这里相当于是定义了项目运行时的入口文件,如果是再开发(process.env.NODE_ENV === 'development')模式下,将入口文件main.js换成main-dev.js,如果是发布模式(process.env.NODE_ENV === 'production'),则将入口文件替换成main-prod.js,可以把src下的main.js复制一份再重命名(注意存放的路径不能出错,否则系统会找不到入口文件,直接报错!!!!)
module.exports = {
lintOnSave: false,
chainWebpack: config=>{
config.when(process.env.NODE_ENV === 'production',config =>{
config.entry('app').clear().add('./src/main-dev.js')
})
config.when(process.env.NODE_ENV === 'development', config=>{
config.entry('app').clear().add('./src/main-prod.js')
})
}
}
11.通过externals加载外部CDN资源
在默认的情况下,通过import语法导入的第三方依赖包,最终会被打包合并到同一个文件中,从而导致打包合并后,单文件体积过大
为了解决上述问题,通过webpack的externals节点,在配置外部的CDN资源,凡是声明在externals中的第三方依赖包,都不会被打包,在vue.config.js文件中配置externals,这样在运行的时候,如果发现用import导入了一个包,👇,如axios,就不会把这个包(axios)合并到上述的文件中去,而是区window全局中寻找axios对象,然后直接来使用
module.exports = {
lintOnSave: false,
chainWebpack: config=>{
// 发布模式
config.when(process.env.NODE_ENV === 'production',config =>{
config.entry('app').clear().add('./src/main-prod.js')
config.set('externals',{
vue:"Vue",
'vue-router': 'VueRouter',
axios: 'axios',
lodash:'_',
echarts : 'echarts',
nprogress:'Nprogress',
'vue-quill-editor': 'VueQuillEditor'
})
})
// 开发模式
config.when(process.env.NODE_ENV === 'development', config=>{
config.entry('app').clear().add('./src/main-dev.js')
})
}
}
做完上面的配置,还需要在public/index.html文件的头部加上CDN资源的引用,例如我的项目中的CDN引用如下👇,可以用https://www.bootcdn.cn/,在这里面直接输入要引入的包名就可以找到了!!
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
<!-- nprogress样式表 -->
<link href="https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.css" rel="stylesheet">
<!-- 富文本编辑器css -->
<link href="https://cdn.bootcdn.net/ajax/libs/quill/2.0.0-dev.3/quill.bubble.min.css" rel="stylesheet">
<link href="https://cdn.bootcdn.net/ajax/libs/quill/2.0.0-dev.3/quill.core.min.css" rel="stylesheet">
<link href="https://cdn.bootcdn.net/ajax/libs/quill/2.0.0-dev.3/quill.snow.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.9/vue.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.9/vue.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script>
<!-- 富文本编辑器js文件 -->
<script src="https://cdn.bootcdn.net/ajax/libs/quill/2.0.0-dev.4/quill.min.js"></script>
</head>
12.首页内容定制
目标:希望在development下,在网页上显示dev-电商后台管理系统,而在production中显示的是 电商后台管理系统,并且在dev中不需要加载CDN,
思路:依旧是需要判断当前加载到底时development还是production,所以着手对号是在vue.config.js的配置中,在发布模ls式和开发模式中,找到一个插件,html,然后通过tap()修改插件中的链式操作,在tap中定义一个回调函数,args时插件中的参数项,在args中加上一个自定义属性,isProd,在发布模式中定义isProd为true,而在生产模式中定义isProd为false
module.exports = {
lintOnSave: false,
chainWebpack: config=>{
// 发布模式
config.when(process.env.NODE_ENV === 'production',config =>{
config.entry('app').clear().add('./src/main-prod.js')
config.plugin('html').tap(args=>{
args[0].isProd = true
return args
})
config.set('externals',{
vue:"Vue",
'vue-router': 'VueRouter',
axios: 'axios',
lodash:'_',
echarts : 'echarts',
nprogress:'Nprogress',
'vue-quill-editor': 'VueQuillEditor'
})
})
// 开发模式
config.when(process.env.NODE_ENV === 'development', config=>{
config.entry('app').clear().add('./src/main-dev.js')
config.plugin('html').tap(args=>{
args[0].isProd = false
return args
})
})
}
}
回到public中的index.html,htmlWebpackPlugin是参数名称,options中是参数项,isProd就是👆定义的参数,用三元运算符判断即可
<title>
<%= htmlWebpackPlugin.options.isProd ? '': 'dev-'%>电商后台管理系统
</title>
然后就是希望在开发模式下不要加载CDN,可以用👇的代码把production中的CDN引入包裹起来,这样在加载开发模式时,页面就不会加载引入的CDN了
<% if(htmlWebpackPlugin.options.isProd){ %>
//CDN
<% }%>
13.路由懒加载
在打包项目时,javascript的包会特别的大 ,影响页面的加载,需要把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应的组件,这样效果会更加高效
下载开发依赖包👆,然后在babel.config.js文件中👇
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins: [
[
'component',
{
libraryName: 'element-ui',
styleLibraryName: 'theme-chalk'
}
],
// 发布产品时候的插件数组
...proPlugins,
'@babel/plugin-syntax-dynamic-import'
]
}
然后就可以在路由中把不同的路径打包,如:👇,在webkpackChunkName中把login,home,welcome打包到一起加载,
const Login = () => import(/* webpackChunkName: 'login_home_welcome'*/ '../components/Login.vue')
const Home = () => import(/* webpackChunkName: 'login_home_welcome'*/ '../components/Home.vue')
const Welcome = () => import(/* webpackChunkName: 'login_home_welcome'*/ '../components/Welcome.vue')
14. 开启gzip配置
分为3步
npm i compression -D //安装相应的包
const compression = require("compression") //导入包
app.use(compression()) //启动(要写在静态的前面)
const express = require("express")
const compression = require("compression")
const app = express()
//
app.use(compression())//一定要写在静态之前
app.use(express.static('./dist'))
app.listen(80 , ()=>{
console.log("server running at http://127.0.0.1")
})