在bilibili上学习一个vue项目:https://www.bilibili.com/video/BV1KJ411U7ML?p=149
配套资源:
https://pan.baidu.com/s/1FX_1sz0Xj-0r1R_E12Qh1g
提取码: 8exy
联系项目代码:https://gitee.com/sicauliuyang/vue_shop
dist:存放build后可以直接部署的代码
node_modules:项目按照的依赖等资源库
public:存放的静态资源都会被简单的复制,而不经过 webpack
components: 存放自定义的vue组件
plugins :插件
router.index.js:路由配置
mian-dev.js:开发全局js,用于配置引入依赖等
main-prod.js:部署运行全局js
.estlintr.js:estlin规范配置文件
babel.config.js:babel配置
package-lock.json:就是锁定安装时的包的版本号,并且需要上传到git,以保证其他人在npm install时大家的依赖能保证一致。
package.json:安装依赖的版本号等信息
vue.config.js:修改webpack配置
路由配置主要在router.index.js中
路由导航守卫控制访问权限
在路由入口js文件中,配置路由导航访问控制权限功能。注意:需要在暴露该路由对象之前进行配置
// 挂载路由导航守卫
router.beforeEach((to, from, next) => {
// to 将要访问的路径
// from 代表从哪个页面跳转而来
// next 是一个函数, 表示放行
// next() 放行 next('/') 强制跳转
// 首页直接放行
if (to.path === '/login') return next()
// 获取token
const tokenStr = window.sessionStorage.getItem('token')
// token不为空,放行
if (!tokenStr) return next('/login')next()
})
export default router
<el-menu router>
<el-submenu :index="item.id + ''" v-for=“item in menus" :key="item.id">
<template slot="title">
<span>{{item.authName}}span>
template>
<el-menu-item :index="'/' + subItem.path" v-for="subItem in item.children" :key="subItem.id" >
<span slot="title">{{subItem.authName}}span>
el-menu-item>
el-submenu>
el-menu>
https://router.vuejs.org/zh/guide/advanced/lazy-loading.html
// 引入axios库,用于通信
import axios from 'axios'
// 配置请求的根路径
axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1/'
// 给请求头添加Authorization
axios.interceptors.request.use(config => {
//
config.headers.Authorization = window.sessionStorage.getItem('token')
return config
})
// 在response拦截器中,隐藏进度条
axios.interceptors.response.use(config => {
return config
})
// 每一个this组件都可以通过this.$http来发起请求
Vue.prototype.$http = axios
整体布局:先上下划分,再左右划分
在登陆函数中,当登陆成功后,把服务器传过来的token保存到window对象中的sessionStorage中。并跳转到主页中
// 登录成功后需要将服务器端传过来的token保存到sessionStorage中
window.sessionStorage.setItem('token',res.data.token);
// 通过编程式导航跳转到后台主页,路由地址为/home
this.$router.push("/home");
电击退出按钮,清空token,返回登陆页
module.exports = {
chainWebpack: config => {
config.when(process.env.NODE_ENV === 'production', config => {
// 配置项目发布时使用的全局js
config.entry('app').clear().add('./src/main-prod.js')
// 使用externals设置排除项
config.set('externals', {
vue: 'Vue',
'vue-router': 'VueRouter',
axios: 'axios',
lodash: '_',
echarts: 'echarts',
nprogress: 'NProgress',
'vue-quill-editor': 'VueQuillEditor'
})
// 使用html插件,声明一个isProd变量
config.plugin('html').tap(args => {
args[0].isProd = true
return args
})
})
config.when(process.env.NODE_ENV === 'development', config => {
// 配置项目开发时使用的全局js
config.entry('app').clear().add('./src/main-dev.js')
// 使用html插件,声明一个isProd变量
config.plugin('html').tap(args => {
args[0].isProd = false
return args
})
})
}
}
默认情况下,依赖项的所有第三方包都会被打包到js/chunk-vendors.******.js文件中,导致该js文件过大,可以通过externals排除这些包,使它们不被打包到js/chunk-vendors.******.js文件中
如上代码
<link rel="stylesheet" href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" />
<link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.core.min.css" />
<link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.snow.min.css" />
<link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.bubble.min.css" />
<link rel="stylesheet" href="https://cdn.staticfile.org/element-ui/2.8.2/theme-chalk/index.css" />
<script src="https://cdn.staticfile.org/vue/2.5.22/vue.min.js">script>
<script src="https://cdn.staticfile.org/vue-router/3.0.1/vue-router.min.js">script>
<script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js">script>
<script src="https://cdn.staticfile.org/lodash.js/4.17.11/lodash.min.js">script>
<script src="https://cdn.staticfile.org/echarts/4.1.0/echarts.min.js">script>
<script src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js">script>
<script src="https://cdn.staticfile.org/quill/1.3.4/quill.min.js">script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue-quill-editor.js">script>
<script src="https://cdn.staticfile.org/element-ui/2.8.2/index.js">script>
对应删除main.js中的引用
为了使开发测试不收干扰
在vue.config.js中获取html插件,添加变量,在index.html中进行判断
<% if(htmlWebpackPlugin.options.isProd) { %>
<link rel="stylesheet" href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" />
<link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.core.min.css" />
<link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.snow.min.css" />
<link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.bubble.min.css" />
<link rel="stylesheet" href="https://cdn.staticfile.org/element-ui/2.8.2/theme-chalk/index.css" />
<script src="https://cdn.staticfile.org/vue/2.5.22/vue.min.js">script>
<script src="https://cdn.staticfile.org/vue-router/3.0.1/vue-router.min.js">script>
<script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js">script>
<script src="https://cdn.staticfile.org/lodash.js/4.17.11/lodash.min.js">script>
<script src="https://cdn.staticfile.org/echarts/4.1.0/echarts.min.js">script>
<script src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js">script>
<script src="https://cdn.staticfile.org/quill/1.3.4/quill.min.js">script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue-quill-editor.js">script>
<script src="https://cdn.staticfile.org/element-ui/2.8.2/index.js">script>
<% } %>
// 导入express对象
const express = require('express')
const app = express()
app.use(express.static('./dist'))
// 开启8998监听
app.listen(8998,()=>{
console.log("server running at http://127.0.0.1:8998")
})
打开vue_shop_server文件夹的终端,输入命令:npm i compression -D
打开app.js,编写代码:
const express = require('express')
const compression = require('compression')
const app = express()
app.use(compression())
app.use(express.static('./dist'))
app.listen(8998,()=>{
console.log("server running at http://127.0.0.1:8998")
})
配置https服务一般是后台进行处理,前端开发人员了解即可。
首先,需要申请SSL证书,进入https://freessl.cn官网 在后台导入证书,打开今天资料/素材,复制素材中的两个文件到vue_shop_server中
打开app.js文件,编写代码导入证书,并开启https服务
const express = require('express')
const compression = require('compression')
const https = require('https')
const fs = require('fs')
const app = express()//创建配置对象设置公钥和私钥
const options = {
// 下载的证书文件
cert:fs.readFileSync('./full_chain.pem'),
key:fs.readFileSync('./private.key')
}
app.use(compression())
app.use(express.static('./dist'))
//启动https服务
https.createServer(options,app).listen(443)
注意:因为我们使用的证书有问题,所以无法正常使用https服务
打开vue_shop_server文件夹的终端,输入命令:npm i pm2 -g
使用pm2启动项目,在终端中输入命令:pm2 start app.js --name 自定义名称
查看项目列表命令:pm2 ls
重启项目:pm2 restart 自定义名称
停止项目:pm2 stop 自定义名称
删除项目:pm2 delete 自定义名称
使用element-ui 的Container布局元素
这里需要引入对应的布局元素,去掉前面的el,去掉字母大写
el-container : Container
布局元素的class类,默认和名字相同 el-container 的一个类:el-container
使用NavMenu布局
获取表单对象,并调用表单对象的validate方法,该方法有一个返回函数,其参数为一个布尔值,当验证为真时返回 true,否则返回false
this.$refs.loginFormRef.validate(valid => {
//未通过验证
if (!valid) return
//通过验证
})
获取表单对象,并调用表单对象的resetFields方法
$nextTick 的执行时机: DOM 更新完毕之后
<el-button size="small" v-else @click="showTagInput(scope.row)">+ New Tag</el-button>
showTagInput(row) {
row.tagInputVisible = true
// 当我们修改了 data 中 tagInputVisible 的值以后,如果要操作文本框,必须等页面重新渲染完毕之后才可以,所以,必须把操作文本框的代码放到 $nextTick 中,当作回调去执行($nextTick 的执行时机,是在 DOM 更新完毕之后)
this.$nextTick(() => {
this.$refs.saveTagInput.$refs.input.focus()
})
}
// 时间格式过滤器
Vue.filter('dateFormat', function (originVal) {
// 获取时间对象
const dt = new Date(originVal)
// 年
const y = dt.getFullYear()
// 月 getMonth返回的是从0 开始的,所以需要加1;如果不是两位,在前面补0
const m = (dt.getMonth() + 1 + '').padStart(2, '0')
// 日
const d = (dt.getDate() + '').padStart(2, '0')
// 时
const hh = (dt.getHours() + '').padStart(2, '0')
// 分
const mm = (dt.getMinutes() + '').padStart(2, '0')
// 时
const ss = (dt.getSeconds() + '').padStart(2, '0')
// 'yyyy-mm-dd hh:mm:ss'
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
})
这是一个用同步的思维来解决异步问题的方案,当前端接口调用需要等到接口返回值以后渲染页面时。
async
async的用法,它作为一个关键字放到函数前面,用于表示函数是一个异步函数,因为async就是异步的意思, 异步函数也就意味着该函数的执行不会阻塞后面代码的执行,async 函数返回的是一个promise 对象。
await
await的含义为等待。意思就是代码需要等待await后面的函数运行完并且有了返回结果之后,才继续执行下面的代码。这正是同步的效果
login() {
this.$refs.loginFormRef.validate(async valid => {
if (!valid) return;
const { data: res } = await this.$http.post('login', this.loginForm);
if(res.meta.status == 200){
console.log(res.meta.msg);
}
})
}
基本使用 https://github.com/MisterTaki/vue-table-with-tree-grid)
效果
字符串分割为数组
data.forEach(item => {
item.attr = item.attr.length === 0 ? [] : item.attr.split(' ')
})
vue-quill-editor:富文本编辑器
基本使用:https://github.com/surmon-china/vue-quill-editor
lodash进行深拷贝
nprogress:进度条效果
使用:https://github.com/rstacruz/nprogress
//导入进度条插件
import NProgress from 'nprogress'
//导入进度条样式
import 'nprogress/nprogress.css'
.....
//请求在到达服务器之前,先会调用use中的这个回调函数来添加请求头信息
axios.interceptors.request.use(config => {
//当进入request拦截器,表示发送了请求,我们就开启进度条
NProgress.start()
//为请求头对象,添加token验证的Authorization字段
config.headers.Authorization = window.sessionStorage.getItem("token")
//必须返回config
return config
})
//在response拦截器中,隐藏进度条
axios.interceptors.response.use(config =>{
//当进入response拦截器,表示请求已经结束,我们就结束进度条
NProgress.done()
return config
})
项目发布时,移除其中console.*
在babel.config.js中配置
//项目发布阶段需要用到的babel插件
const productPlugins = []
//判断是开发还是发布阶段
if(process.env.NODE_ENV === 'production'){
//发布阶段
productPlugins.push("transform-remove-console")
}
module.exports = {
"presets": [
"@vue/app"
],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
],
...productPlugins
]
}