demo地址:vue3
项目目录结构如下图所示(这个图是项目搭建完成后的图,项目刚创建完的话,有些文件是没有的(vue.config,api.lib,config这些文件刚创建的项目应该都没有)):
npm install element-plus --save
在main.js中
import ElementPlus from 'element-plus';
import 'element-plus/lib/theme-chalk/index.css';
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
参考链接:elementPlus官网
vue-axios是一个vue整合axios的工具
npm install --save axios vue-axios
//在main.js中
.use(VueAxios, axios)
参考链接:http://www.axios-js.com/zh-cn/docs/vue-axios.html
npm install --save less less-loader
import { createApp } from 'vue';
import App from './App.vue';
import router from './router/index';
import store from './store';
import ElementPlus from 'element-plus'; //引入elementPLus
import 'element-plus/lib/theme-chalk/index.css'; //elementPlus的css
import axios from 'axios'; //axios请求插件
import VueAxios from 'vue-axios'; //可以让vue直接使用(use)axios的小插件
import config from '@/config'; //配置后端请求地址的文件
//创建app
const app = createApp(App);
app.config.globalProperties = config; //后端请求地址
app.use(store)
.use(router)
.use(ElementPlus)
.use(VueAxios, axios)
.mount('#app');
export default app
其实这个js有用的只有baseUrl
export default {
/**
* @description 配置显示在浏览器标签的title
*/
// title: '测试',
/**
* @description api请求基础路径
*/
baseUrl: {
dev: 'http://localhost:8080/', // 我的主机
pro: '/'//线上服务器地址
},
/**
* @description 默认打开的首页的路由name值,默认为home
*/
// homeName: 'home',
}
配置后可以全局使用特定文件夹里面的css、less。
vue.config.js里面(这里是整个文件的js):
const path = require('path');
const resolve = dir => {
return path.join(__dirname, dir)
};
/**
*默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上,
*例如 https://www.my-app.com/。
*如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。
*如果你的应用被部署在 https://www.my-app.com/my-app/,
*则设置 publicPath 为 /my-app/。
*这个值也可以被设置为空字符串 ('') 或是相对路径 ('./'),这样所有的资源都会被链接为相对路径,
*这样打出来的包可以被部署在任意路径,也可以用在类似 Cordova hybrid 应用的文件系统中。
*/
const PUBLIC_PATH = process.env.NODE_ENV === 'production' ? '/' : '/';
/**
* 引入全局的less文件
* @param {*} rule
*/
const addStyleResource = (rule) => {
rule.use('style-resource')
.loader('style-resources-loader')
.options({
patterns: [
// 需要全局导入的less,这个地方一点要写./src才行,否则会报错...
path.resolve(__dirname, './src/assets/css/publicCss.less')
]
});
};
module.exports = {
// 选项...
publicPath:PUBLIC_PATH,
chainWebpack: config => {
const types = ['vue-modules', 'vue', 'normal-modules', 'normal'];
types.forEach(type => addStyleResource(config.module.rule('less').oneOf(type))); //轮询加载全局样式
config.resolve.alias
//配置@指向src
.set('@', resolve('src')) // key,value自行定义,比如.set('@@', resolve('src/components'))
//配置_c指向src
.set('_c', resolve('src/components'))
},
devServer: {
overlay: {
warnings: true,
errors: true
}
},
css: {
loaderOptions: {
less: {
javascriptEnabled: true
}
}
}
};
我的文件名是axios.js
import axios from "axios";
import app from '@/main';
// 退出登录
const logout = () => {
app.config.globalProperties.$router.push({name: 'login'});
clearAllSessionStorage()
};
// 清空sessionStorage
const clearAllSessionStorage = () => {
sessionStorage.removeItem('token')
}
// 响应拦截
const respFilter = res => {
// elementPlus的信息提示
let message = app.config.globalProperties.$message;
let msg = {"content": res.data.message, "duration": 5};
let code = res.data.code;
let method = res.config.method;
if (method) {
method = method.toLowerCase();
}
if ((method !== 'options') && code === 'timeout') {
logout()
} else if (code === 'Unauthorized') {
message.error(msg);
} else if (code === 'system_error') {
message.error(msg);
}
if (res.data.success === false) {
message.error(msg);
}
};
class HttpRequest {
constructor(baseUrl = baseURL) {
this.baseUrl = baseUrl;
this.queue = {}
}
getInsideConfig() {
return {
baseURL: this.baseUrl,
headers: {
token: localStorage.getItem('token') || '',
}
}
}
interceptors(instance) {
// 请求拦截
instance.interceptors.request.use(config => {
return config
}, error => {
return Promise.reject(error)
});
// 响应拦截
instance.interceptors.response.use(
res => {
respFilter(res);
const {data, status, headers} = res;
return {data, status, headers}
},
error => {
return Promise.reject(error)
})
}
request(options) {
const instance = axios.create();
options = Object.assign(this.getInsideConfig(), options);
this.interceptors(instance, options.url);
return instance(options)
}
}
export default HttpRequest
文件名request.js
import HttpRequest from './axios';
import config from '@/config';
const baseUrl = process.env.NODE_ENV === 'development' ? config.baseUrl.dev : config.baseUrl.pro;
const axios = new HttpRequest(baseUrl);
export default axios
src/store/index.js
import { createStore } from 'vuex'
import user from './module/user'
export default createStore({
state: {
},
mutations: {
},
actions: {
},
modules: {
user,
}
})
src/store/module/user.js
import {login} from "@/api/user";
export default {
state:{
},
mutations:{
},
actions:{
userLogin({commit},data){
return new Promise((resolve, reject) => {
login(data).then(res => resolve(res)).catch(error => reject(error))
})
}
}
}
src/api/user.js
import axios from '@/lib/request'
export const login = (data) =>{
return axios.request({
url: 'login',
data: data,
method: 'post'
})
}
以登陆为例
login
src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Routes from '@/router/routers';
// 导入routers的路由
const routes = Routes;
// 创建初始化router
const router = createRouter({
/**
* hash模式:createWebHashHistory,
* history模式:createWebHistory
*/
history: createWebHistory(),
routes:routes,
});
//配置导航守卫
router.beforeEach((to,from,next) => {
//如果访问的是登录页,直接放行
if(to.path === '/login') return next();
// 获取token
// const userInfo = sessionStorage.getItem('token');
const userInfo = '565432';
// 判断token是否存在,如果不存在返回登录页,存在就允许跳转
if(!userInfo) return next('/login');
next()
});
export default router
src/router/routers/index.js
import main from '@/components/index.vue'
import view from '@/components/menus/menu.vue'
/**
*
* 路由配置规则:
* 一级菜单的component必须为 main||() => import('@/components/index.vue')
* {
* path:'',路径
* name:'',路由名称,生成menu时menu显示的name
* breadcrumb: boolean值,true是可以点击面包屑跳转到对应页面,false||不写||null||unfinde不跳转
* ---------- ps:一般父级菜单项都不跳转
* redirect:'', 路由转发,可以转发到另外一个页面。
* -------------例如:访问 / 会转发到home再转发到 /home/index,/home/index才是需要显示的首页
* isShow:'', 是否显示为菜单,为TRUE时为菜单,false不是菜单不会在导航栏显示
* icon:'',图标,显示在名称前面的图标
* children: [], 子路由,menu中的子menu 没有时可为空数组或者不填,
* ----------- 当一个菜单有三级或者以上的时候需要在他的父级使用:
* ----------- component:view||component: () => import('@/components/menus/menu.vue'),这个属性才能显示出多子级菜单
* }
*
*/
const Routes = [
{
path: '/',
redirect: '/home',
isShow: false
},
{
path: '/login',
name: '登录',
isShow: false,
component: () => import('@/components/login/login.vue'),
},
{
path: '/home',
name: '首页',
isShow: false,
component:main,
breadcrumb:true,
redirect:'/home/index',
children:[
{
path: '/home/index',
isShow: false,
icon: 'el-icon-s-home',
component: () => import('@/views/home.vue'),
},
]
},
{
path: '/system',
name: '系统管理',
isShow: true,
icon: 'el-icon-s-home',
breadcrumb:false,
component:main,
children:[
{
path: 'user',
name: '用户管理',
isShow: true,
icon: 'el-icon-user',
component:view,
children:[
{
path: '/system/user/home',
name: '添加用户',
isShow: true,
icon: 'el-icon-user',
breadcrumb:true,
component: () => import('@/views/system/Home.vue')
},
{
path: '/system/user/user',
name: '用户列表',
isShow: true,
icon: 'el-icon-user',
breadcrumb:true,
component: () => import('@/views/system/user.vue')
}
]
},
{
path: '/system/doc',
name: '文档',
isShow: true,
breadcrumb:true,
icon: 'el-icon-s-order',
component: () => import('@/views/system/About.vue'),
},
]
},
{
path: '/chart',
name: '图表',
isShow: true,
breadcrumb:true,
icon: 'el-icon-s-order',
component:main,
children:[
{
path: '/chart/echarts',
name: '柱状图',
isShow: true,
breadcrumb:true,
icon: 'el-icon-s-order',
component:() => import('@/views/system/echarts.vue')
}
]
},
];
export default Routes;
app.vue中添加
src/components/index.vue文件(页面布局文件)
左侧导航采用递归展示菜单
src/components/Sidebar/index.vue
vue3练习
src/components/Sidebar/sidebar.vue
{{item.name}}
{{item.name}}
到这项目基本就搭建完成了,缺少的主题内容和头部内容随便创建个组件就可以了(当然最主要的是它太长了QAQ),以后可能会拆分。