不知不觉已写到第7篇。前面6篇都是探索性的实现,是学习理论的过程,从这篇开始,开始用理论来指导实践了。
接上篇,我们现在通过组件继承实现Admin页面内导航。
动态导航
我们要的导航,是根据登录用户的权限,显示不同的导航菜单。根据职能分工,菜单内容的确定由后端来做更符合实践,前端只需要实现动态渲染菜单即可。好在这是Vue擅长的。
页内跳转.PNG
在components目录下新建Aside.vue
。在Aside.vue
中放置一个el-menu
,我们先用一个静态的占个位,然后实现成动态的。静态的我们直接用ElemenUI自己的例子好了。
<template>
<el-row>
<el-col :span="24">
<h5>管理后台</h5>
<el-menu
default-active="2"
class="el-menu-vertical-demo"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b">
<el-submenu index="1">
<template slot="title">
<i class="el-icon-location"></i>
<span>导航一</span>
</template>
<el-menu-item-group>
<template slot="title">分组一</template>
<el-menu-item index="1-1">选项1</el-menu-item>
<el-menu-item index="1-2">选项2</el-menu-item>
</el-menu-item-group>
<el-menu-item-group title="分组2">
<el-menu-item index="1-3">选项3</el-menu-item>
</el-menu-item-group>
<el-submenu index="1-4">
<template slot="title">选项4</template>
<el-menu-item index="1-4-1">选项1</el-menu-item>
</el-submenu>
</el-submenu>
<el-menu-item index="2">
<i class="el-icon-menu"></i>
<span slot="title">导航二</span>
</el-menu-item>
<el-menu-item index="3" disabled>
<i class="el-icon-document"></i>
<span slot="title">导航三</span>
</el-menu-item>
<el-menu-item index="4">
<i class="el-icon-setting"></i>
<span slot="title">导航四</span>
</el-menu-item>
</el-menu>
</el-col>
</el-row>
</template>
<script>
export default {
};
</script>
<style scoped>
/*去掉最右边的白框,个人习惯*/
.el-menu {
border-right: 0;
}
</style>
Admin.vue
<el-aside width="300px"><Aside /></el-aside>
name: 'App',
components: {
Aside,
},
修改下Admin.vue
中的背景色,否则太难看
.el-aside {
background-color: #545c64;/*这里*/
color: #333;
text-align: center;
}
现在,npm run dev,正常的话,显示效果已经出来了!
下面来实现动态效果。
现在修改Aside.vue
来实现自定义菜单
<template>
<el-row>
<el-col :span="24">
<h5>管理后台</h5>
<el-menu
default-active="2"
class="el-menu-vertical-demo"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b">
<template v-for="menu in menus">
<el-submenu :index="menu.index" v-if="menu.items" :key="menu.index">
<template slot="title"><i :class="getIcon(menu.icon)"></i>{{menu.label}}</template>
<el-menu-item v-for="item in menu.items"
:index="item.index" @click="send(item)" :key="item.index">
<i :class="getIcon(item.icon)"></i>{{item.label}}
</el-menu-item>
</el-submenu>
<el-menu-item :index="menu.index" @click="send(menu)" :key="menu.index" v-else>
<i :class="getIcon(menu.icon)"></i>{{menu.label}}
</el-menu-item>
</template>
</el-menu>
</el-col>
</el-row>
</template>
<script>
/**
* 定义一个menus,体验菜单的动态渲染
* 将来会通过props传进来
*/
const menus = [
{
index: '1',
label: '配置管理',
icon: 'document',
items: [
{
index: '11',
label: '网站配置',
url: 'web.json',
},
{
index: '12',
label: '数据库配置',
url: 'core,json',
},
],
},
{
index: '2',
label: '用户管理',
url: 'login.json',
redirect: true,
},
{
index: '3',
label: '统计信息',
url: 'status.json',
icon: 'location',
},
];
export default {
data() {
return { menus };
},
methods: {
send(item) {
this.$emit('redirect', item);
},
getIcon(icon = 'menu') {
return `el-icon-${icon}`;
},
},
};
</script>
<style scoped>
/*去掉菜单最右边的白框,个人习惯*/
.el-menu {
border-right: 0;
text-align: left;
}
</style>
我们的菜单已经是通过一个数组menus
来自定义了,根据vue特性,修改menus
菜单就会变化哦,现在我们先不测试这个,留待将来在测试。我们这个有更重要的,菜单点击后会向Admin
组件发布redirect
消息,我们修改Admin
组件,处理这个消息。
给Admin
组件添加响应消息的地方
<el-aside width="240px"><Aside @redirect="onRedirect"/></el-aside>
...
<el-main><component :config="view" v-bind:is="view.name" /></el-main>
...
<script>
export default {
data() {
return {
view: {
},
};
},
methods: {
submit() {
this.$emit('redirect', { url: '/login.json' });
},
onRedirect(action) {
// 冒泡
if (this.passUp(action)) return this.$emit('redirect', action);
// 本地处理
return this.$HttpSend(action).then((response) => {
this.view = response.view;
throw new Error('route');
}).catch(() => {});
},
passUp(action) {
return action && action.redirect;
},
},
};
</script>
给Admin
组件添加几个临时组件方便效果展示
const Table = {
template: '<H1>Table</H1>',
};
const Form = {
template: '<H1>Form</H1>',
};
const Chart = {
template: '<H1>Chart</H1>',
};
export default {
components: {
Aside,
Table,
Form,
Chart,
},
data() {...
突发奇想,就想修改下Http.js(HttpSend参数格式变了)
/**
* 远程调用的核心方法
* @returns {Promise<T>}
*/
static HttpSend = (action = {}) => {
/** @type {boolean} */
const withValue = action && action.value;
const option = {
url: Http.createUrl((action) ? action.url : undefined),
};
if (action && action.post) {
option.method = 'post';
if (withValue) option.data = Qs.stringify(action.value);
option.headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
} else {
if (withValue) option.params = JSON.parse(JSON.stringify(action.value));
option.method = 'get';
}
// 开启跨域cookie
option.withCredentials = true;
option.paramsSerializer = params => Qs.stringify(params, { arrayFormat: 'brackets' });
return $http(option).then((response) => {
const data = response.data;
// 判断返回结果信息
if ((function isError(v) {
if (typeof v !== 'object') return false;
if (v.status === false) return true;
return (v.status && Number(v.status) <= 0);
})(data)) return Http.onError(data, '操作无效');
return Http.onReceive(data);
}, error => Http.onError(error, '数据获取失败'))
.catch(error => Http.onError(error, '内部错误'));
};
/**
* 触发钩子函数
* @type {Function}
* @param {Object} data
* @returns {Object}
*/
static onReceive = (data) => {
Http.receivers.forEach(receiver => receiver(data));
return data;
}
/**
* 插件安装函数
*/
static install(Vue) {
this.vue = Vue;
this.createUrl = this.vue.createUrl || (url => url);
this.vue.prototype.$httpGet = (url, value = null) => this.HttpSend({ url, value });
this.vue.prototype.$HttpPost = (url, value = null) => this.HttpSend({ url, value, post: true });
this.vue.prototype.$HttpSend = Http.HttpSend;
this.vue.prototype.$addReceiver = receiver => this.receivers.push(receiver);
this.vue.prototype.$removeReceiver = id => this.receivers.splice(id, 1);
}
看看神奇的效果吧。原来的几个按钮,因为Http.js的修改,失效了,改起来很简单,不会就问我。
这样呢,App和Admin有一部分重复的功能,我们提取出来
<script>
export default {
data() {
return {
view: {
},
};
},
methods: {
onRedirect(action) {
// 冒泡
if (this.passUp(action)) return this.$emit('redirect', action);
// 本地处理
return this.$HttpSend(action).then((response) => {
this.view = response.view;
throw new Error('route');
}).catch(() => {});
},
passUp(action) {
return action && action.redirect;
},
},
};
</script>
取名叫Container.vue放在components下。
修改App.vue
import Father from './components/Container';
...
export default {
name: 'App',
extends: Father,
data() {
return {
trace: {
rows: [],
},
};
},
...
methods: {
passUp() {
return false;
},
},
};
</script>
修改Admin.vue
export default {
extends: Father,
...
methods: {
submit() {
this.$emit('redirect', { url: '/login.json' });
},
},
};
看看效果,妈呀,组件继承就这么简单!!!
网友评论