本文转自:https://godbasin.github.io/2017/06/02/angular2-free-4-create-sidebar/

因为项目原因又玩上了Angular2(v4.0+),《玩转Angular2》系列用于探索一些灵活或者新的用法。
本文记录制作左侧菜单,并使用路由自动定位的过程。

调整配置


上一篇有些配置不是很合适,故这里我们先进行调整。

全局注入jQuery

上篇我们是这样注入jQuery的:

1
2
// jquery
window['$'] = window['jQuery'] = require('./assets/js/jquery.min.js');

这样的全局注入其实可能会导致一些问题(不知道是不是配置不正确,导致本骚年的其他jQuery插件失效),所以我们还是用webpack来注入。
首先安装jQuery的依赖:

1
npm install jquery --save

然后在webpack的插件配置plugins中添加:

1
2
3
4
5
6
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
]

就可以挪掉上面不够优雅的注入方式了。

开启source-map

之前我们的webpack配置中也添加了devtool: 'source-map',但是这个需要配合source-map-loader才能生效:

1
npm install -D source-map-loader

然后在webpack中添加loader:

1
2
3
4
5
6
7
8
9
10
11
rules: [
{
test: /\.js$/,
use: ["source-map-loader"],
enforce: "pre",
exclude: [
path.join(__dirname, 'node_modules', '@angular/compiler'),
path.join(__dirname, 'node_modules', 'rxjs')
]
}
]

这里我们需要排除@angular/compiler以及rxjs,可能还有其他一些依赖,不然会有webpack的warning。详细也可以查看类似的issue-Warnings displayed by webpack when using source-map-loader

压缩代码

webpack自带了一个压缩插件UglifyJsPlugin,我们添加以下配置就可以生效:

1
2
3
4
5
6
7
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
]

压缩后的代码体积大大减小,但会消耗一定的编译速度,故一般打包到生产环境才会使用。

分离代码

如果说我们需要分离其他的代码,像一些依赖的代码,或者是css代码,也可以通过配置实现。

  1. 抽离依赖vender.js文件
1
2
3
4
5
6
7
new CommonsChunkPlugin({
name: 'vendors',
filename: 'vendors.js',
minChunks: function(module) {
return isExternal(module);
}
})

关于isExternal()函数,用了很简单的方式进行:

1
2
3
4
5
6
7
function isExternal(module) {
var userRequest = module.userRequest;
if (typeof userRequest !== 'string') {
return false;
}
return userRequest.indexOf('node_modules') >= 0; // 是否位于node_modules里
}
  1. 将样式从js中抽出,生成单独的.css样式文件。即把所以的css打包合并:
1
2
3
new ExtractTextPlugin('style.css', {
allChunks: true // 提取所有的chunk(默认只提取initial chunk,而上面CommonsChunkPlugin已经把部分抽离了)
})

这些大家下来可以配置,本骚年就不在项目这使用了。

创建左侧菜单


添加配置文件

这里我们为了方便拓展,使用配置的方式来自定义菜单,这样每次我们需要修改的时候只需要调整配置文件就好了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// sidebar.config.ts
export const menus = [{
icon: 'fa-home', // icon用于储存菜单对应的图标
text: '页面管理', // text用于储存该菜单显示名称
childMenus: [{
link: '/home/page-setting', // link用于设定该菜单跳转路由
text: '页面配置' // text用于储存该菜单显示名称
}, {
link: '/home/page-rebuild',
text: '页面重现'
}]
}, {
icon: 'fa-cubes',
text: '使用说明',
link: '/home/page-handbook'
}];

这里暂时限定我们最多为二级菜单,跟之前搭建管理项目的方式一致。

添加html文件

这里我们可以遍历配置文件生成菜单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div class="col-md-3 left_col menu_fixed">
<div class="left_col scroll-view">
<!-- 其他省略,重点在下面 -->
 
<!-- sidebar menu -->
<div class="main_menu_side hidden-print main_menu">
<div class="menu_section">
<!-- 其他省略,重点在下面 -->
<ul class="nav side-menu metismenu" id="sidebar-menu">
<li class="topper-menu" *ngFor="let menu of menus;" [ngClass]="menu.link && isActive(menu.link) ? 'active' : ''">
<a *ngIf="menu.link" [routerLink]="menu.link"><i class="fa" [ngClass]="menu.icon"></i> {{menu.text}}</a>
<a *ngIf="!menu.link" class="has-arrow"><i class="fa" [ngClass]="menu.icon"></i> {{menu.text}}</a>
<ul class="nav child_menu slide">
<li *ngFor="let childMenu of menu.childMenus;" class="slide-item" routerLinkActive="current-page">
<a [routerLink]="childMenu.link">{{ childMenu.text }}</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
<!-- /sidebar menu -->
</div>
</div>

