项目前期准备
- 创建项目:
- cmd命令行:vue init webpack 项目名 --> vue init webpack shop-admin(yyyyynnny)
- cd shop-admin进入项目
- 安装vuex:npm i vuex(状态管理模式)
- https://vuex.vuejs.org/zh/guide/
*创建src/store/index.js文件
import Vue from "vue"
import Vuex from "vuex"
// 安装插件
Vue.use(Vuex);
// store-> vuex 实例
let store = new Vuex.Store({
})
export default store
*在main.js中引入并应用
+ import store from "./store"
new Vue({
+ store,// 组件应用vuex实例
})
- 安装axios:npm i axios(请求数据)
- http://www.axios-js.com/
*创建src/utils/http.js文件
import axios from "axios"
import store from "@/store"
import router from "@/router"
import qs from "qs"
axios.interceptors.request.use(config => {
// Do something before request is sent
// console.log(config)
// 使用qs 进行post加密和取消两次请求
if(config.method=="post"){
config.data = qs.stringify(config.data)
}
let token = localStorage.getItem("info") ? JSON.parse(localStorage.getItem("info")).token : "";
// 每一次请求都会尝试获取token
// 每一请求带上token
config.headers.Authorization = token;
return config;
}, error => {
// Do something with request error
return Promise.reject(error);
});
axios.interceptors.response.use(response => {
// Do something before response is sent
//处理过期 说明token已过期
if (response.data.code == 403) {
// 清空登录数据
localStorage.clear();
store.commit("CLEAR_INFO");
// 跳转到 登录页
router.replace("/login");
}
return response.data;
}, error => {
// Do something with response error
return Promise.reject(error);
});
// 产生不同axios 实例处理图片上传问题
let upload = axios.create()
upload.interceptors.request.use(config => {
// Do something before request is sent
let token = localStorage.getItem("info") ? JSON.parse(localStorage.getItem("info")).token : "";
// 每一次请求都会尝试获取token
// 每一请求带上token
config.headers.Authorization = token;
// 改写上传文件的请求头
config.headers['Content-Type'] = "multipart/form-data";
//上传文件需要的容器,空容器
let formData = new FormData();
// 容器使用 append 方法添加数据
for (var key in config.data) {
formData.append(key, config.data[key]);
}
config.data = formData;
return config;
}, error => {
// Do something with request error
return Promise.reject(error);
});
upload.interceptors.response.use(response => {
// Do something before response is sent
//处理过期 说明token已过期
if (response.data.code == 403) {
// 清空登录数据
localStorage.clear();
store.commit("CLEAR_INFO");
// 跳转到 登录页
router.replace("/login");
}
return response.data;
}, error => {
// Do something with response error
return Promise.reject(error);
});
export default {
axios,upload}
- 将axios请求响应拦截器应用全局(main.js)
import http from "@/utils/http" // 给默认抛出的对象取名为http
Vue.prototype.$http = http.axios
Vue.prototype.$upload = http.upload
// 设置域名
Vue.prototype.$domain = "http://localhost:3000"
- 安装element-ui:npm i element-ui -S
- https://element.eleme.io/
*在main.js中引入
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
- 安装less:npm i less less-loader@5.0.0 -D
*应用
//scoped属性,style标签中样式只对当前组件生效
<script lang='less' scoped>
设置跨域代理
//设置跨域代理
proxyTable: {
"/api":{
target:"http://localhost:3000"
}
},
// Various Dev Server settings
host: 'localhost', // can be overwritten by process.env.HOST
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
autoOpenBrowser: true,// 设置设置自动开启浏览器
路由router/index.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
let router = new Router({
routes: [
{
path: '/login',
component:()=>import("@/pages/Login")
},
{
path: '/',
component:()=>import("@/pages/Layout"),
children:[{
path:"index",
component:()=>import("@/pages/Index")
},{
path:"menu",
component:()=>import("@/pages/Menu")
},{
path:"role",
component:()=>import("@/pages/Role")
},{
path:"user",
component:()=>import("@/pages/User")
},{
path:"category",
component:()=>import("@/pages/Cate")
},{
path:"specs",
component:()=>import("@/pages/Specs")
},{
path:"goods",
component:()=>import("@/pages/Goods")
},{
path:"*",
redirect:"/index"
}]
}
]
})
router.beforeEach((to,from,next)=>{
// 以是否存在token判断是否登录
let token = localStorage.getItem("info")?JSON.parse(localStorage.getItem("info")).token:false;
// 后台允许该账号访问的前端页面路由
let urls = localStorage.getItem("info")?JSON.parse(localStorage.getItem("info")).menus_url:[];
if(token){
if(to.path=="/login"){
next(false);
}else{
// 添加后台没有的路由
urls.push("/","/index")
// 判断前往路由是否是后台允许访问的路由
let flag = urls.indexOf(to.path)>-1;
// let flag = urls.includes(to.path)
console.log(flag)
// 可以访问
if(flag){
next()
}else{
// 不可以访问的
next(false)
}
}
}else{
// 未登录
if(to.path=="/login"){
next()
}else{
next("/login")
}
}
})
export default router
store/index.js
- 组件之间通信(登录的用户名显示在layout头部)
import Vue from "vue"
import Vuex from "Vuex"
Vue.use(Vuex);
// localStorage 中存在info,说明已登录,vuex重新刷新,会被重制,可以从localStorage中获取一份
let info = localStorage.getItem("info")? JSON.parse(localStorage.getItem("info")):{
};
let store = new Vuex.Store({
state:{
// 登录的用户信息
info
},
getters:{
username:state=>state.info.username
},
mutations:{
SET_INFO(state,info){
state.info = info;
},
CLEAR_INFO(state){
state.info={
}
}
}
})
export default store
登录页(一级路由)
- 使用rules定义的验证规则进行验证的方法
- 回调函数在验证结束后触发,回调参数就是验证结果
- valid: true->验证通过,false 验证失败
- 验证通过发送请求
- 成功:
- 1.数据持久化,数据保存在localStorage中,页面刷新,vuex中数据会重置
- 2.提交mutation,数据保存在 vuex中