前端案例分析
CommonAside
prismjs
<el-menu
default-active="1-4-1"
class="el-menu-vertical-demo"
backgroundColor='#545c64'
textColor="#fff"
active-text-color="#ffd04b"
@open="handleOpen"
@close="handleClose"
:collapse="isCollapse">
<h3>{{ isCollapse ? '系统' : '通用后台管理系统' }}</h3>
<el-menu-item @click="clickMenu(item)" v-for="item in noChildren" :index="item.path" :key="item.path">
<i :class="'el-icon-' + item.icon"></i>
<span slot="title">{{ item.label }}</span>
</el-menu-item>
<el-submenu v-for="item in hasChildren" :index="item.path + ''" :key="item.path">
<template slot="title">
<i :class="'el-icon-' + item.icon"></i>
<span slot="title">导航一</span>
</template>
<el-menu-item-group v-for="(subItem, subIndex) in item.children" :key='subItem.path'>
<el-menu-item @click="clickMenu(subItem)" :index="subItem.path">{{ subItem.label }}</el-menu-item>
</el-menu-item-group>
</el-submenu>
</el-menu>
el-menu
属性
- collapse 是否水平折叠收起菜单(仅在mode为vertical时可用)
- backgroundColor 菜单的背景颜色
- textColor 菜单的文字颜色
- active-text-color 激活当前菜单的文字颜色
事件
-
open
说明:sub-menu 展开的回调
回调参数:index: 打开的 sub-menu 的 index, indexPath: 打开的 sub-menu 的 index path
-
close
说明:sub-menu 收起的回调
回调参数:index: 收起的 sub-menu 的 index, indexPath: 收起的 sub-menu 的 index path
SubMenu Attribute
index: 唯一标识
prismjs
<header>
<div class="l-content">
<el-button @click="handleMenu" plain icon="el-icon-menu" size="mini"></el-button>
<!-- <h3 style="#fff">首页</h3> -->
<el-breadcrumb separator="/">
<el-breadcrumb-item v-for="item in tabs" :key="item.path" :to="{ path: 'item.path' }">{{item.label}}</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="r-content">
<!--用来设置触发下拉框的方法和大小-->
<el-dropdown trigger="click" size="mini">
<span>
<img class="user" :src="userImg">
</span>
<!--下拉菜单项-->
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>个人中心</el-dropdown-item>
<el-dropdown-item @click.native="logOut">退出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</header>
el-breadcrumb:面包屑
- separator:用来设置分隔符
- to:路由跳转对象,同v-router的to
路由钩子
prismjs
router.beforeEach((to,from,next)=>{
store.commit('getToken');
const token = store.state.user.token;
if (!token && to.name !== 'login') {
next({name: 'login'});
} else if(token && to.name === 'login') {
next({name: 'home'})
}else {
next();
}
})
store仓库
prismjs
state: {
isCollapse: true,
tabsList: [
{
path: '/',
name: 'home',
label: '首页',
icon: 'home'
},
],
currentMenu: null,
menu: [],
},
mutations: {
}
自动折叠功能实现
CommonHeader 在(method中实现)
prismjs
handleMenu() {
this.$store.commit('collapseMenu');
}
CommonAside 在(computed中实现)
prismjs
isCollapse() {
return this.$store.state.tab.isCollapse;
}
扩展(vuex)
什么是vuex?
vuex是一个专门为Vue.js应用程序开发的状态管理模式,它采用集中式存储管理所有组件的公共状态,并以相应的规则保证状态以一种可预测的方式发生变化。
-
state中是保存的公共状态,改变公共状态的唯一方式就是通过mutation进行更改。
-
将
getters
属性理解为所有组件的computed
属性, 也就是计算属性. vuex的官方文档也是说到可以将getter理解为store的计算属性, getters的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。 -
Mutations: mutations理解为store的methods,mutations对象中保存着更改数据的回调函数,该函数名官方规定叫type,第一个参数是state,第二个参数是payload,也就是自定义的参数。
注意:调用mutations中回调函数,只能使用store.commit(type,payload)
- Actions:
- Modules:由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、出处。
CommonForm
prismjs
<template>
<el-form ref="form" label-width="100px" :model="form" :inline="inline">
<el-form-item v-for="item in formLabel" :key="item.label" :label="item.label">
<el-input v-if="item.type === 'input'" :placeholder="'请输入' + item.label" v-model="form[item.model]">
</el-input>
<el-switch v-if="item.type === 'switch'" v-model="form[item.model]"></el-switch>
<el-date-picker v-if="item.type === 'date'" type="date" value-format="yyyy-MM-dd" placeholder="选择日期"
v-model="form[item.model]"></el-date-picker>
<el-select v-if="item.type === 'select'" placeholder="请选择" v-model="form[item.model]">
<el-option v-for="item in item.opts" :key="item.val" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item><slot></slot></el-form-item>
</el-form>
</template>
<script>
export default {
name: 'CommonForm',
props: {
formLabel: Array,
form: Object,
inline: Boolean
},
data() {
return {
}
}
}
</script>
<style scoped>
</style>
- label-width 表单域的标签的宽度,作为form直接子元素的form-item会继承该值。
CommonTable
prismjs
<template>
<div class="common-table">
<el-table :data="tableData" height="90%" stripe>
<el-table-column show-overflow-tooltip v-for="item in tableLabel" :key="item.prop" :label="item.label"
:width="item.width ? item.width : 125">
<template slot-scope="scope">
<span style="margin-left: 10px;">{{ scope.row[item.prop] }}</span>
</template>
</el-table-column>
<el-table-column label="操作" min-width="180">
<template slot-scope="scope">
<el-button size="mini" @click="handleEdit(scope.row)">编辑</el-button>
<el-button size="mini" type="danger" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
class="pager"
layout="prev,pager,next"
:total="config.total"
:current-page.sync="config.page"
@current-change="changePage"
:page-size="20">
<!--
layout: 组件布局,子组件名用逗号分隔
total:总条数目
current-page:当前页数(支持.sync)
page-size:每页显示条目数(支持.sync)
.sync是一个语法糖。是父组件监听子组件更新某个props的请求的缩写语法。
-->
</el-pagination>
</div>
</template>
<script>
export default {
name: 'CommonTable',
props: {
tableData: Array,
tableLabel: Array,
config: Object,
},
methods: {
handleEdit(row) {
this.$emit('edit',row)
},
handleDelete(row) {
this.$emit('del',row)
},
changePage(page) {
this.$emit('changePage',page)
}
},
data() {
return {
}
}
}
</script>
<style lang="less" scoped>
.common-table {
height: calc(100% - 62px);
background-color:aliceblue;
position: relative;
.pager {
position: absolute;
bottom: 0;
right: 20px;
}
}
</style>
- data 显示的数据
- height: Table的高度,默认为自动高度。如果是数值则单位为px
- stripe: 是否为斑马纹 默认为false
- show-overflow-tooltip 当内容过长内隐藏时显示 tooltip
知识回顾: 插槽
作用域插槽就是在父组件中使用子组件中的数组
CommonTag
prismjs
<template>
<div class="tabs">
<!--
closeable 是否可以关闭
effect 主题
-->
<el-tag size="small" v-for="(tag,index) in tags" :key="tag.name" :closable="tag.name !== 'home'"
:effect="$route.name === tag.name ? 'd' : 'plain'"
@click="changeMenu(tag)"
@close="handleClose(tag,index)">
{{tag.label}}
</el-tag>
</div>
</template>
<script>
import { mapState,mapMutations } from 'vuex';
export default {
name: 'CommonTag',
data() {
return {
}
},
computed: {
...mapState({
tags: state => state.tab.tabsList
})
},
methods: {
...mapMutations({
close: 'closeTag'
}),
changeMenu(item) {
this.$router.push({name: item.name});
},
handleClose(tag,index) {
const length = this.tags.length -1;
this.close(tag);
// this.$store.commit("closeTag",tag);
if (tag.name !== this.$route.name) {
return;
}
if (index === length) {
this.$router.push({
name: this.tags[index-1].name
})
} else {
this.$router.push({
name: this.tags[index].name
})
}
}
}
}
</script>
<style lang="less" scoped>
.tabs {
padding: 20px;
.el-tag {
margin-right: 15px;
cursor: pointer;
}
}
</style>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)