Vue项目总结
做这个项目前期比较生疏,后来就挺上手的了,这里总结一些项目中用到的小知识
路由跳转
嵌套
子页面在children里配置,如:path:'/home'带 / 路径是在根目录下,path:'home'不带 / 路径跟在其主页面路径后。redirect路由重定向,使用一个新的路由替换访问的目标路由
{
path: '/home',
name: 'Home',
component: Home,
redirect: '/welcome',
children: [
{
path: '/users',
component: User
},
]
}
传参
参数传递可以使用query和params,区别:query显示在路径上;params不会显示在路径上。
- 使用path来匹配路由,通过query来传递参数,通过 this.$route.qurey.变量名 取值
- 使用name名来匹配路由,要使用params来传递参数,使 this.$route.params.变量名 取值
登录状态无需验证
在登录后保存token到本地存储sessionStorage,下次进入时判断是否有token
methods: {
go() {
const { data: res } = await this.$axios.post('login', this.userInfo)
if (res.meta.status === 200) {
// 提示登陆成功
this.$message.success(res.meta.msg)
// 保存token状态
window.sessionStorage.setItem('token', res.data.token)
// 跳转
this.$router.push('/home')
} else {
this.$message.error('登录失败')
}
}
},
mounted() {
if (window.sessionStorage.getItem('token')) {
this.$router.push('/home')
}
}
上传图片
<template>
<el-tab-pane label="商品图片" name="3">
<el-upload class="upload-demo" :action="uploadURL" :on-preview="handlePreview" :on-remove="handleRemove" :file-list="fileList" list-type="picture" :on-success="handleSuccess" :headers="headerObj">
<el-button size="small" type="primary">点击上传</el-button>
<template #tip>
<div class="el-upload__tip">
只能上传 jpg/png 文件,且不超过 500kb
</div>
</template>
</el-upload>
</el-tab-pane>
</template>
export default {
data() {
return {
goodsValue: {
goods_name: '',
goods_price: 0,
pics: [],
},
previewPath: '',
previewVisible: false,
fileList: [],
// 地址
uploadURL: 'http://127.0.0.1:9000/api/private/v1/upload',
// 请求头
headerObj: {
Authorization: window.sessionStorage.getItem('token')
}
}
}
// 上传图片开始
// 预览
handlePreview(file) {
console.log('图片预览--------------', file)
this.previewPath = file.response.data.url
this.previewVisible = true
},
// 移除图片
handleRemove(file) {
// console.log(file)
// 1. 获取将要删除的图片的临时路径
const filePath = file.response.data.tmp_path
// 2. 从 pics 数组中,找到这个图片对应的索引值
const i = this.goodsValue.pics.findIndex(x => x.pic === filePath)
// 3. 调用数组的 splice 方法,把图片信息对象,从 pics 数组中移除
this.goodsValue.pics.splice(i, 1)
console.log('移除图片--------------', this.goodsValue)
},
// 上传成功
handleSuccess(response) {
console.log('上传图片--------------', response)
// 1. 拼接得到一个图片信息对象
const picInfo = { pic: response.data.tmp_path }
// 2. 将图片信息对象,push 到pics数组中
this.goodsValue.pics.push(picInfo)
console.log(this.goodsValue)
}
}
// 上传图片结束
组件传递
- 父传子: 父组件动态绑定一个属性,子组件通过props方式接受这个属性作为数据
- 子传父:子组件发射一个事件$emit,父组件接受事件以后调用相应的函数
- 兄弟相传: 使用一个空的Vue对象在第一个组件的点击事件中,使用on来接收事件
//父组件
<amend-user @updatelist="getUserList" :user="currentUser" ref="amendRef"></amend-user>
//子组件
export default {
props: ['user'],
methods: {
saveUserInfo() {
this.$refs.amendUserRef.validate(async valid => {
if (valid) {
const { data: res } = await this.$axios.put(`users/${this.user.id}`, this.user)
if (res.meta.status === 200) {
this.$emit('updatelist')
}
}
})
}
}
}
- 在echart图标部分用到了lodash工具lodash.merge()将两组数据合并
项目优化
-
添加进度条
nprogress --- npm install nprogress -S
api中导入nprogress和nprogress/nprogress.css,在拦截请求和响应请求时分别使用nprogress.start()和nprogress.done()
-
修改警告提示
buid--运行
template用的slot应为v-slot:slot名="scope"(如果没有用scope就空串)
-
去除打包的console.log
发布阶段 在打包阶段去掉console.log()
npm install babel-plugin-transform-remove-console -D
由于开发阶段不用去除,所以
在babel.config.js中配置plugins
const prodPlugins=[]
if(process.env.NODE_ENV==='production'){
prodPlugins.push('transform-remove-console')
}
module.exports={
plugins:[
...prodPlugins
]
}
-
完成打包多入口
vue.config.js中将开发阶段和发布阶段的打包入口分开
先分别创建main-prod.js和main-dev.js文件,在vue.config.js中配置如下代码:
module.exports = {
chainWebpack:config=>{
//发布模式
config.when(process.env.NODE_ENV === 'production',config=>{
//entry找到默认的打包入口,调用clear则是删除默认的打包入口
//add添加新的打包入口
config.entry('app').clear().add('./src/main-prod.js')
})
//开发模式
config.when(process.env.NODE_ENV === 'development',config=>{
config.entry('app').clear().add('./src/main-dev.js')
})
}
}
-
加载CDN
1)vue.config.js中
config.set('externals', {
vue: 'Vue',
'vue-router': 'VueRouter',
axios: 'axios',
echarts: 'echarts',
nprogress: 'NProgress',
moment: 'moment'
})
2)需要在index.html页面中添加CDN
但在开发阶段不需要加载CDN,所以在vue.config.js中配置
config.plugin('html').tap(args => {
args[0].isProd = true
return args
})
然后在index.html中用<%%>包裹script路径
<% if(htmlWebpackPlugin.options.isProd) { %>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.2/index.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/echarts/5.1.2/echarts.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.2.0/vue-router.min.js"></script>
<% } %>
需要注意的是要版本对应
6. 开启gzip压缩(服务器和前端都要进行配置)
这里有一个问题是 compression-webpack-plugin 使用版本不能太高
开启nginx部署: nginx 进行部署前端工程,nginx需要开启gzip压缩功能
nginx 给浏览器返回的gzip是实时压缩的,会造成nginx性能消耗,所以应该直接在nginx上放gzip,即前端打包的时候,直接打包成gzip文件
操作:
-
下载compression-webpack-plugin
-
vue.config.js中配置
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i
// gzip打包
configureWebpack: {
plugins: [
new CompressionWebpackPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: productionGzipExtensions,
threshold: 10240,
minRatio: 0.8,
deleteOriginalAssets: true
})
]
},
-
路由懒加载
- 没有指定webpackChunkName,每个组件打包成一个js文件
const 组件名=() => import('组件路径'); - 分组加载
把组件按组分块,指定了相同的webpackChunkName,会合并打包成一个js文件
const 组件名 = () => import(/* webpackChunkName: '组名' */ '组件路径')分组加载需先下载syntax-dynamic-import插件,在babel.config.js里将'@babel/plugin-syntax-dynamic-import'放入plugins中
项目优化完毕,dist文件夹里会有一个gzip文件,最后将dist文件夹放到服务器上