Vue路由
安装插件:
yarn add vue-router
import {createRouter, createWebHashHistory} from "vue-router";
const routes =[
{
path: '/',
redirect: '/login'//首页需要重定向到一个显示的路由页面,这个重定向的页面必须在路由中有定义
},
{
path: '/login',//路由的路径
name: 'Login',
//懒加载,可以节省浏览器的使用内存
component: () => import('../views/Login.vue')
},
{
path: '/manage',//管理页面路径
name: 'Manage',
//懒加载,可以节省浏览器的使用内存
component: () => import('../views/Manage.vue'),
//子路由,即页面中的页面,子路由是在路由中配置的一个数组,数组中配置路由的信息
children: [
{
path: '/setting',
name: 'Setting',
//懒加载,可以节省浏览器的使用内存
component: () => import('../views/Setting.vue')
},
{
path: '/user',
name: 'User',
//懒加载,可以节省浏览器的使用内存
component: () => import('../views/User.vue')
},
{
path: '/position',
name: 'Position',
//懒加载,可以节省浏览器的使用内存
component: () => import('../views/Position.vue')
}
]
},
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router;
也就是说当开启项目后会自动进入/login页面,手动进入/manage页面后里面包含了三个子页面,即/setting,/user,/position,这三个页面存在于/manage页面之中。需要对其进行弹性布局。
弹性布局(折叠菜单)
<script setup lang="ts">
import {ref} from "vue";
let isCollapse = ref(false)
const menus = [
{
id: 1,
name: '系统设置',
icon: "Setting",//图标为Setting样式,在Element-plus官网查看
route: '/setting'
},
{
id: 2,
name: '用户管理',
icon: "User",
route: '/user'
},
{
id: 3,
name: '地址管理',
icon: "Position",
route: '/position'
}
]
</script>
<template>
<div class="main-container">
<header>
<el-icon>
<!--隐藏菜单,即点击切换Expand和Fold状态-->
<component :is="isCollapse ? 'Expand' : 'Fold'" @click="isCollapse = !isCollapse"/>
</el-icon>
</header>
<main>
<!--default-active表示默认使用的菜单,其值为菜单的index属性
collapse属性表示菜单是否折叠,router属性用来开启vue-router模式
开启后使用的菜单的index属性值作为路由的path-->
<el-menu default-active="1" :collapse="isCollapse" :router="true">
<el-menu-item v-for="m in menus" :index="m.route">
<el-icon>
<!--如果图标需要发生变化就要使用component标签-->
<component :is="m.icon"/>
</el-icon>
{{m.name}}
</el-menu-item>
</el-menu>
<section>
<nav>操作导航</nav>
<article>
<!--由于父容器使用的是弹性布局,因此子路由容器不能再使用弹性布局
应该使用绝对定位布局防止组件外溢-->
<router-view class="child-container"/>
</article>
<footer> 632 2024-2030 版权所有</footer>
</section>
</main>
</div>
</template>
<style scoped>
.main-container {
width: 100%;
height: 100%;
overflow: hidden;/*超出部分隐藏*/
display: flex;/*浮动*/
flex-direction: column;/*上下排列*/
}
header{
height: 50px;
border-bottom: 1px solid #ddd;
}
main{
flex-grow: 1.0;/*空间足够会自动拉伸*/
flex-shrink: 0.8;/*空间不足会自动缩小*/
display: flex;
flex-direction: row;/*主体部分为横向排列*/
}
.el-menu{
color: #535bf2!important;
background-color: transparent;
width: 150px;
border-right: 1px solid #ddd;/*右边框*/
overflow: hidden;
transition: width .1s;/*当‘el-menu’类的元素宽度发生变化时以0.1s平滑过渡*/
}
section{
flex-grow: 1.0;
flex-shrink: 0.8;
display: flex;
flex-direction: column;
}
article{
flex-grow: 1.0;
flex-shrink: 0.8;
position: relative;/*相对定位,因为子组件要进行绝对定位所以需要将自己的位置作为参照物*/
}
nav{
height: 22px;
border-bottom: 1px solid #ddd;
font-size: 14px;
line-height: 22px;/*行高*/
text-indent: 10px;/*首行缩进*/
}
footer{
height: 40px;
line-height: 40px;
border-top: 1px solid #ddd;
text-indent: 10px;
}
.child-container{
position: absolute;/*绝对定位*/
top: 5px;
right: 5px;
bottom: 5px;
left: 5px;
}
</style>
<!--element-plus中的css样式,在修改的时候如果样式的名称存在双横杠,
那么这些css样式必须在全局样式中调整才能生效-->
<style>
.el-menu--collapse{
width: 60px !important;/*提高此样式规则的优先级,使其覆盖其他任何可能影响宽度的样式规则。*/
}
</style>
查询列表 + 对话框 + 消息提示框:
<script setup lang="ts">
import {onMounted, ref} from "vue";
import {showConfirm} from "../tip";
import {FormInstance} from "element-plus";
const condidtion = ref({
name: '',
sex: '',
birthday: []
})
const sexArr = ref(['男','女','其他'])
const selectedUsers = ref([])
const currentPage = ref(1)
const pageSize = ref(5)
const pageSizes = ref([5,10,20])
const total = ref(20)
const users = ref([])
const userDialog= ref({
visible: false,
isUpdate: false,
user: {
username: '',name: '',sex: '',birthday: ''
},
userRules: ''
})
const search = ()=>{
//假数据
users.value=[{
username: "boduo",name: '波多',sex: '女',birthday: '2002-11-30'
},{
username: "boduoy",name: '波多y',sex: '女',birthday: '2002-11-30'
},{
username: "boduoye",name: '波多ye',sex: '女',birthday: '2002-11-30'
},{
username: "boduoyej",name: '波多yej',sex: '女',birthday: '2002-11-30'
},{
username: "boduoyejie",name: '波多yeji',sex: '女',birthday: '2002-11-30'
},{
username: "boduoyejie1",name: '波多yeji',sex: '女',birthday: '2002-11-30'
},{
username: "boduoyejie12",name: '波多yeji',sex: '女',birthday: '2002-11-30'
},{
username: "boduoyejie123",name: '波多yeji',sex: '女',birthday: '2002-11-30'
},{
username: "boduoyejie1234",name: '波多yeji',sex: '女',birthday: '2002-11-30'
},{
username: "boduoyejie12345",name: '波多yeji',sex: '女',birthday: '2002-11-30'
},{
username: "boduoyejie123456",name: '波多yeji',sex: '女',birthday: '2002-11-30'
},{
username: "boduoyejie1234567",name: '波多yeji',sex: '女',birthday: '2002-11-30'
},{
username: "boduoyejie12345678",name: '波多yeji',sex: '女',birthday: '2002-11-30'
}
];
const start = (currentPage.value-1) * pageSize.value
const end = currentPage.value * pageSize.value
users.value = users.value.slice(start,end)
}
const handleSelectionChange = (val)=>{
selectedUsers.value = val
}
const handleSizeChange = (val:number)=>{
pageSize.value=val
search()//更新数据
}
const handleCurrentChange = (val:number)=>{
currentPage.value=val
search()//更新数据
}
const edit = (user)=>{
//这里不能直接使用对象的内存地址,否则编辑的时候外面的内容会一同改变因为地址相同
//所以应该使用对象的属性
let temp = {username: '',name: '',sex: '',birthday: ''}
//Object.keys()函数用于获取一个对象中定义的所有属性名的集合
Object.keys(temp).forEach((key)=>{temp[key] = user[key]})
userDialog.value.user = temp
showDialog(true)
}
const showDialog = (isUpdate:boolean) => {
userDialog.value.isUpdate = isUpdate
userDialog.value.visible = true
}
const deleteUser = (username) =>{
showConfirm(`确定要删除\"${username}\"的相关数据吗?`,()=>{
console.log("用户删除数据操作")
})
}
const userForm = ref<FormInstance>()
const closeDialog = () => {
userDialog.value.isUpdate = false
userDialog.value.user = {username: '',name: '',sex: '',birthday: ''}
userForm.value.resetFields()
userDialog.value.visible = false
}
const save = () =>{
userForm.value.validate(valid =>{
if (valid) {}
})
}
//onMounted()函数是vue3提供的钩子函数,用于页面挂载后的初始化动作
onMounted (()=>search())
</script>
<template>
<div>
<!--inline属性表示能在一行中展示-->
<el-form :model="condidtion" :inline="true">
<el-form-item label="姓名">
<el-input v-model="condidtion.name" placeholder="请输入姓名" clearable/>
</el-form-item>
<el-form-item label="性别" style="width: 192px">
<el-select v-model="condidtion.sex">
<el-option v-for="(s,index) in sexArr" :label="s" :value="index"></el-option>
</el-select>
</el-form-item>
<el-form-item label="出生日期">
<!--type表示日期选择器的类型,可以是单个日期也可以是一个时间范围
单个日期就是单个值,日期范围是数组,数组中会存在一个开始值和结束值-->
<el-date-picker
v-model="condidtion.birthday"
type="daterange"
range-separator="至"
start-placeholder="请选择开始日期"
end-placeholder="请选择结束日期"
value-format="yyyy-MM-dd"/>
</el-form-item>
<el-form-item>
<el-button icon="Search" type="primary" @click="search">查询</el-button>
<el-button icon="RefreshLeft">重置</el-button>
<el-button icon="plus" type="danger" @click="showDialog(false)">增加</el-button>
</el-form-item>
</el-form>
<!--
page-sizes表示每页条数
background属性表示分页按钮的背景色
layout属性表示分页组件要展示的内容,给定的内容顺序为展示顺序
total属性表示查询结果的总条数
size-change属性表示绑定一个每页显示条数改变触发的事件
current-change属性表示绑定一个分页页码改变的时间
-->
<el-pagination style="float: right"
v-show="total>0"
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="pageSizes"
background
layout="total,sizes,prev,pager,next"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
size="small"
/>
<!--data属性表示表格要展示的数据,一般都是与一个数组绑定,height属性表示表格的高度,
只有设置了这个属性表格才会在内容溢出的时候出现滚动条-->
<el-table :data="users" height="500px" style="width: 100%" border
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="50px"/><!--选择-->
<el-table-column prop="username" label="账号" />
<el-table-column prop="name" label="姓名" />
<el-table-column label="性别" >
<template #defalut="scope">
<el-tag v-if="scope.row.sex===0" type="primary">男</el-tag>
<el-tag v-if="scope.row.sex===1" type="success">女</el-tag>
<el-tag v-if="scope.row.sex===2" type="danger">其他</el-tag>
</template>
</el-table-column>
<el-table-column prop="birthday" label="出生日期" />
<el-table-column label="操作">
<!--如果列中展示的内容需要使用到一些模板就必须使用template标签
default属性表示操作这个表格的对象,值就是一个对象名,对象名.row就能拿到当前行的数据-->
<template #default="s">
<el-button link type="primary" size="small" @click="edit(s.row)" >编辑</el-button>
<el-button link type="warning" size="small">冻结</el-button>
<el-button link type="success" size="small">解冻</el-button>
<el-button link type="danger" size="small" @click="deleteUser(s.row.username)" >删除</el-button>
</template>
</el-table-column>
</el-table>
<!--title属性表示对话框而定标题内容
before-class属性表示关闭对话框之前要执行的函数-->
<el-dialog
v-model="userDialog.visible"
:title="userDialog.isUpdate ? '编辑用户信息':'新增用户信息'"
width="500"
:before-close="closeDialog"
>
<el-form :model="userDialog.user" :rules="userDialog.userRules" ref="userForm">
<el-form-item label="账号" prop="username">
<el-input v-model="userDialog.user.username" placeholder="请输入账号" clearable/>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="userDialog.user.name" placeholder="请输入姓名" clearable/>
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-select v-model="userDialog.user.sex" placeholder="请选择性别" clearable>
<el-option v-for="(s,index) in sexArr" :label="s" :value="index"></el-option>
</el-select>
</el-form-item>
<el-form-item label="生日">
<el-date-picker v-model="userDialog.user.birthday" type="date" placeholder="请选择生日" clearable/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="closeDialog()">取消</el-button>
<el-button type="primary" @click="save()">保存</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<style scoped>
div{
background-color: transparent;
}
el-dialog{
background-color: transparent;
}
</style>
ajax:vue提供的ajax
安装:yarn add axios
请求代理:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
server: {//服务器配置
port: 7777, //服务器端口
proxy:{//这里就是对请求做代理
//下面的内容就是代理的规则
// /vue表示凡是以/vue开始的请求都会被代理
'/vue':{
// http://localhost:7777/vue/user => http://localhost:8888/vue/user => http://localhost:8888/user
target: 'http://localhost:8888',//表示会将请求代理至目标服务器
changeOrigin: true, //表示允许跨域操作
rewrite: path => path.replace(/^\/vue/, "") //路径重写
}
}
}
})