1.项目的开发环境
开发依赖:
"dependencies": {
"axios": "^0.21.1",
"babel-plugin-transform-remove-console": "^6.9.4",
"core-js": "^3.6.5",
"echarts": "^5.1.2",
"element-ui": "^2.4.5",
"moment": "^2.29.1",
"nprogress": "^0.2.0",
"quill": "^1.3.6",
"vue": "^2.6.11",
"vue-quill-editor": "^3.0.6",
"vue-router": "^3.2.0",
"vue-table-with-tree-grid": "^0.2.4",
"vuex": "^3.4.0"
},
element-ui全局安装
vue add element-ui //在终端输入
这里可以看到让我们选择全部引入还是按需引入,此时我们选择按需引入 Import on demand
\
然后选择zh-CN,这时候我们可以看到此处多了一个plugins的文件夹,里面有一个element.js的文件,并main.js
中多了一个import的内容。然后如果我们仔细观察的话会发现其实babel.config.js也是注入了相关内容的。
element-ui ----> Form 表单
<template>
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="活动名称" prop="name">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">立即创建</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
ruleForm: {
name: ''
},
rules: {
name: [
{ required: true, message: '请输入活动名称', trigger: 'blur' },
{ min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }
]
}
}
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
// 验证成功执行此代码块
alert('submit!')
} else {
// 验证失败执行此代码块
console.log('error submit!!')
return false
}
})
},
resetForm(formName) {
// 重置表单
this.$refs[formName].resetFields()
}
}
}
</script>
ruleForm: input双向绑定的数据
rules: 表单的验证规则
prop: 为需校验的字段名
element-ui ----> Cascader 级联选择器
<el-cascader v-model="value" :options="options" @change="handleChange"></el-cascader>
options: 可选项数据源,键名可通过 Props 属性配置
Props:
expandTrigger: 次级菜单的展开方式 可选择click/hover 默认'click'
checkStrictly: 是否严格的遵守父子节点不互相关联
value: 指定选项的值为选项对象的某个属性值
label: 指定选项标签为选项对象的某个属性值
children: 指定选项的子选项为选项对象的某个属性值
element-ui ----> Pagination 分页
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage4"
:page-sizes="[100, 200, 300, 400]"
:page-size="100" layout="total, sizes, prev, pager, next, jumper"
:total="400">
</el-pagination>
size-change和current-change: 事件来处理页码大小和当前页变动时候触发的事件
page-sizes: 接受一个整型数组,数组元素为展示的选择每页显示个数的选项,[100, 200, 300, 400]表示四个选项,每页显示 100 个,200 个,300 个或者 400 个数据
total: 表示数据的总数
2. 登录界面的实现
当用户点击了登录按钮时,进行数据请求,同时将登录成功之后的 token,保存到客户端的 sessionStorage 中,然后进行路由跳转.同时在axios的请求拦截器中携带token.最后再使用路由的全局前置守卫进行读取sessionStorage里面存储的进行判断是否有值,有值进行跳转,否则返回登录页面.
登录按钮的点击事件
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (!valid) return
this.$http.post('login', this.ruleForm).then(res => {
console.log(res.data)
if (res.data.meta.status !== 200) return this.$message.error('登录失败!')
this.$message.success('登录成功')
// 1. 将登录成功之后的 token,保存到客户端的 sessionStorage 中
// 1.1 项目中出了登录之外的其他API接口,必须在登录之后才能访问
// 1.2 token 只应在当前网站打开期间生效,所以将 token 保存在 sessionStorage 中
window.sessionStorage.setItem('token', res.data.data.token)
// 2. 通过编程式导航跳转到后台主页,路由地址是 /home
this.$router.push('/home')
})
})
},
})
请求拦截器
axios.interceptors.request.use((config) => {
// 这个config里面要携带token
config.headers.Authorization = window.sessionStorage.getItem('token') || ''
return config
})
全局前置守卫
router.beforeEach((to, from, next) => {
// to 将要访问的路径
// from 代表从哪个路径跳转而来
// next 是一个函数,表示放行
// next() 放行 next('/login') 强制跳转
if (to.path === '/login') return next()
// 获取token
const tokenStr = window.sessionStorage.getItem('token')
if (!tokenStr) return next('/login')
next()
})
3.整个页面的布局是基于的element-ui常用的组件中的Container 布局容器实现的
<el-container>
<el-header>Header</el-header> //头部
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-main>Main</el-main>
</el-container>
</el-container>
4. 项目 ---->优化
4.1. 给项目添加进度条,使用nprogress
安装命令 npm install nprogress -S // nprogress里面有start() done()这两个方法
配置:
1.首先在封装的axios里面导入nprogress
import NProgress from 'nprogress'
2. 在请求拦截器里面添加 NProgress.start() //什么时候开始
3. 在响应拦截器里面添加 NProgress.done() //什么时候完成
4.2. 修改打包时的警告提示和错误
4.3 去除打包的console.log (发布阶段在打包阶段去掉console.log() )
可以使用 babel-plugin-transform-remove-console来自动去除console.log()
安装命令 npm install babel-plugin-transform-remove-console -D
配置: 在babel.config.js中配置如下内容
const proPlugins = []
if (process.env.NODE_ENV === 'production') {
proPlugins.push('transform-remove-console')
}
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins: [
...proPlugins // 展开数组
]
}
4.4. 完成打包多入口,将开发阶段和发布阶段的打包入口分开
新创建一个main-dev.js 和 main-prod.js把原来main.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')
})
}
}
4.5. 将引用本地文件的东西替换成CDN加载
首先在vue.config.js中上面配置的发布模式中添加如下内容
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',
echarts: 'echarts',
nprogress: 'NProgress',
moment: 'moment',
lodash: '_',
quill: 'quill'
})
// html-webpack-plugin 将index进行赋值 isProd 似乎是开发阶段
config.plugin('html').tap(args => {
args[0].isProd = true
return args
})
})
然后在public目录下的index.html中引入CDN,如下: (注意版本一定要统一!!!!)
<% 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/vue-router/3.2.0/vue-router.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/lodash.js/4.17.21/lodash.core.min.js"></script>
<!-- moment -->
<script src="https://cdn.bootcdn.net/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<!-- elementUI -->
<script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.2/index.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.2/theme-chalk/index.min.css" rel="stylesheet">
<link href="https://cdn.bootcdn.net/ajax/libs/quill/1.3.6/quill.snow.min.css" rel="stylesheet">
<% } %>
4.6. 启用GZIP压缩功能
在vue.config.js中配置如下内容:
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const productionGzipExtensions = ['js', 'css']
configureWebpack: {
plugins: [
// 配置compression-webpack-plugin压缩
new CompressionWebpackPlugin({
algorithm: 'gzip',
test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
threshold: 10240,
minRatio: 0.8
})
]
4.7. 开启路由懒加载
{
path: 'welcome',
component: () => import('../views/Welcome.vue')
},