2019-10-22
卖座后台管理系统知识体系
目录
vue-cli3 创建项目(略)
重置样式和公共样式(略)
路由配置(略)
使用饿了么 ui 库,请看文档(略)
布局组件(已完成)
vue 原生点击事件(已完成)
vuex
axios 拦截器(完成一半)
打包部署项目
active-class
父子组件通信
vue-cli3 脚手架配置
五、布局组件
- 拷贝饿了么的布局容器
- 展开侧边栏的设置 :default-openeds 设置
- 样式调整
- layout 组件设置 padding-top
- 头部调整(固定定位)
- 侧边栏 html=>body=>#app>div>aside 高度全部设为 100%
六、vue 原生点击事件
在组件上添加事件的时候需要添加修饰符。native 来绑定事件,比如
<el-submenu index="2" @click.native="open('2')"></el-submenu>
八、axios 拦截器
文档地址:http://huruqing.cn/docs/Vue/advance/02.axios.html
在新建 /utils/request.js
-
使用 axios 创建实例,配置 baseUrl 和超时时间
const service = axios.create({ // 配置基本的路径 baseURL: 'http://132.232.87.95:3000/admin', timeout: 5000 // 请求超时时间(因为需要调试后台,所以设置得比较大) })
-
response 拦截器让我们在请求成功之后,统一做某些处理(完整的代码请看项目)
// response 拦截器 service.interceptors.response.use(res => { if (res.data.code == 666) { return res.data } else { return Promise.reject(res.data.msg); } }, error => { return Promise.reject(error) }); export default service;
把 axios 挂载在 Vue 的原型上
import $axios from '@/utils/request';
Vue.prototype.$axios = $axios;
- 发送请求只需要这样写
let url = "/city/getList";
this.$axios
.get(url)
.then(res => {
this.list = res.cities;
console.log(res.cities);
})
.catch(err => {
console.log(err);
});
九、打包部署项目(上线)
-
全局变量 process.env
let env = process.env.NODE_ENV; let baseURL = ''; // 开发环境 if (env === 'development') { baseURL = 'http://jun.huruqing.cn:3000/admin'; } else { // 生产环境 baseURL = 'http://jun.huruqing.cn:3000/admin'; }
web04 班因为条件限制,所以,开发和生产用同一套代码
-
配置打包路径和资源访问路径
-
新建 /vue.config.js, 代码如下
// 以陈灿为例 module.exports = { // 资源路径 publicPath: '/maizuo/chencan/', // 打包路径 outputDir: 'chencan', // 关闭eslint检查 lintOnSave: false }
-
执行 npm run build 命令,然后把生成的文件夹 chencan 上传到 jun.huruqing.cn/maizuo/
十、路由表和侧边栏配置
-
导出路由数组
export const routes = [];
-
导入路由数组
import {routes} from '@/router/index'
item.meta && item.meta.title => && 左边为 false 的时候,不会继续执行
-
设置默认值
function test(data) { data = data || {}; console.log(data.aa); }
十一、路由守卫
-
配置全局路由守卫
let routes = []; let router = new Router({ routes }) router.beforeEach((to, from, next) => { // 修改网页标题 document.title = to.meta.title; next(); }) export default router;
- to: Route: 即将要进入的目标 路由对象
- from: Route: 当前导航正要离开的路由
- next
利用路由守卫让没登录的时候,不管访问什么页面都调到登录页面
// 获取登录状态isLogi的值 this.$store.state
import store from '../store/index';
router.beforeEach((to, from, next) => {
// console.log('登录状态', store.state.isLogin);
// 修改网页标题
document.title = to.meta.title;
let isLogin = store.state.isLogin;
debugger;
// 如果没登录,并且去的页面不是登录页面, 就跳转到登陆页面
if (!isLogin && to.path !== '/login') {
next('/login');
} else {
next();
}
})
export default router;
十二、级联组件的使用 (影院模块的制作)
-
覆盖饿了么的样式
-
给组件起一个不会重复的 class, 模块名 + 组件名,比如
<div class="cinema-add"> // cinema模块的add组件
使用两个 style, 一个加 scoped, 另外一个不加
-
覆盖饿了么组件样式
<style lang="less"> .cinema-add { .el-cascader { display: block; } } </style>
// 下面的 style 用来写本组件的样式
<style lang="less" scoped> </style>
-
Promise.all, 同时发多个请求
// promise1,promise2都是promise对象 Promise.all([promise1,promise2]).then(res=> { // res是一个数组,返回两个promise的数据 })
// 获取城市列表和地区列表 getList() { let cityUrl = '/city/allCity'; let areaUrl = '/area/allArea'; // 获取城市列表的promise let cityPromise = this.$axios.get(cityUrl); // 获取地区列表的promise let areaPromise = this.$axios.get(areaUrl); Promise.all([cityPromise,areaPromise]).then(res=> { console.log(res); }).catch(err=> { this.$message.error(err); }) },
-
把城市列表和地区列表编程级联组件需要的数据格式
getList() { let cityUrl = "/city/allCity"; let areaUrl = "/area/allArea"; // 获取城市列表的promise let cityPromise = this.$axios.get(cityUrl); // 获取地区列表的promise let areaPromise = this.$axios.get(areaUrl); Promise.all([cityPromise, areaPromise]) .then(res => { // console.log(res); // 把城市列表和地区列表编程级联组件需要的数据格式 let cityList = res[0].cities; let areaList = res[1].areas; let newCityList = cityList.map(city => { // 找出城市对应的地区列表 let newAreaList = areaList.filter(area => { return area.cityId === city.cityId; }); // 地区列表变成组件需要的数据结构 newAreaList = newAreaList.map(area=> { return { value: area.areaId, label: area.name } }) return { value: city.cityId, label: city.name, children: newAreaList }; }); // console.log(newCityList); this.options = newCityList; }) .catch(err => { this.$message.error(err); });
级联组件添加清空,搜索,禁用
-
子组件向父组件传数据
-
父组件自定义事件
<Address @getAddress="getAddress"></Address> getAddress(data) { console.log('父组件收到的数据',data); },
-
自组件通过 $emit 触发父组件定义的自定义事件
handleChange(value) { this.$emit('getAddress',value); }
-
-
十三、请求的 loading 和 axios.finally
.finally 不管请求成功或失败都会执行回调
cinemaDetail(cinemaId) {
let loading = this.$loading({
lock: true,
text: "努力加载中...",
background: "rgba(0, 0, 0, 0.7)"
});
let url = "/cinema/getDetail2?cinemaId="+ cinemaId;
this.$axios.get(url).then(res => {
console.log(res);
}).catch(err => {
this.$message.error(err);
}).finally(()=> {
loading.close();
})
},
十四、动态路由配置
例子 1:
// 路由配置
{
path: 'edit/:cinemaId',
meta: {
title: 'edit'
},
component: () => import('@/pages/demo/edit')
},
// 页面跳转
<router-link to="/demo/edit/a1234444">去编辑</router-link>
// 获取cinemaId的值
this.$route.params.cinemaId;
例子 2: 传多个参数
// 路由配置
{
path: 'edit/:cinemaId/:cityId/:areaId',
meta: {
title: 'edit'
},
component: () => import('@/pages/demo/edit')
},
// 页面跳转
<router-link to="/demo/edit/a1234444/b234234/c1234234">去编辑</router-link>
// 获取cinemaId,cityId,areaId
let {cinemaId,cityId,areaId} = this.$route.params;
十五、添加和编辑共用同一个组件(以城市模块为例)
-
判断当前路由是添加还是编辑
-
方法一:获取 cityId, 有 cityId 为编辑页面,没有则是添加页面
this.$route.params.cityId;
具体代码如下
<template> <div> <el-button>{{isAdd?'立即添加':'立即编辑'}}</el-button> </div> </template> <script> export default { data() { return { // 是否是添加页面 isAdd: true }; }, created() { let cityId = this.$route.params.cityId; this.isAdd = !!cityId ? false : true; } }; </script>
-
方法二:通过 this.$route.path 来判断
<template> <div> <el-button>{{isAdd?'立即添加':'立即编辑'}}</el-button> </div> </template> <script> export default { data() { return {}; }, computed: { isAdd() { return this.$route.path.includes("add"); } } }; </script>
-
十六、命名规范
每个公司都有自己的命令规范,代码也有检查工具叫 eslint
- 文件统一大写或统一小写,跟你的同事保持一致
- 注意缩进
- 函数名一般是 动词 + 名词
- 函数命名和变量命名要语义化
- 组件名称首字母大写
十七、watch 的使用
- 监听路由
watch: {
$route(newRoute,oldRoute) {
// todo
}
}
- 深层监听
watch:{
childrens:{
handler:function(val,oldval){
console.log(val.name)
},
deep:true//对象内部的属性监听,也叫深度监听
},
}
- 立即执行
``
poster: {
handler(newName, oldName) {
// ...
},
immediate: true
}