table表格
table表格遍历数据
子项是绑定一个prop属性进行全部遍历出来
但有时候需求不是这样的,我们的需求不是照着模板遍历出来,或者想使用v-model绑定数据时,就需要用到插槽的方式进行使用。
form表单同样适用
使用
scope.row.value 取到遍历数组的项
scope.$index 可以直接取到序号
button按钮+dialog对话框
button按钮+dialog对话框应用场景最多的就是后台管理系统的新增页面和编辑页面,由于后台管理系统的新增功能和编辑功能是有异曲同工之妙,所以我们一般不会分成2个页面去写,而是写在一个页面上。
我们来看下新增页面和编辑页面对比。
页面几乎一样,我们要做的其实只是对数据进行如何区分罢了。
那么,这怎么区分用户点击的是编辑按钮还是新增按钮呢?而与此同时,对话框的标题也随之对应呢?
因为我是父子组件的方式写的,所以需要传值,但不影响逻辑
子组件需要接收一个属性过来,用一个三元运算符就可区分出用户点击了新增按钮还是编辑按钮,点击新增按钮就是新增页面的对话框,反之亦然。
关键就是父组件如何进行对应的逻辑编写,其实就是一个if else语句可以搞定了,前提是子组件发送事件传递过来,父组件接收。
只需这样就知道用户点击了哪个按钮,用一个if语句判断,如果用户点击编辑按钮,那就编写编辑功能的代码。
tag标签,状态筛查的逻辑
状态筛查也是后台管理系统使用的比较多的功能
一般后端写接口,都是以0 1 2 3 4 来区分status, 0-4几个数字分别代表不同的状态,而前端这边发起请求,就是将label作为参数传递给后端
在data中定义数据
将用户的选中的状态发送给后台
根据状态码,在表格中展示不同风格的tag和信息
折叠导航栏
先来看效果图,这种需求也是后台管理系统场景常见。
这种操作是怎么实现的呢?
像上面这种需求,我们一般也是父子组件分离写的,不会在一个页面上写,为的就是组件分离,不让页面太繁杂,父子组件开发在vue中十分重要且频繁使用。
话不多说,进入正题,先看下页面结构拆分就知道为什么要父子组件啦。
所以说,做后台管理系统又是200%逃不开layout布局了,在这里建议,一定要学会这种layout布局
回到需求上面来。
从上面那张结构拆解图来看,侧边栏和头部区域还有主体区域都是属于子组件,因此,他们3个都是由一个父亲来控制。
逻辑代码实现部分,关键是弄懂这3个人之间的 :collapse="isCollapse"属性是怎么互相通讯的,弄懂了这个就明白了logo文字的变化,图标的切换等等。
父组件
<template>
<div class="layout-container">
<el-container style="height: 100%">
<el-aside class="aside" width="auto">
<Aside :isCollapse="isCollapse" class="aside-menu" />
</el-aside>
<el-container>
<el-header class="header">
<HeaderView
@changeCollapse="changeCollapse"
:isCollapse="isCollapse"
/>
</el-header>
<el-main class="main">
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
import Aside from "./components/aside.vue";
import HeaderView from "./components/header.vue";
export default {
data() {
return {
isCollapse: false,
};
},
components: {
Aside,
HeaderView,
},
methods: {
changeCollapse() {
this.isCollapse = !this.isCollapse;
},
},
};
</script>
侧边栏
<template>
<el-menu
:default-active="this.$route.path"
class="el-menu-vertical-demo"
@open="handleOpen"
@close="handleClose"
background-color="#002033"
text-color="#fff"
active-text-color="#ffd04b"
router
:collapse="isCollapse"
>
<div class="logo">{{ isCollapse ? "logo" : "logo 后台登录系统" }}</div>
<el-menu-item
v-for="(item, index) in menu"
:key="index"
:index="item.path"
>
<i :class="item.icon"></i>
<span slot="title">{{ item.label }}</span>
</el-menu-item>
</el-menu>
</template>
<script>
export default {
data() {
return {
menu: [
{
label: "首页",
path: "/home",
icon: "el-icon-s-home",
},
{
label: "内容管理",
path: "/article",
icon: "el-icon-document",
},
{
label: "素材管理",
path: "/images",
icon: "el-icon-picture",
},
{
label: "发布文章",
path: "/publish",
icon: "el-icon-collection-tag",
},
{
label: "评论管理",
path: "/comment",
icon: "el-icon-s-comment",
},
{
label: "粉丝管理",
path: "/fans",
icon: "el-icon-connection",
},
{
label: "个人设置",
path: "/settings",
icon: "el-icon-setting",
},
],
};
},
props: ["isCollapse"],
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
},
},
};
</script>
<style lang="less" scoped>
.logo {
font-size: 22px;
color: white;
text-align: center;
user-select: none;
}
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
</style>
头部
<template>
<div class="header-container">
<div style="font-size: 24px">
<i
@click="change"
:class="{
'el-icon-s-fold': !isCollapse,
'el-icon-s-unfold': isCollapse,
}"
></i>
<span style="margin-left: 10px">XXXXXX有限公司</span>
</div>
<el-dropdown>
<div class="avatar-wrap">
<img class="avatar" :src="user.photo" alt="" />
<span>{{user.name}}</span>
<i class="el-icon-arrow-down el-icon--right"></i>
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item icon="el-icon-s-tools">个人设置</el-dropdown-item>
<el-dropdown-item
icon="el-icon-switch-button"
@click.native="onLogout"
>用户退出</el-dropdown-item
>
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
<script>
import { getUserProfile } from '@/api/user';
export default {
data(){
return {
user:{}
}
},
props: ["isCollapse"],
created() {
//组件初始化好,请求获取用户资料
this.loadUserProfile();
},
methods: {
change() {
this.$emit("changeCollapse"); //tips:涉及3个组件用store改良方案最好
},
loadUserProfile() {
getUserProfile().then((res) => {
this.user = res.data
});
},
onLogout(){
this.$confirm('确认退出登录吗?', '退出提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
localStorage.removeItem('user')
this.$router.push('/')
}).catch(() => {
this.$message({
type: 'info',
message: '已取消退出'
});
});
}
}
}
</script>
<style lang="less" scoped>
.header-container {
height: 60px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #ccc;
.avatar-wrap {
display: flex;
align-items: center;
.avatar {
width: 30px;
height: 30px;
border-radius: 50%;
margin-right: 10px;
}
}
}
</style>