这里可以看到,我们使用*ngFor来进行遍历,然后我们大致可以得到我们的component需要以下功能:

  • [routerLink]: 链接跳转
  • routerLinkActive: 路由激活时样式
  • isChildMenuActived: 判断该菜单下是否有子菜单的路由处于激活状态

这里我们需要注意的是:

  1. 使用angular自带的常用指令,像*ngForngClass等,需要在注册@NgModule时引入CommonModule
  2. 使用angular里面路由常用指令,像[routerLink]routerLinkActive等,需要在注册@NgModule时引入RouterModule
  3. 使用angular里面表单常用指令,像[(ngModel)]等,需要在注册@NgModule时引入FormModule

像我们的HomeModule

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { CommonModule } from '@angular/common';
 
import { HomeRoutes } from './home.routes';
import { HomeComponent } from './home.component';
import { SidebarComponent } from './sidebar/sidebar.component';
 
@NgModule({
declarations: [
HomeComponent,
SidebarComponent
],
imports: [
FormsModule,
CommonModule,
RouterModule.forChild(HomeRoutes)
],
providers: []
})
export class HomeModule { }

添加component

组件使用了简单的jQuey插件metisMenu,详细说明请参考文档,这里我们只需要知道调用$().metisMenu()的时候,若有<li class="active">则自动将该<li>设置为激活形式,此时我们在路由跳转结束的时候就可以获取对应激活路由然后初始化菜单状态了。

我们直接在代码中说明吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import {Component, ElementRef} from '@angular/core';
import {ActivatedRoute, Router, NavigationEnd} from '@angular/router';
import {menus} from './sidebar.config';
import 'rxjs/Rx';
 
@Component({
selector: 'home-sidebar',
templateUrl: './sidebar.component.html',
})
export class SidebarComponent {
menus: any[] = menus;
 
constructor(private route: ActivatedRoute, private router: Router, el: ElementRef) {
this.router.events.subscribe(event => {
// 判断路由结束
if (event instanceof NavigationEnd) {
const $menu = $(el.nativeElement).find('#sidebar-menu');
this.menus.forEach((menu, index) => {
if (this.isChildMenuActived(menu)) {
// 将被激活的路由对应的li添加“active”的class
$menu.find('li.topper-menu').eq(index).addClass('active');
}
});
// 初始化菜单状态
$menu.metisMenu();
}
});
}
 
// 判断路由是否激活状态
isActive(url: string): boolean {
return this.router.isActive(url, false);
}
 
// 判断菜单是否有子路由处于激活状态
isChildMenuActived(menu: any): boolean {
let hasOneActive = false;
if (menu.childMenus) {
// 遍历子路由看是否被激活
menu.childMenus.forEach(child => {
hasOneActive = hasOneActive || this.isActive(child.link);
});
}
return hasOneActive;
}
}

在Angular2-release版本里,一般路由的状态是通过事件监听获取的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 使用`ActivatedRoute`的API获取路由信息。
import { ActivatedRoute } from '@angular/router';
@Component({
... // 略
})
export class SidebarComponent {
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.route.params
.subscribe((params) => {
this.id = parseInt(params['id']); // 获取params
... // 其余代码
});
}
... // 其余代码
}

这里我们也可以使用filter()来过滤监听我们想要的事件:

1
2
// 监听导航事件变更完毕
router.events.filter(event => event instanceof NavigationEnd).subscribe(event => {});

更多有关路由的我们上节也说过,可以点击回顾《玩转Angular2(3)–启用路由和添加静态资源》

最终效果图:

结束语


这节主要讲了一些基础环境配置的调整,以及制作路由自动定位左侧菜单的过程,主要涉及的可能还是路由相关。
看菜单列表的内容,大家猜猜本骚年接下来想要做什么?就不告诉你,哈哈。
此处查看项目代码
此处查看页面效果

查看Github有更多内容噢:https://github.com/godbasin

