1.布局文件
<!-- * @Description: 布局容器组件 vue-intro + intro.js 新手引导页功能 home文件 * @Version: 2.0 * @Autor: lhl * @Date: 2020-06-11 17:54:29 * @LastEditors: lhl * @LastEditTime: 2020-08-20 16:54:29 -->
<!-- -->
<template>
<div class="layout-box">
<el-container>
<el-header>
<topHeader />
</el-header>
<el-container>
<el-aside width="220px">
<el-scrollbar class="page-component__scroll">
<siderBar />
</el-scrollbar>
</el-aside>
<el-main>
<div class="right-view" ref="rightViewBox">
<!-- <Breadcrumb ref="bread"/> -->
<transition name="fade-transform" mode="out-in">
<keep-alive :include="keepAliveList">
<router-view></router-view>
</keep-alive>
</transition>
</div>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
// router-view 的 key 或者用路由钩子 再或者用监听路由变化 // 场景:由于 Vue 会复用相同组件, 即 /detail/1 => /detail/2 或者 /detail?id=1 => /detail?id=2 这类链接跳转时, 将不在执行created, mounted之类的钩子 // <router-view :key="$route.fullPath"></router-view> // 这样组件的 created 和 mounted 就都会执行
import topHeader from "./topHeader"; import siderBar from "./siderBar"; import Breadcrumb from '../Breadcrumb/index' import { mapActions, mapGetters, mapMutations } from "vuex"; // 引导
import Driver from 'driver.js' // import driver.js
import 'driver.js/dist/driver.min.css' // import driver.js css
import steps from '@/common/steps' export default { components: { topHeader, siderBar, Breadcrumb }, data() { //这里存放数据
return { keepAliveList: ['baiduMapTest'] // 缓存的组件
} }, methods: { ...mapMutations(["setContentBoxHeight", "setBtnPermitCode"]), // 系统引导
guide() { const driver = new Driver() driver.defineSteps(steps) driver.start() }, // 获取按钮code码
getBtnCodeList(){ this.$http.user.btnList().then(res => { console.log(res) if(res.returnResult === 200){ this.setBtnPermitCode(res.returnData.buttonList) } }) } }, computed:{ ...mapGetters(['getcontentBoxHeight']) }, created() { this.getBtnCodeList() }, mounted() { this.guide(); //第二种方法
if (window.performance.navigation.type == 1) { console.log("页面被刷新") } else { console.log("首次被加载") } window.addEventListener("resize", () => { if (this.$refs.rightViewBox && this.$refs.rightViewBox.clientHeight) { this.setContentBoxHeight(this.$refs.rightViewBox.clientHeight); // console.log(this.$refs.rightViewBox.clientHeight, "rightViewBox");
} }) if (this.$refs.rightViewBox.clientHeight) { this.setContentBoxHeight(this.$refs.rightViewBox.clientHeight); } } }; </script>
<style lang='scss' scoped> //@import url(); 引入公共css类 .layout-box { height: 100%; min-width: 1200px; .el-aside { position: absolute; top: 60px; bottom: 0; background: #3db4f8; .el-menu{ border-right: none;
} } .el-main { position: absolute; left: 220px; right: 0; top: 60px; bottom: 0; padding: 10px; background: #eee; .right-view{ padding: 20px; background: #fff; min-height: 100%;
} } } </style>
<!-- * @Description: 侧边栏组件 * @Version: 2.0 * @Autor: lhl * @Date: 2020-06-11 17:54:54 * @LastEditors: lhl * @LastEditTime: 2020-07-17 14:22:49 -->
<!-- -->
<template>
<div class="sider-content-box">
<el-menu class="el-menu-vertical-demo" background-color="#3DB4F8" text-color="#fff" active-text-color="#fff" :collapse-transition="false" router >
<!-- 一级菜单 -->
<template v-for="(item,index) in menuData">
<el-submenu v-if="item.children && item.children.length" :index="item.menuUrl" :key="item.menuUrl"
>
<template slot="title">
<i :class="item.icon"></i>
<span>{{item.name}}</span>
</template>
<!-- 二级菜单 -->
<template v-for="(itemChild,vIndex) in item.children">
<el-submenu v-if="itemChild.children && itemChild.children.length" :index="itemChild.menuUrl" :key="vIndex"
>
<template slot="title">
<i :class="itemChild.icon"></i>
<span>{{itemChild.name}}</span>
</template>
<!-- 三级菜单 -->
<el-menu-item v-for="itemChild_Child in itemChild.children" :index="itemChild_Child.menuUrl" :key="itemChild_Child.menuUrl"
>
<i :class="itemChild_Child.icon"></i>
<span slot="title">{{itemChild_Child.name}}</span>
</el-menu-item>
</el-submenu>
<el-menu-item v-else :index="itemChild.menuUrl" :key="itemChild.vIndex">
<i :class="itemChild.icon"></i>
<span slot="title">{{itemChild.name}}</span>
</el-menu-item>
</template>
</el-submenu>
<el-menu-item v-else :index="item.menuUrl" :key="index">
<i :class="item.icon"></i>
<span slot="title">{{item.name}}</span>
</el-menu-item>
</template>
</el-menu>
</div>
</template>
<script> import { menuData } from '@/common/constant' export default { components: {}, data() { //这里存放数据
return { menuData }; }, computed: {}, watch: {}, methods: {}, created() {}, mounted() {} }; </script>
<style lang='scss' scoped> //@import url(); 引入公共css类 </style>
<!-- * @Description: 头部组件 * @Version: 2.0 * @Autor: lhl * @Date: 2020-06-12 09:12:02 * @LastEditors: lhl * @LastEditTime: 2020-08-04 17:33:36 -->
<!-- -->
<template>
<div class="header-content-box">
<div class="logo" id="logo">
<img src="@/assets/logo.png" alt />
</div>
<div id="title">vue测试管理系统</div>
<div class="top-info">
<div class="user-avatar">
<img src="@/assets/logo.png" alt />
</div>
<div class="user-down" id="user">
<el-dropdown trigger="click" @command="handleCommand">
<span class="el-dropdown-link"> {{getUserInfo.userName || '默认用户'}} <i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="baseInfo">基本资料</el-dropdown-item>
<el-dropdown-item command="changePassword">修改密码</el-dropdown-item>
<el-dropdown-item divided command="loginOut">退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
<el-dialog title="用户基本资料" :visible.sync="dialogVisibleInfo" width="50%">
<div class="user-info">
<p>id:{{getUserInfo.id}}</p>
<p>用户名:{{getUserInfo.userName}}</p>
<p>账号:{{getUserInfo.domainAccount}}</p>
<p>所在公司:{{getUserInfo.organizationName}}</p>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisibleInfo = false">取 消</el-button>
<el-button type="primary" @click="dialogVisibleInfo = false">确 定</el-button>
</span>
</el-dialog>
<el-dialog title="修改密码" :visible.sync="dialogVisibleChangePwd" width="50%">
<el-form ref="ruleForm" :model="ruleForm" :rules="resetRules" class="login-form" label-width="80px" label-position="left"
>
<el-form-item label="密码" prop="passwd">
<el-input type="password" v-model="ruleForm.passwd" placeholder="请输入密码" autocomplete="off" show-password ></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="checkPass">
<el-input type="password" v-model="ruleForm.checkPass" placeholder="请输入确认密码" autocomplete="off" show-password ></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="resetForm('ruleForm')">取 消</el-button>
<el-button type="primary" @click="submitForm('ruleForm')">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script> import { mapMutations, mapGetters } from "vuex"; export default { data() { var validatePass = (rule, value, callback) => { if (value === "") { callback(new Error("请输入密码")); } else { if (this.ruleForm.checkPass !== "") { this.$refs.ruleForm.validateField("checkPass"); } callback(); } }; var validatePass2 = (rule, value, callback) => { if (value === "") { callback(new Error("请再次输入密码")); } else if (value !== this.ruleForm.passwd) { callback(new Error("两次输入密码不一致!")); } else { callback(); } }; //这里存放数据
return { dialogVisibleInfo: false, // 用户信息
dialogVisibleChangePwd: false, // 修改用户密码
ruleForm: { passwd: "", checkPass: "", }, resetRules: { passwd: [{ validator: validatePass, trigger: "blur" }], checkPass: [{ validator: validatePass2, trigger: "blur" }], }, }; }, computed: { ...mapGetters(["getUserInfo"]), }, created() {}, methods: { ...mapMutations(["loginOut"]), handleCommand(command) { console.log(command); if (command === "baseInfo") { this.dialogVisibleInfo = true; } else if (command === "changePassword") { this.dialogVisibleChangePwd = true; } else if (command === "loginOut") { this.$confirm("您确定要退出吗?", "退出管理平台", { confirmButtonText: "确定", cancelButtonText: "取消", }) .then(() => { this.loginOut(); this.$router.push(`/login?redirect=${this.$route.fullPath}`);
}) .catch(() => {}); } }, submitForm(formName) { this.$refs[formName].validate((valid) => { if (valid) { // 调用重置密码的接口
alert("重置密码成功!"); this.dialogVisibleChangePwd = false; } else { // console.log("error submit!!");
return false; } }); }, resetForm(formName) { this.dialogVisibleChangePwd = false; this.$refs[formName].resetFields(); }, }, }; </script>
<style lang='scss' scoped> //@import url(); 引入公共css类 .header-content-box { height: 60px; display: flex; justify-content: space-between; align-items: center; background: url("~@/assets/img/bg.png"); .logo { img { width: 40px; height: 40px;
} } .top-info { display: flex; justify-content: center; align-items: center; .user-avatar { border-radius: 50%; img { width: 40px; height: 40px; border-radius: 50%;
} } } } </style>
2.公共样式
// reset.scss @import './transition.scss'; @import './public.scss'; @import './elementreset.scss'; *{ margin: 0; padding: 0; list-style: none;
}
/** 清除内外边距 **/ body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, /* structural elements 结构元素 */ dl, dt, dd, ul, ol, li,/* list elements 列表元素 */ pre, /* text formatting elements 文本格式元素 */ form, fieldset, legend, button, input, textarea, /* form elements 表单元素 */ th, td /* table elements 表格元素 */ { margin: 0; padding: 0;
} body,#app{ height: 100%; -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
} html{ height:100%;
} body{ height:100%; margin:0px; padding:0px;
} address, cite, dfn, em, var ,i{ font-style: normal;
}
/* for ie6 */ fieldset, img { border: 0; }
/* img :让链接里的 img 无边框 */ button, input, select, textarea { font-size: 100%;}
/* 使得表单元素在 ie 下能继承字体大小 *//* 注:optgroup 无法扶正 */ /** 重置表格元素 **/ table { border-collapse: collapse; border-spacing: 0; } label { font-weight: 700;
} html *{ font-size: 14px; box-sizing: border-box;
} *, *:before, *:after { box-sizing: inherit;
} // a:focus, // a:active { // outline: none; // } // a, // a:focus, // a:hover { // cursor: pointer; // text-decoration: none; // } div:focus { outline: none;
} .fr { float: right;
} .fl { float: left;
} .clearfix { &:after { visibility: hidden; display: block; font-size: 0; content: " "; clear: both; height: 0;
} } .md{ display: inline-block; vertical-align: middle;
}
/*去掉type为number的箭头*/ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { -webkit-appearance: none;
} input[type="number"] { -moz-appearance: textfield;
} // Dialog 对话框居中显示 .dialog-box-center{ text-align: center; &:after { content: ""; display: inline-block; height: 100%; width: 0; vertical-align: middle;
} .el-dialog{ text-align: left; display: inline-block; margin: 0 !important; vertical-align: middle; min-width: 800px;
} }
// transition.scss /*fade*/ .fade-enter-active, .fade-leave-active { transition: opacity 0.3s;
} .fade-enter, .fade-leave-active { opacity: 0;
}
/*fade-transform*/ .fade-transform-leave-active, .fade-transform-enter-active { transition: all .8s;
} .fade-transform-enter { opacity: 0; transform: translateX(-30px);
} .fade-transform-leave-to { opacity: 0; transform: translateX(30px);
}
// public.scss .pd10{ padding: 10px;
} .ptb10{ padding: 10px 0;
} .mt10{ margin-top: 10px;
} .md { display: inline-block; vertical-align: middle;
} // 进度条颜色 #nprogress .bar { background: red !important; //自定义颜色 } .flex-column { display: flex; justify-content: center; flex-direction: column;
}
/*滚动条样式*/ .page-component__scroll { height: 100%; .el-scrollbar__wrap { overflow-x: auto;
} } /*滚动条颜色*/ .scroll-bar-color { .el-scrollbar__thumb { background-color: rgba(118, 118, 119, 0.8);
} }
// elementreset.scss // 分页样式 .el-pagination { text-align: right; margin-top: 10px;
} // element ui表头换行 .el-table .cell { white-space: pre-line;
} // tooltip样式更改 固定宽高换行显示 .el-tooltip__popper { max-width: 400px; line-height: 180%;
} // 重置表单样式 element ui 下拉、输入、级联、日期 .reset-form { .el-input, .el-select, .el-cascader, .el-range-editor { width: 100% !important;
} .el-pagination { .el-input { width: 50px !important;
} .el-select { .el-input { width: 100px !important;
} width: 100px !important; } } } .el-table { .el-date-editor.el-input, .el-date-editor.el-input__inner { width: 100% !important;
} } // to fixed https://github.com/ElemeFE/element/issues/2461 // Dialog内select tree等组件在点击箭头时有虚晃 .el-dialog { transform: none; left: 0; position: relative; margin: 0 auto;
} // 当前行选中颜色高亮 .el-table--striped .el-table__body tr.el-table__row--striped.current-row td, .el-table__body tr.current-row>td { background-color: #ffec8b;
} .el-loading-mask { background-color: rgba(0, 0, 0, .3);
} // 菜单样式 /* 非折叠的竖直菜单处理方式和上方的水平菜单一样,只不过需要将horizontal改为vertical Element-UI中,在没有折叠的菜单中,无论是水平还是竖直菜单,子菜单是放在菜单栏所在的div中的, 只是将display属性设置为了none。 而在折叠菜单中,虽然菜单项也是放在页面上,但不在是放在菜单栏所在的div中,而是放在了页面底部的单独div中, 类属性值是el-menu--popup,因为是单独的div,所以在处理弹出菜单时就比较方便,直接处理el-submenu__title 和el-menu-item就可以,而不必区分是几级菜单项(如果不同级别菜单项要分别处理,需要使用“>”等操作分别处理) */
/*处理竖直菜单收齐后的弹出菜单中的子菜单 */ .el-menu--vertical .el-menu--popup .el-submenu__title { height: 40px; line-height: 40px;
} .el-menu--vertical .el-menu--popup .el-menu-item { height: 40px; line-height: 40px;
} .el-menu--vertical .el-menu--popup .el-icon-arrow-right:before { color: #fff;
}
3.面包屑组件
<!-- * @Description: 全局面包屑组件 Breadcrumb/index.vue * @Version: 2.0 * @Autor: lhl * @Date: 2020-08-04 17:51:48 * @LastEditors: lhl * @LastEditTime: 2020-08-20 16:57:07 -->
<template>
<div class="breadcrumb-box">
<!-- separator-class="el-icon-arrow-right" 图标分隔符 class -->
<el-breadcrumb separator="/">
<el-breadcrumb-item v-for="item in breadList" :to="{path: item.path }" :key="item.name"
>{{item.meta.title}}</el-breadcrumb-item>
</el-breadcrumb>
</div>
</template>
<script> export default { created() { this.getBreadcrumb(); }, data() { return { breadList: [], }; }, watch: { $route() { this.getBreadcrumb(); }, }, methods: { getBreadcrumb() { let matched = this.$route.matched.filter((item) => item.name); // console.log(matched,'matched')
this.breadList = matched; }, }, }; </script>
<style lang='scss' scoped> //@import url(); 引入公共css类 .breadcrumb-box{ padding: 10px 0; background: #fff; border-bottom: 1px solid #333;
}
</style>
以上代码本人项目实测!!!真实可靠,请勿随意转载~转载请注明出处~~~谢谢合作!