Vue Web开发(二)
1. 项目搭建
1.1. 首页架子搭建
使用Element ui中的Container布局容器,选择倒数第二个样式,将代码复制到Home.vue。
1.1.1.下载less
(1)下载less样式
npm i less
(2)下载less编辑解析器
npm i less-loader@5.0.0
在项目package.文件中可以看到下载包
1.1.2. 界面开发
界面
(1)按需引入组件
//main.js
import Vue from 'vue'
import App from './App.vue'
import 'element-ui/lib/theme-chalk/index.css';
//ElementUI全局引入
// import ElementUI from 'element-ui';
// Vue.use(ElementUI)
//ElementUI按需引入
import {Button,Container,Aside,Header,Main} from 'element-ui';
Vue.use(Button)
Vue.use(Container)
Vue.use(Aside)
Vue.use(Header)
Vue.use(Main)
import router from '../router/router.js';
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
}).$mount('#app')
(2)界面搭建
//view/home.vue
<template>
<el-container style="height: 100%;">
<el-aside width="auto">Aside</el-aside>
<el-container>
<el-header>Header</el-header>
<el-main>Main</el-main>
</el-container>
</el-container>
</template>
<script>
export default {
name: 'Home',
data() {
return {}
}
}
</script>
<style lang="less">
.el-header {
background-color: black;
}
.el-main {
padding-top: 0px;
}
</style>
1.2. 左侧导航栏实现
本质上这个模块应该是在Home.vue的Aside标签内,这个模块每个页面都会用到,所以我们把它新建成一个公共模块,所以我们在components文件下新建CommonAside.vue文件,components会存放所有组件。
左侧导航栏逻辑如图所示,有一级菜单、二级菜单。这里我们使用Element ui的NavMenu导航菜单组件的折叠组件。
(1)新建components/CommonAside.vue文件,引入现成组件,复制代码至CommonAside.vue文件,还有style、script代码。
//components/CommonAside.vue
<template>
<el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose" :collapse="isCollapse">
<el-submenu index="1">
<template slot="title">
<i class="el-icon-location"></i>
<span slot="title">导航一</span>
</template>
<el-menu-item-group>
<span slot="title">分组一</span>
<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">
<span slot="title">选项4</span>
<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>
</template>
<script>
export default {
data() {
return {
isCollapse: true
};
},
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
}
}
}
</script>
<style>
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
</style>
(2)在CommonAside.vue文件中新建template标签,将元素标签放入,style、script代码在template标签外面。根据外面的逻辑图删除一些不必要的元素。
//components/CommonAside.vue
<template>
<el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose"
:collapse="isCollapse">
<el-menu-item index="2">
<i class="el-icon-menu"></i>
<span slot="title">导航二</span>
</el-menu-item>
<el-submenu index="1">
<template slot="title">
<i class="el-icon-location"></i>
<span slot="title">导航一</span>
</template>
<el-menu-item-group>
<span slot="title">分组一</span>
<el-menu-item index="1-1">选项1</el-menu-item>
</el-menu-item-group>
</el-submenu>
<el-menu-item index="3" disabled>
<i class="el-icon-document"></i>
<span slot="title">导航三</span>
</el-menu-item>
</el-menu>
</template>
<script>
export default {
data() {
return {
isCollapse: false
};
},
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
}
}
}
</script>
<style>
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
</style>
(3)menu数据:在data()return中定义menu,将数据放入menu,并且将isCollapse属性设置为false!!!,表示图标展开。
[
{
path: "/",
name: "home",
label: "首页",
icon: "s-home",
url: "Home/Home",
},
{
path: "/mail",
name: "mail",
label: "商品管理",
icon: "video-play",
url: "MailManage/MailManage",
},
{
path: "/user",
name: "user",
label: "用户管理",
icon: "user",
url: "UserManage/UserManage",
},
{
label: "其他",
icon: "location",
children: [
{
path: "/page1",
name: "page1",
label: "页面1",
icon: "setting",
url: "Other/PageOne",
},
{
path: "/page2",
name: "page2",
label: "页面2",
icon: "setting",
url: "Other/PageTwo",
}
],
},
]
//components/CommonAside.vue
<template>
<el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose"
:collapse="isCollapse">
<el-menu-item index="2">
<i class="el-icon-menu"></i>
<span slot="title">导航二</span>
</el-menu-item>
<el-submenu index="1">
<template slot="title">
<i class="el-icon-location"></i>
<span slot="title">导航一</span>
</template>
<el-menu-item-group>
<span slot="title">分组一</span>
<el-menu-item index="1-1">选项1</el-menu-item>
</el-menu-item-group>
</el-submenu>
<el-menu-item index="3" disabled>
<i class="el-icon-document"></i>
<span slot="title">导航三</span>
</el-menu-item>
</el-menu>
</template>
<script>
export default {
data() {
return {
isCollapse: false,
menu: [{
path: "/",
name: "home",
label: "首页",
icon: "s-home",
url: "Home/Home",
},
{
path: "/mail",
name: "mail",
label: "商品管理",
icon: "video-play",
url: "MailManage/MailManage",
},
{
path: "/user",
name: "user",
label: "用户管理",
icon: "user",
url: "UserManage/UserManage",
},
{
label: "其他",
icon: "location",
children: [{
path: "/page1",
name: "page1",
label: "页面1",
icon: "setting",
url: "Other/PageOne",
},
{
path: "/page2",
name: "page2",
label: "页面2",
icon: "setting",
url: "Other/PageTwo",
}
],
},
]
};
},
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
}
}
}
</script>
<style>
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
</style>
在CommonAside.vue中,这里主要是处理数据,使用computed计算属性,两个属性,noChildren和hasChildren,需要对数据源进行过滤。过滤使用filter方法,filter里面有一个函数,判断是否有子项目,这样可以拿到noChildren和hasChildren两个数组。主要是为了区分一二级菜单的渲染。
//计算属性
computed:{
noChildren(){
return this.menu.filter(item => !item.children)
},
hasChildren(){
return this.menu.filter(item => item.children)
}
}
1.2.1. 一级菜单渲染
一级菜单,进行页面渲染,更改前面的代码。遍历有v-for,使用遍历需要加上key,使用路径作为唯一标识。图标原本是,这里我们用字符串拼接,因为数据中有icon对象,双花括号渲染数据,数据有多少条就渲染多少条,一级菜单一个有四个,分别是首页、商品管理、用户管其他。
<!-- 一级菜单,:=v-bind: -->
<el-menu-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>
//components/CommonAside.vue
<template>
<el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose"
:collapse="isCollapse">
<!-- 一级菜单,:=v-bind: -->
<el-menu-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 index="1">
<template slot="title">
<i class="el-icon-location"></i>
<span slot="title">导航一</span>
</template>
<el-menu-item-group>
<span slot="title">分组一</span>
<el-menu-item index="1-1">选项1</el-menu-item>
</el-menu-item-group>
</el-submenu>
<el-menu-item index="3" disabled>
<i class="el-icon-document"></i>
<span slot="title">导航三</span>
</el-menu-item>
</el-menu>
</template>
<script>
export default {
data() {
return {
isCollapse: false,
menu: [{
path: "/",
name: "home",
label: "首页",
icon: "s-home",
url: "Home/Home",
},
{
path: "/mail",
name: "mail",
label: "商品管理",
icon: "video-play",
url: "MailManage/MailManage",
},
{
path: "/user",
name: "user",
label: "用户管理",
icon: "user",
url: "UserManage/UserManage",
},
{
label: "其他",
icon: "location",
children: [{
path: "/page1",
name: "page1",
label: "页面1",
icon: "setting",
url: "Other/PageOne",
},
{
path: "/page2",
name: "page2",
label: "页面2",
icon: "setting",
url: "Other/PageTwo",
}
],
},
]
};
},
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
}
},
//计算属性
computed: {
//没有子菜单
noChildren() {
return this.menu.filter(item => !item.children)
},
//有子菜单
hasChildren() {
return this.menu.filter(item => item.children)
}
}
}
</script>
<style>
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
</style>
1.2.2. 二级菜单渲染
更改CommonAside.vue文件,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">{{item.label}}</span>
</template>
<!-- 这里subItem和subIndex并没有实际意义,只是用来指代item.children的多个数组,两者甚至可以互换,只新定义一个也可以的,:index后面有没有.path都可以运行成功 -->
<el-menu-item-group v-for="(subItem,subIndex) in item.children" :key="subItem.path">
<el-menu-item :index="subIndex.path">{{subItem.label}}</el-menu-item>
</el-menu-item-group>
</el-submenu>
//components/CommonAside.vue
<template>
<el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose"
:collapse="isCollapse">
<h3>通用后台管理系统</h3>
<!-- 一级菜单,:=v-bind: -->
<el-menu-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">{{item.label}}</span>
</template>
<!-- 这里subItem和subIndex并没有实际意义,只是用来指代item.children的多个数组,两者甚至可以互换,只新定义一个也可以的,:index后面有没有.path都可以运行成功 -->
<el-menu-item-group v-for="(subItem,subIndex) in item.children" :key="subItem.path">
<el-menu-item :index="subIndex.path">{{subItem.label}}</el-menu-item>
</el-menu-item-group>
</el-submenu>
<el-menu-item index="3" disabled>
<i class="el-icon-document"></i>
<span slot="title">导航三</span>
</el-menu-item>
</el-menu>
</template>
<script>
export default {
data() {
return {
isCollapse: false,
menu: [{
path: "/",
name: "home",
label: "首页",
icon: "s-home",
url: "Home/Home",
},
{
path: "/mail",
name: "mail",
label: "商品管理",
icon: "video-play",
url: "MailManage/MailManage",
},
{
path: "/user",
name: "user",
label: "用户管理",
icon: "user",
url: "UserManage/UserManage",
},
{
label: "其他",
icon: "location",
children: [{
path: "/page1",
name: "page1",
label: "页面1",
icon: "setting",
url: "Other/PageOne",
},
{
path: "/page2",
name: "page2",
label: "页面2",
icon: "setting",
url: "Other/PageTwo",
}
],
},
]
};
},
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
}
},
//计算属性
computed: {
//没有子菜单
noChildren() {
return this.menu.filter(item => !item.children)
},
//有子菜单
hasChildren() {
return this.menu.filter(item => item.children)
}
}
}
</script>
<style>
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
</style>