為了防止接口異常,在上一章的基礎(chǔ)上創(chuàng)建一個(gè)mork文件夾寫了個(gè)menu.json放入public文件里:
Element官網(wǎng):https://element.eleme.cn/#/zh-CN/guide/design
{
? ? "data": [
? ? ? ? {
? ? ? ? ? ? "id": 101,
? ? ? ? ? ? "authName": "用戶管理",
? ? ? ? ? ? "path": "users",
? ? ? ? ? ? "children": [
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? "id": 1,
? ? ? ? ? ? ? ? ? ? "authName": "用戶列表",
? ? ? ? ? ? ? ? ? ? "path": "users",
? ? ? ? ? ? ? ? ? ? "children": []
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? "id": 2,
? ? ? ? ? ? ? ? ? ? "authName": "添加用戶",
? ? ? ? ? ? ? ? ? ? "path": "addusers",
? ? ? ? ? ? ? ? ? ? "children": []
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ]
? ? ? ? },
? ? ? ? {
? ? ? ? ? ? "id": 102,
? ? ? ? ? ? "authName": "分類管理",
? ? ? ? ? ? "path": "categories",
? ? ? ? ? ? "children": [
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? "id": 1,
? ? ? ? ? ? ? ? ? ? "authName": "分類列表",
? ? ? ? ? ? ? ? ? ? "path": "categories",
? ? ? ? ? ? ? ? ? ? "children": []
? ? ? ? ? ? ? ? },{
? ? ? ? ? ? ? ? ? ? "id": 2,
? ? ? ? ? ? ? ? ? ? "authName": "添加分類",
? ? ? ? ? ? ? ? ? ? "path": "addcategories",
? ? ? ? ? ? ? ? ? ? "children": []
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ]
? ? ? ? },
? ? ? ? {
? ? ? ? ? ? "id": 103,
? ? ? ? ? ? "authName": "商品管理",
? ? ? ? ? ? "path": "goods",
? ? ? ? ? ? "children": [
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? "id": 1,
? ? ? ? ? ? ? ? ? ? "authName": "商品列表",
? ? ? ? ? ? ? ? ? ? "path": "goods",
? ? ? ? ? ? ? ? ? ? "children": []
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ]
? ? ? ? }
? ? ],
? ? "meta": {
? ? ? ? "msg": "獲取菜單列表成功",
? ? ? ? "status": 200
? ? }
}
App.vue里放入路由容器:
<template>
? <div id="app">
? ? <router-view></router-view>
? </div>
</template>
<style lang="scss">
</style>
view下LoginView.vue:
<template>
? ? <!-- el-form 組件
? ? :model="ruleForm" ruleForm是data中定義的存儲(chǔ)的是用戶名和密碼值的對(duì)象 通過model傳給el-form組件 -->
? ? <!-- :rules="rules" rules是data中定義的對(duì)象目的是校驗(yàn)用戶名和密碼的規(guī)則 ?-->
? ? <!-- ref="ruleForm" 咱們可以通過ref來獲取el-form組件內(nèi)部的方法 比如:validate校驗(yàn)方法 resetFields重置方法 ?-->
? ? <!-- status-icon 是在表單校驗(yàn)錯(cuò)誤的時(shí)候 輸入框中出現(xiàn)的提示小圖標(biāo)-->
? ? <!-- label-width="200px" 是用來控制用戶名和密碼文本的寬度 ?-->
? ? <div class="myform">
? ? ? ? <el-form :model="ruleForm" ?status-icon :rules="rules" ref="ruleForm" label-width="100px">
? ? ? ? ? ? <!-- label 控制輸入框的文本 ?prop="username" 是對(duì)應(yīng)表單域model中的username字段
? ? ? ? ? ? 規(guī)則的名字需要和表單域model中的字段一模一樣 -->
? ? ? ? ? ? <el-form-item label="用戶名" prop="username">
? ? ? ? ? ? ? <!-- v-model 里面對(duì)應(yīng)的是data中的數(shù)據(jù) -->
? ? ? ? ? ? ? ? <el-input v-model="ruleForm.username"></el-input>
? ? ? ? ? ? </el-form-item>
? ? ? ? ? ? <el-form-item label="密碼" prop="password">
? ? ? ? ? ? ? <!-- autocomplete="off" 作用是把輸入框的自動(dòng)提示功能關(guān)閉 -->
? ? ? ? ? ? ? ? <el-input type="password" v-model="ruleForm.password" autocomplete="off"></el-input>
? ? ? ? ? ? </el-form-item>
? ? ? ? ? ? <el-form-item>
? ? ? ? ? ? ? <!-- 提交的時(shí)候把ref里面的名字傳過去目的是為了使用refs方法 來調(diào)用el-form里面的 validate校驗(yàn)方法-->
? ? ? ? ? ? ? ? <el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
? ? ? ? ? ? ? ? <!-- 提交的時(shí)候把ref里面的名字傳過去目的是為了使用refs方法 來調(diào)用el-form里面的 resetFields重置方法-->
? ? ? ? ? ? ? ? <el-button @click="resetForm('ruleForm')">重置</el-button>
? ? ? ? ? ? </el-form-item>
? ? ? ? </el-form>
? ? </div>
</template>
<script>
import axios from 'axios';
? export default {
? ? name:"LoginView",
? ? data() {
? ? ? var checkUser = (rule, value, callback) => {
? ? ? ? console.log('用戶名:',value)
? ? ? ? if(value.trim()==''){
? ? ? ? ? ? callback(new Error('請(qǐng)輸入用戶名'));
? ? ? ? }else if(!/^[0-9a-zA-Z_\u4e00-\u9fa5@.]{5,12}$/.test(value)){
? ? ? ? ? ? callback(new Error('用戶名為5-10位中英文數(shù)字或者下劃線'));
? ? ? ? }
? ? ? ? else{
? ? ? ? ? ? callback();
? ? ? ? }
? ? ? };
? ? ? var validatePass = (rule, value, callback) => {
? ? ? ? console.log('密碼:',value)
? ? ? ? if (value.trim()=='') {
? ? ? ? ? callback(new Error('請(qǐng)輸入密碼'));
? ? ? ? } else{
? ? ? ? ? callback();
? ? ? ? }
? ? ? };
? ? ? return {
? ? ? ? ruleForm: {
? ? ? ? ? password: '',
? ? ? ? ? username: ''
? ? ? ? },
? ? ? ? rules: {
? ? ? ? ? password: [
? ? ? ? ? ? { validator: validatePass, trigger: 'blur' }
? ? ? ? ? ],
? ? ? ? ? username: [
? ? ? ? ? ? { validator: checkUser, trigger: 'blur' }
? ? ? ? ? ]
? ? ? ? }
? ? ? };
? ? },
? ? methods: {
? ? ? submitForm(formName) {
? ? ? ? this.$refs[formName].validate((valid) => {
? ? ? ? ? /* el-form組件的validate方法 在回調(diào)函數(shù)中
? ? ? ? ? ?如果 valid 為 true 則表示表單校驗(yàn)通過
? ? ? ? ? ?為false則表示不通過 */
? ? ? ? ? if (valid) {
? ? ? ? ? ? axios.post('https://api.***.ed***********',{
? ? ? ? ? ? ? email:this.ruleForm.username,
? ? ? ? ? ? ? password:this.ruleForm.password
? ? ? ? ? ? })
? ? ? ? ? ? .then(res=>{
? ? ? ? ? ? ? let {access_token} = res.data
? ? ? ? ? ? ? ? ? this.$message.success('登陸成功')
? ? ? ? ? ? ? ? ? /* 當(dāng)?shù)卿洺晒?把用戶名和token存入本地緩存中方便后續(xù)使用 */
? ? ? ? ? ? ? ? ? localStorage.token = access_token
? ? ? ? ? ? ? ? ? /* 登錄成功后過一秒跳轉(zhuǎn)首頁 */
? ? ? ? ? ? ? ? ? setTimeout(()=>{
? ? ? ? ? ? ? ? ? ? this.$router.push({name:'index'})
? ? ? ? ? ? ? ? ? },1000)
? ? ? ? ? ? })
? ? ? ? ? ? ? /* 登錄失敗(包括用戶名或者密碼不對(duì)會(huì)走catch) */
? ? ? ? ? ? .catch(()=>{
? ? ? ? ? ? ? this.$message.error('登陸失敗')
? ? ? ? ? ? })
? ? ? ? ? } else {
? ? ? ? ? ? this.$message.error('您輸入的有誤')
? ? ? ? ? }
? ? ? ? });
? ? ? },
? ? ? resetForm(formName) {
? ? ? ? /* 通過vue中的$refs方法來調(diào)用組件el-form中的 resetFields重置方法 */
? ? ? ? this.$refs[formName].resetFields();
? ? ? }
? ? }
? }
</script>
<style lang="scss">
? ? .myform{
? ? ? ? width:600px;
? ? ? ? margin:50px auto;
? ? }
</style>
view下IndexView.vue:
//這里做了點(diǎn)改動(dòng),相比上一章這里采取動(dòng)態(tài)路由來獲取側(cè)邊欄以及二級(jí)菜單:
相關(guān)注意點(diǎn)已用注釋表明:
<template>
? <!-- 100vh全屏展示 -->
? <el-container style="height: 100vh; border: 1px solid #eee">
? ? <el-aside width="200px" style="background-color: rgb(238, 241, 246)">
? ? ? <!-- <el-menu :default-openeds="['1', '3']"> 表示默認(rèn)展開第幾個(gè)菜單 -->
? ? ? <!-- 1對(duì)應(yīng)了el-submenu index="1" -->
? ? ? <!-- :default-openeds="openList" 不可以直接['1'] 需要一個(gè)變量openList代替
? ? ? ? 因?yàn)橹禃?huì)變,如果寫死 ['1'] 那么就永遠(yuǎn)不會(huì)變
? ? ? ? ? ? ?否則點(diǎn)二級(jí)菜單 一級(jí)菜單會(huì)自動(dòng)合上-->
? ? ? <el-menu
? ? ? ? :default-openeds="openList"
? ? ? ? :router="true"
? ? ? ? :default-active="pagepath"
? ? ? ? :unique-opened="true"
? ? ? >
? ? ? ? <!-- :unique-opened="true" 表示始終只打開一個(gè)欄點(diǎn)開一個(gè)欄另外的會(huì)收起來-->
? ? ? ? <!-- default-active="/index/users 表示一進(jìn)入頁面就默認(rèn)激活/index/users 導(dǎo)航菜單欄 -->
? ? ? ? <!-- 不能寫死值,要用監(jiān)聽器解決 -->
? ? ? ? <!-- 把router屬性改成true才能實(shí)現(xiàn)點(diǎn)擊跳轉(zhuǎn) -->
? ? ? ? <!-- index接收的是字符串類型,(i+1)是數(shù)字類型,所以使用toString方法轉(zhuǎn)成字符串,傳給index -->
? ? ? ? <!-- 因?yàn)閕是從0開始的 所以需要+1 -->
? ? ? ? <el-submenu
? ? ? ? ? :index="(i + 1).toString()"
? ? ? ? ? v-for="(v, i) in navList"
? ? ? ? ? :key="i"
? ? ? ? >
? ? ? ? ? <template slot="title"
? ? ? ? ? ? ><i class="el-icon-menu"></i>{{ v.authName }}</template
? ? ? ? ? >
? ? ? ? ? <!-- <template slot="title">分組一</template> -->
? ? ? ? ? <!-- el-menu-item index="1-1" 表示第一個(gè)導(dǎo)航里面的第一個(gè)子項(xiàng) -->
? ? ? ? ? <!-- 子選項(xiàng)需要改成例如: 1-1格式 以字符串的形式傳給index屬性 -->
? ? ? ? ? <!-- 因?yàn)樽舆x項(xiàng)也是一個(gè)數(shù)組所以需要再次循環(huán) -->
? ? ? ? ? <el-menu-item
? ? ? ? ? ? :index="'/index/' + item.path"
? ? ? ? ? ? v-for="(item, index) in v.children"
? ? ? ? ? ? :key="index"
? ? ? ? ? >
? ? ? ? ? ? {{ item.authName }}
? ? ? ? ? </el-menu-item>
? ? ? ? </el-submenu>
? ? ? </el-menu>
? ? </el-aside>
? ? <el-container>
? ? ? <el-header style="text-align: right; font-size: 12px">
? ? ? ? <el-dropdown>
? ? ? ? ? <i class="el-icon-setting" style="margin-right: 15px"></i>
? ? ? ? ? <el-dropdown-menu slot="dropdown">
? ? ? ? ? ? <el-dropdown-item>查看</el-dropdown-item>
? ? ? ? ? ? <el-dropdown-item>新增</el-dropdown-item>
? ? ? ? ? ? <el-dropdown-item>刪除</el-dropdown-item>
? ? ? ? ? </el-dropdown-menu>
? ? ? ? </el-dropdown>
? ? ? ? <span>王小虎</span>
? ? ? </el-header>
? ? ? <el-main>
? ? ? ? <router-view></router-view>
? ? ? </el-main>
? ? </el-container>
? </el-container>
</template>
<script>
import axios from "axios";
export default {
? data() {
? ? return {
? ? ? openList: ["1"],
? ? ? navList: [],
? ? ? pagepath: "/index/users",
? ? };
? },
? watch: {
? ? /* 當(dāng)路由發(fā)生變化的時(shí)候,就把最新的地址給到pagepath變量
? ? ? ?作用是為了保持路由菜單欄的高亮顯示,以及解決點(diǎn)擊不跳轉(zhuǎn)的bug */
? ? $route: {
? ? ? handler: function (newV) {
? ? ? ? console.log(newV);
? ? ? ? this.pagepath = newV.path;
? ? ? },
? ? ? immediate: true,
? ? },
? },
? created: function () {
? ? this.getNaviList();
? },
? methods: {
? ? getNaviList: function () {
? ? ? axios
? ? ? ? .get("/mork/menu.json", {
? ? ? ? ? headers: {
? ? ? ? ? ? Authorization: localStorage.token,
? ? ? ? ? },
? ? ? ? })
? ? ? ? .then((res) => {
? ? ? ? ? console.log(res);
? ? ? ? ? let { data, meta } = res.data;
? ? ? ? ? /* 數(shù)據(jù)獲取成功 */
? ? ? ? ? if (meta.status == 200) {
? ? ? ? ? ? this.navList = data;
? ? ? ? ? ? /* 動(dòng)態(tài)添加路由 */
? ? ? ? ? ? /* 因?yàn)榈谝粋€(gè)路由是默認(rèn)的所以我們從第二個(gè)路由開始動(dòng)態(tài)添加 */
? ? ? ? ? ? console.log(this.navList);
? ? ? ? ? ? let arr = this.navList.slice(1,3)
? ? ? ? ? ? /* 循環(huán)路由數(shù)組 動(dòng)態(tài)添加路由 */
? ? ? ? ? ? console.log(arr);
? ? ? ? ? ? arr.forEach(v => {
? ? ? ? ? ? ? /* 我們盡量使用v.children[0].path 原因是我們的路徑名用的是子路由的 */
? ? ? ? ? ? ?/* 如果我們直接寫死 v.children[0].path 會(huì)導(dǎo)致只有一個(gè)子路由的路徑被動(dòng)態(tài)添加了
? ? ? ? ? ? ? ? 如果有多個(gè)就無法生效, 所以我們要二次循環(huán)v.children,從而實(shí)現(xiàn)多個(gè)二級(jí)子路由
? ? ? ? ? ? ? ? 能夠被動(dòng)態(tài)的添加*/
? ? ? ? ? ? ?v.children.forEach(r=>{
? ? ? ? ? ? ? ? this.$router.addRoute("index",
? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? path:r.path,
? ? ? ? ? ? ? ? name:r.path,
? ? ? ? ? ? ? ? component:()=>import(`@/views/${r.path.substring(0,1).toUpperCase()+r.
? ? ? ? ? ? ? ? path.substring(1)}View.vue`),
? ? ? ? ? ? ? },
? ? ? ? ? ? ? );
? ? ? ? ? ? ? })
? ? ? ? ? ? ? this.$router.addRoute("index",
? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? path:v.children[0].path,
? ? ? ? ? ? ? ? name:v.children[0].path,
? ? ? ? ? ? ? ? component:()=>import(`@/views/${v.children[0].path.substring(0,1).toUpperCase()+v.children[0].
? ? ? ? ? ? ? ? path.substring(1)}View.vue`),
? ? ? ? ? ? ? },
? ? ? ? ? ? ? );
? ? ? ? ? ? });
? ? ? ? ? ? console.log(this.$router);
? ? ? ? ? } else {
? ? ? ? ? ? /* 防止數(shù)據(jù)獲取失敗給出相應(yīng)的后臺(tái)提示 */
? ? ? ? ? ? this.$message.error(meta.msg);
? ? ? ? ? }
? ? ? ? })
? ? ? ? .catch((err) => {
? ? ? ? ? console.log(err);
? ? ? ? });
? ? },
? },
};
</script>
<style scoped>
.el-header {
? background-color: #b3c0d1;
? color: #333;
? line-height: 60px;
}
.el-aside {
? color: #333;
}
</style>
router下路由配置:采取動(dòng)態(tài)路由,之前的注釋掉了:
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
? {
? ? path: '/',
? ? name: 'login',
? ? component:()=>import('@/views/LoginView.vue')
? },
? {
? ? path:'/index',
? ? name:'index',
? ? /* 已進(jìn)入頁面就默認(rèn)進(jìn)入二級(jí)路由users頁面 */
? ? redirect:'/index/users',
? ? component:()=>import('@/views/IndexView.vue'),
? ? ?children:[{
? ? ? path:'users',
? ? ? name:'users',
? ? ? component:()=>import('../views/UsersView.vue'),
? ? ? },
? ? ? {
? ? ? ? path:'addusers',
? ? ? name:'addusers',
? ? ? component:()=>import('../views/AddusersView.vue'),
? ? ? }
? ? ?/* {
? ? ? ?path:'roles',
? ? ? ?name:'roles',
? ? ? ?component:()=>import('../views/RolesView.vue'),
? ? ?},
? ? ?{
? ? ? ?path:'rights',
? ? ? ?name:'rights',
? ? ? ?component:()=>import('../views/RightsView.vue'),
? ? ?},
? ? ?{
? ? ? ?path:'goods',
? ? ? ?name:'goods',
? ? ? ?component:()=>import('../views/GoodsView.vue'),
? ? ?},
? ? ?{
? ? ? ?path:'params',
? ? ? ?name:'params',
? ? ? ?component:()=>import('../views/ParamsView.vue'),
? ? ?},
? ? ?{
? ? ? ?path:'categories',
? ? ? ?name:'categories',
? ? ? ?component:()=>import('../views/CategoriesView.vue'),
? ? ?},
? ? ?{
? ? ? ?path:'categories',
? ? ? ?name:'categories',
? ? ? ?component:()=>import('../views/CategoriesView.vue'),
? ? ?},
? ? ?{
? ? ? ?path:'orders',
? ? ? ?name:'ordes',
? ? ? ?component:()=>import('../views/OrdersView.vue'),
? ? ?},
? ? ?{
? ? ? ?path:'reports',
? ? ? ?name:'reports',
? ? ? ?component:()=>import('../views/ReportsView.vue'),
? ? ?}, */
? ]
? }
]
const router = new VueRouter({
? routes
})
export default router
views下跳轉(zhuǎn)的AddcategoriesView.vue:
<template>
? <div><h1>添加分類</h1></div>
</template>
<script>
export default {
}
</script>
<style>
</style>