[转]玩转Angular2(4)--制作左侧自动定位菜单的更多相关文章

  1. MVC4做网站后台:栏目管理3、删除栏目与左侧列表菜单

    一.左侧列表菜单 打开视图Menu.cshtml,增加部分见红框 在category中添加脚本 //栏目菜单加载完毕函数 function CategoryMenu_Ready() { $('#cat ...

  2. Ecshop 后台增加一个左侧列表菜单menu菜单的方法

    Ecshop 后台增加一个左侧列表菜单menu菜单需要修改三个文件:/admin/includes/inc_menu.php/admin/includes/inc_priv.php/languages ...

  3. 后台增加一个左侧列表菜单menu菜单的方法

    Ecshop 后台增加一个左侧列表菜单menu菜单需要修改三个文件:/admin/includes/inc_menu.php/admin/includes/inc_priv.php/languages ...

  4. jQuery+Superfish制作下拉菜单

    superfish制作下拉菜单真的很方便而好很好用,而且还可以通过Superfish提供的参数来控制下拉菜单的不同效果,而且他没有层级限制,换句话说可以通过Superfish来写你想要的层级菜单. 官 ...

  5. jquery仿天猫商城左侧导航菜单

    之前看到有博友写了一个仿天猫商城左侧导航菜单,可惜不提供免费下载,也没有代码.以前自己也写过类似的效果,只是都是一小块一小块的,现在重新拼凑.我将一步一步的实现拼凑过程,希望对你有所帮助. Demo在 ...

  6. 制作下拉菜单(PopupList)

    怎样判断是否应当使用下拉菜单 下拉菜单,就是将一系列的选项隐藏,通过单击某一个控件将会弹出一个包含这些选项的列表,在其中选择想要的选项.这样做不但可以节省屏幕空间,也可以让用户在进行选择时更加方便快捷 ...

  7. 使用 EasyUI 创建左侧导航菜单

    使用 JQuery EasyUI 创建左侧导航菜单,菜单的数据由后台服务提供. 效果图 HTML 元素 <div id="menuAccordion"></div ...

  8. 【转】Ecshop 后台增加一个左侧列表菜单menu菜单的方法

    cshop 后台增加一个左侧列表菜单menu菜单需要修改三个文件:/admin/includes/inc_menu.php/admin/includes/inc_priv.php/languages/ ...

  9. wemall doraemon中Android app商城系统解决左侧抽屉菜单和viewpager不能兼容问题

    完美解决左侧抽屉菜单和viewpager不能兼容左右滑动的问题,可进行参考. WeMall-Client/res/layout/wemall_main_ui.xml </RadioGroup&g ...

随机推荐

  1. 利用openxml在Excel中插入图表

    using System.Collections.Generic; using System.Linq; using DOD = DocumentFormat.OpenXml.Drawing; usi ...

  2. Splinter常用API介绍(转)

    # Example from splinter import Browser with Browser() as browser: # Visit URL url = "http://www ...

  3. django查询数据库无法过滤月份的解决

    我试过,当settings里的:USE_TZ = False时也可以查询,但是数据库里的时间就会显示错的 解决方法是可以再终端输入 mysql_tzinfo_to_sql /usr/share/zon ...

  4. AbstractRoutingDataSource 实现动态切换数据源

    扩展AbstractRoutingDataSource类 package com.datasource.test.util.database; import org.springframework.j ...

  5. Gephi安装过程中出现错误:can’t find java 1.8 or higher

    Gephi具体的安装过程我就不多说了,一直点击下一步就OK了,我想说的是出现如下图这种或者类似的错误怎么解决. 在百度的过程中发现很多的博文等等出现这个错误的解决方法都是安装对应版本的JDK啊,配置对 ...

  6. 新鲜出炉的一套Java面试题

    作者:孤独烟 由于近期是互联网寒冬,然而烟哥的好友还是顶着重重压力出去面试,最终斩获无数offer.在烟哥的沟通下,终于套得其中一套题目,故在此分享! 公司:国内三巨头其中的一家!面试时间约在1月份左 ...

  7. Javascript高级编程学习笔记(78)—— 表单(6)HTML约束验证API

    自动切换焦点 使用JS可以极大地提升表单的易用性 其中最常用的一种就是当用户填写完当前字段后焦点自动切换到下一个字段 以下方的HTML代码为例: <input type="text&q ...

  8. Pycharm Debug调试心得

    1.操作步骤: 1-1.添加断点:直接在标记处点击鼠标左键即可.(删除断点只需再点击断点处即可) 1-2.Debug下运行代码 1-3.按照所需调试进行代码调试.Debug的调试方式如下所示: 分别为 ...

  9. Python学习笔记【第五篇】:基础函数

    一.函数:函数定义关键字def  后跟函数名称 def 函数名(参数):             ...     函数体     ...     返回值 案例: # 定义函数 def say_hei( ...

  10. Kali学习笔记30:身份认证与命令执行漏洞

    文章的格式也许不是很好看,也没有什么合理的顺序 完全是想到什么写一些什么,但各个方面都涵盖到了 能耐下心看的朋友欢迎一起学习,大牛和杠精们请绕道 实验环境: Kali机器:192.168.163.13 ...