目录
2.创建一个文件夹,这里创建了名为VueProject的文件夹,进入该文件的cmd。这里原本是空的,只不过我执行完第3步命令之后生成的东西。
一、项目创建
1 首先保证安装node.js 与 Vue
2.创建一个文件夹,这里创建了名为VueProject的文件夹,进入该文件的cmd。这里原本是空的,只不过我执行完第3步命令之后生成的东西。
2.1 在cmd里面执行
1. npm init -y 进行初始化
2. npm i -D @vue/cli 创建脚手架
3. npx vue -V 查看脚手架版本
4. npx vue create project-one 通过脚手架构建
这里会让你选择创建vue的哪个版本,我选择的是vue2,选择之后回车,就开始下载了。
构建完成了一个名为project-one的项目
cd project-one
执行npm run serve,build中。。。。。
打开浏览器,访问localhost:8080
目录
二、项目配置
进入project-one文件夹,输入code . 就会用vscode打开该项目了。
配置运行npm run serve 自动打开
三、项目实战
3.1 整合elementUI
进入project-one文件夹,进入cmd,执行npm i element-ui -S。
在package.json里面会多出elementUI的东西。
依赖导入了,进行引用,进入src->main.js里面。
import ElementUI from 'element-ui' //引入ElementUI
import 'element-ui/lib/theme-chalk/index.css' //导入样式
Vue.use(ElementUI) //使用
修改原始HelloWorld.vue 改为Home.vue,修改app.vue
最终效果
3.2 axios安装
进入项目cmd,运行npm i axios -S
进入main.js,配置全局使用
import axios from 'axios' //引入axios
Vue.prototype.axios = axios // 挂载到原型上,可以全局使用
3.3 路由安装
进入项目cmd,运行npm i vue-router@3.5.3 -S 因为用的是Vue2版本,所以定义一下router的版本。
安装完进行配置,在src目录下新建文件夹router,在该文件夹下创建index.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from '../components/Home.vue'
Vue.use(Router)
export default new Router({
routes:[
{
path:'/',
component:Home
}
],
mode:'history'
})
使用,在main.js里面导入并在渲染之前挂载一下
在app.vue里面加入路由出口, <router-view></router-view>
最终显示
3.3.1 路由懒加载
不需要import Home...,只需要在componet后面加import
import Vue from 'vue'
import Router from 'vue-router'
// import Home from '../components/Home.vue'
Vue.use(Router)
export default new Router({
routes:[
{
path:'/home',
component:()=> import('@/components/Home')
}
],
mode:'history'
})
3.3.2 异步组件
import Vue from 'vue'
import Router from 'vue-router'
// import Home from '../components/Home.vue'
Vue.use(Router)
export default new Router({
routes:[
{
path:'/home',
// component:()=> import('@/components/Home') //路由懒加载
component:resolve => require(['@/components/Home'],resolve) // 异步组件
}
],
mode:'history'
})
3.4 登陆页面实现
component文件夹创建Login.vue
<template>
<div class="login">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>通用后台管理系统</span>
</div>
<el-form label-width="80px" :model="form" ref="form">
<el-form-item label="用户名" prop="username"
:rules="[
{required:true,message:'请输入用户名', trigger:'blur'},
{min:4,max:10,message:'长度在4-10位字符之间', trigger:'blur'}
]">
<el-input v-model="form.username"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password"
:rules="[
{required:true,message:'请输入密码', trigger:'blur'},
{min:6,max:12,message:'长度在6-12位字符', trigger:'blur'}
]">
<el-input type="password" v-model="form.password"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="login('form')">登录</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data(){
return {
form:{
username:'',
password:''
}
}
},
methods:{
login(form){
this.$refs[form].validate((valid)=>{
if(valid){
console.log(this.form)
}else{
console.error(this.form)
}
})
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.login{
width: 100%;
height: 100%;
position: absolute;
background: #409EFF;
}
.box-card{
width: 450px;
margin:200px auto;
}
</style>
修改router文件夹下的index.js
import Vue from 'vue'
import Router from 'vue-router'
// import Home from '../components/Home.vue'
Vue.use(Router)
export default new Router({
routes:[
{
path:'/',
redirect:'/login',
component:()=> import('@/components/Login') //路由懒加载
},
{
path:'/login',
name:'/Login',
component:()=> import('@/components/Login') //路由懒加载
},
{
path:'/home',
// component:()=> import('@/components/Home') //路由懒加载
component:resolve => require(['@/components/Home'],resolve) // 异步组件
}
],
mode:'history'
})
封装验证规则及token
在src下创建utils文件夹,增加validate.js,用来封装验证的方法
// 用户名匹配
export function nameRule(rule,value,callback){
// 请输入4-10位的昵称
let reg = /(^[a-zA-Z0-9]{4,10}$)/;
if(value === ''){
callback(new Error('请输入用户名'))
}else if(!reg.test(value)){ // 校验没有通过
callback(new Error('请输入4-10位用户名'))
}else{
callback()
}
}
// 用户密码匹配
export function passRule(rule,value,callback){
// 请输入6-12位的密码,需要包含大小写字母和数字以及特殊符号
let pass = /^\S*(?=\S{6,12})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*? ])\S*$/;
if(value === ''){
callback(new Error('请输入密码'))
}else if(!pass.test(value)){ // 校验没有通过
callback(new Error('6-12位密码需要包含大小写字母和数字及符号'))
}else{
callback()
}
}
使用,login.vue全代码
<template>
<div class="login">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>通用后台管理系统</span>
</div>
<el-form label-width="80px" :model="form" ref="form" :rules="rules">
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="form.password"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="login('form')">登录</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
import {nameRule,passRule } from '../utils/validate.js'
export default {
name: 'HelloWorld',
data(){
return {
form:{
username:'',
password:''
},
rules:{
username:[{validator:nameRule,trigger: 'blur'}],
password:[{validator:passRule,trigger: 'blur'}]
}
}
},
methods:{
login(form){
this.$refs[form].validate((valid)=>{
if(valid){
console.log(this.form)
// this.axios.post('http://localhost:8080/bike/login',this.form)
// .then(res =>{
// console.log(res)
// })
localStorage.setItem('username',this.form.username)
this.$message({message:'登陆成功',type:'success'})
this.$router.push('/home')
}else{
console.error(this.form)
}
})
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.login{
width: 100%;
height: 100%;
position: absolute;
background: #409EFF;
}
.box-card{
width: 450px;
margin:200px auto;
}
</style>
在src->utils文件夹下,增加setToken.js,用来封装Token
// 设置
export function setToken(tokenKey,token){
return localStorage.setItem(tokenKey,token)
}
// 获取
export function getToken(tokenKey){
return localStorage.getItem(tokenKey)
}
// 删除
export function removeToken(tokenKey){
return localStorage.removeItem(tokenKey)
}
使用,在login.js中使用
封装axios
1.在src目录下新建service.js
import axios from 'axios'
import {getToken} from '@/utils/setToken.js'
import { Message } from 'element-ui'
const service = axios.create({
baseURL:'/api', //baseURL会自动加在请求地址上
timeout:5000
})
// 添加请求拦截器
service.interceptors.request.use((config)=>{
// 在请求之前做些什么(获取并设置token)
config.headers['token'] = getToken('token')
return config
},(error)=>{
return Promise.reject(error)
})
// 添加响应拦截器
service.interceptors.response.use((response)=>{
// 在响应数据做些什么(获取并设置token)
let {code, msg} = response.data
if(code !== 200){
Message({message: msg || 'error',type:'warning'})
}
return response
},(error)=>{
return Promise.reject(error)
})
export default service
2.去vue.config.js配置代理
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer:{
open:true, // 自动打开
host: 'localhost',
proxy:{ // 配置代理
'/api':{
target:'http://localhost:8080/bike',
changeOrigin:true, //允许跨域
pathRewrite:{
'^/api':''
}
}
}
}
})
3.去main.js,替换原来的axios为自己的service
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui' //引入ElementUI
import 'element-ui/lib/theme-chalk/index.css' //导入样式
// import axios from 'axios' //引入axios
import router from './router' //引入router
import service from './service'
Vue.prototype.service = service // 挂载到原型上,可以全局使用
Vue.use(ElementUI) //使用
Vue.config.productionTip = false
new Vue({
router, // 渲染之前挂载一下
render: h => h(App),
}).$mount('#app')
4.使用,这里是后端自己定义的接口
@PostMapping("login")
public Map<String,Object> login(@RequestBody LoginParam param){
Map<String,Object> res = new HashMap<>();
if (param.getUsername()!= null && param.getPassword() != null){
res.put("code",200);
res.put("msg","登录成功");
res.put("username",param.getUsername());
res.put("token","123456");
return res;
}
else {
res.put("code",201);
res.put("msg","登录失败");
return res;
}
}
LoginParam.java
package com.zsp.bike.entity.param;
import lombok.Data;
import java.io.Serializable;
@Data
public class LoginParam implements Serializable {
private String username;
private String password;
}
在login.vue写请求方法,并存储token
login(form){
this.$refs[form].validate((valid)=>{
if(valid){
console.log(this.form)
let LoginParam = this.form
this.service.post('/login',LoginParam)
.then(res=>{
console.log(res)
if(res.data.code === 200){
setToken('username',res.data.username)
setToken('token',res.data.token)
this.$message({message:res.data.msg, type:'success'})
this.$router.push('/home')
}
})
}else{
console.error(this.form)
}
})
}
api请求封装,在src目录下新建api文件夹,创建api.js
// 项目中我们大多数时候都会把对应的接口请求都封装成api来调用
import service from '../service.js'
// 登录接口封装
export function login(data){
return service({
method: 'post',
url:'/login',
data
})
}
使用,在login.vue中首先导入这个api中定义的login,然后使用
import { login } from '@/api/api.js'
export default {
name: 'HelloWorld',
data(){
return {
form:{
username:'',
password:''
},
rules:{
username:[{validator:nameRule,trigger: 'blur'}],
password:[{validator:passRule,trigger: 'blur'}]
}
}
},
methods:{
login(form){
this.$refs[form].validate((valid)=>{
if(valid){
console.log(this.form)
let LoginParam = this.form
login(LoginParam).then(res=>{
if(res.data.code === 200){
setToken('username',res.data.username)
setToken('token',res.data.token)
this.$message({message:res.data.msg, type:'success'})
this.$router.push('/home')
}
})
}else{
console.error(this.form)
}
})
}
登录成功
创建404页面,在src->components文件夹下新建NotFound.vue
<template>
<div class="notfound">
<div class="wrapper">
<div class="big">页面不见了</div>
<div>去首页瞧瞧,点击<router-link to="/">这里</router-link>进入首页</div>
</div>
</div>
</template>
<script>
export default {
data(){
return {};
}
}
</script>
<style>
.notfpund{
height: 100%;
background-image: url('../assets/404.jpg');
background-position: right top, center center;
background-repeat: no-repeat repeat;
}
.notfound .wrapper .big{
font-size: 74px;
font-weight: 700;
line-height: 68px;
margin-bottom: 48px;
}
</style>
需要在app.vue中设置body和html宽高,否则不生效
3.5 后台页面
3.5.1 后台页面布局
在src->components文件夹下创建common文件夹。
头部、底部、菜单最终实在Home.vue中写的
在Home.vue中导入三个组件
<template>
<div class="home">
<!-- 头部 -->
<Header>Header</Header>
<el-container class="content">
<!-- 左侧菜单栏 -->
<Menu/>
<!-- 内容 -->
<el-container>
<el-main>Main</el-main>
<!-- 底部 -->
<el-footer><Footer/></el-footer>
</el-container>
</el-container>
</div>
</template>
<script>
import Header from './common/Header.vue'
import Footer from './common/Footer.vue'
import Menu from './common/Menu.vue'
export default {
name: 'HelloWorld',
components:{ //注册
Header,
Footer,
Menu
},
data(){
return {}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.home{
width:100%;
height:100%;
}
.content{
position: absolute;
width: 100%;
top:60px;
bottom: 0;
}
</style>
header的书写,左侧展示标题,右侧展示用户名
<template>
<div class="header">
<el-header>
<div class="title">管理系统</div>
<div>{{name}}</div>
</el-header>
</div>
</template>
<script>
import { getToken } from '@/utils/setToken';
export default{
name:"Header_",
data(){
return{
name:''
}
},
created(){
this.name = getToken('username')
}
}
</script>
<style scoped>
.el-header{
background: #2578b5;
color:#fff;
line-height: 60px;
display: flex;
justify-content: space-between;
}
.title{
width: 200px;
font-size: 24px;
}
</style>
footer的书写
<template>
<div class="footer">
<el-card>
China 2023 Casey
</el-card>
</div>
</template>
<script>
export default{
name:"footer_",
data(){
return{}
}
}
</script>
Menu.vue的书写
<template>
<div class="menu">
<el-aside width="200px">
<el-menu
default-active="2"
class="el-menu-vertical-demo"
background-color="#2578b5"
text-color="#fff"
active-text-color="#ffd04b">
<el-submenu index="1">
<template slot="title">
<i class="el-icon-location"></i>
<span>导航一</span>
</template>
<el-menu-item-group>
<el-menu-item index="1-1">选项1</el-menu-item>
<el-menu-item index="1-2">选项2</el-menu-item>
</el-menu-item-group>
</el-submenu>
</el-menu>
</el-aside>
</div>
</template>
<script>
export default{
name:"menu_",
data(){
return{}
}
}
</script>
<style scoped>
.el-aside{
height: 100%;
}
.el-menu{
height: 100%;
}
.el-submenu-item{
min-width: 0;
}
</style>
最终效果
3.5.2 路由的渲染,将路由渲染到菜单Menu中
在components文件夹下创建bike和bikeupdate文件夹。
修改路由,进入router.js
import Vue from 'vue'
import Router from 'vue-router'
// import Home from '../components/Home.vue'
Vue.use(Router)
export default new Router({
routes:[
{
path:'/',
redirect:'/login',
hidden:true,
component:()=> import('@/components/Login') //路由懒加载
},
{
path:'/login',
name:'/Login',
hidden:true,
component:()=> import('@/components/Login') //路由懒加载
},
{
path:'*',
name:'NotFound',
hidden:true,
component:()=> import('@/components/NotFound') //路由懒加载
},
// {
// path:'/home',
// // component:()=> import('@/components/Home') //路由懒加载
// component:resolve => require(['@/components/Home'],resolve) // 异步组件
// },
// 第一个
{
path:'/home',
name:'车辆管理',
redirect:'/home/bike', //默认重定向
component:()=> import('@/components/Home'),
children:[
{
path:'/home/bike',
name:'车辆列表',
component:()=> import('@/components/bike/BikeList'),//这里对应文件的名字,我创建的是BikeList
},
{
path:'/home/ment',
name:'车辆管理',
component:()=> import('@/components/bike/BikeMent'),//这里对应文件的名字,我创建的是BikeList
},
{
path:'/home/info',
name:'信息列表',
component:()=> import('@/components/bike/InfoList'),//这里对应文件的名字,我创建的是BikeList
}
]
},
// 第二个
{
path:'/home',
name:'数据渲染',
component:()=> import('@/components/Home'),
children:[
{
path:'/home/dataview',
name:'数据概览',
component:()=> import('@/components/bikeUpdate/DataView'),//这里对应文件的名字,我创建的是BikeList
}
]
}
],
mode:'history'
})
完成上部分后,去Menu.vue 菜单页完成渲染
<template>
<div class="menu">
<el-aside width="200px">
<el-menu
router
default-active="2"
class="el-menu-vertical-demo"
background-color="#2578b5"
text-color="#fff"
active-text-color="#ffd04b">
<!-- 在这里遍历,进行绑定 -->
<template v-for="(item,index) in menus">
<el-submenu :index="index+''" :key="index" v-if="!item.hidden">
<template slot="title">
<i class="el-icon-location"></i>
<span>{{item.name}}</span>
</template>
<el-menu-item-group v-for="(child,index) in item.children" :key="index">
<el-menu-item :index="child.path">{{child.name}}</el-menu-item>
</el-menu-item-group>
</el-submenu>
</template>
</el-menu>
</el-aside>
</div>
</template>
<script>
export default{
name:"menu_",
data(){
return{
menus:[]
}
},
created(){
console.log(this.$router.options.routes)
this.menus = [...this.$router.options.routes]
}
}
</script>
<style scoped>
.el-aside{
height: 100%;
}
.el-menu{
height: 100%;
}
.el-submenu-item{
min-width: 0;
}
</style>
设置路由出口,让Main区域跟着路由变化而显示不同的内容。在Home.vue中修改,把原始的Main改为router-view
接下来创建面包屑 ,在component文件夹下创建Breadcrumb.vue
<template>
<div>
<el-card>
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item
v-for="(item,index) in $route.matched"
:key="index"
>{{item.name}}</el-breadcrumb-item>
</el-breadcrumb>
</el-card>
</div>
</template>
<script>
export default{
name:"Breadcrumb_",
data(){
return{}
}
}
</script>
<style scoped>
</style>
在Home.vue中注册
<template>
<div class="home">
<!-- 头部 -->
<Header>Header</Header>
<el-container class="content">
<!-- 左侧菜单栏 -->
<Menu />
<!-- 内容 -->
<el-container>
<el-main>
<!-- 面包屑 -->
<Bread />
<div class="cont">
<router-view></router-view>
</div>
</el-main>
<!-- 底部 -->
<el-footer><Footer /></el-footer>
</el-container>
</el-container>
</div>
</template>
<script>
import Bread from './common/Breadcrumb'
import Header from './common/Header'
import Footer from './common/Footer'
import Menu from './common/Menu.vue'
export default {
name: 'HelloWorld',
components:{ //注册
Header,
Footer,
Menu,
Bread
},
data(){
return {}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.home{
width:100%;
height:100%;
}
.content{
position: absolute;
width: 100%;
top:68px;
bottom: 0;
}
.count{
margin:20px 0;
}
</style>
以上就是全部内容。