ng-bootstrap 组件集中 tabset 组件的实现分析
ng-bootstrap: tabset
本文介绍了 ng-bootstrap 项目中,tabset 的实现分析。
使用方式
<ngb-tabset>
作为容器元素,其中的每个页签以一个 <ngb-tab>
元素定义,在 <ngb-tabset>
中包含若干个 <ngb-tab>
子元素。
在 <ngb-tab>
元素中,使用 <ng-template>
模板来定义内容,内容分为两种:标题和内容。
标题使用 [ngbTabTitle]
指令来声明,或者在 <ngb-tab>
元素上使用 title
属性声明。
内容使用 [ngbTabContent]
指令声明。
<ngb-tabset>
<ngb-tab title="Simple">
<ng-template ngbTabContent>
<p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth
master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh
dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum
iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p>
</ng-template>
</ngb-tab>
<ngb-tab>
<ng-template ngbTabTitle><b>Fancy</b> title</ng-template>
<ng-template ngbTabContent>Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid.
<p>Exercitation +1 labore velit, blog sartorial PBR leggings next level wes anderson artisan four loko farm-to-table
craft beer twee. Qui photo booth letterpress, commodo enim craft beer mlkshk aliquip jean shorts ullamco ad vinyl
cillum PBR. Homo nostrud organic, assumenda labore aesthetic magna delectus mollit. Keytar helvetica VHS salvia
yr, vero magna velit sapiente labore stumptown. Vegan fanny pack odio cillum wes anderson 8-bit, sustainable jean
shorts beard ut DIY ethical culpa terry richardson biodiesel. Art party scenester stumptown, tumblr butcher vero
sint qui sapiente accusamus tattooed echo park.</p>
</ng-template>
</ngb-tab>
<ngb-tab title="Disabled" [disabled]="true">
<ng-template ngbTabContent>
<p>Sed commodo, leo at suscipit dictum, quam est porttitor sapien, eget sodales nibh elit id diam. Nulla facilisi. Donec egestas ligula vitae odio interdum aliquet. Duis lectus turpis, luctus eget tincidunt eu, congue et odio. Duis pharetra et nisl at faucibus. Quisque luctus pulvinar arcu, et molestie lectus ultrices et. Sed diam urna, egestas ut ipsum vel, volutpat volutpat neque. Praesent fringilla tortor arcu. Vivamus faucibus nisl enim, nec tristique ipsum euismod facilisis. Morbi ut bibendum est, eu tincidunt odio. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris aliquet odio ac lorem aliquet ultricies in eget neque. Phasellus nec tortor vel tellus pulvinar feugiat.</p>
</ng-template>
</ngb-tab>
</ngb-tabset>
可以看到,外层元素是 <ngb-tabset>
。
每个 tab 使用元素 <ngb-tab>
定义,tab 的内容使用 <ng-template>
模板定义, tab 中的内容分为两个部分:标题和内容。
下面是使用模板的标题
<ng-template ngbTabTitle><b>Fancy</b> title</ng-template>
标题也可以在 ngb-tab
上使用 [title]
属性定义。例如:
<ngb-tab title="Disabled" [disabled]="true">
内容部分定义,这里使用了指令 [ngbTabContent]
便于识别。
<ng-template ngbTabContent>
<p>Sed commodo, leo at suscipit dictum, quam est porttitor sapien, eget sodales nibh elit id diam.
</p>
</ng-template>
TabSet 组件定义
从前面的使用可以看出,所有 tab 的定义都是 ngb-tabset
元素的内容,它们在使用时定义,而不是在 ngb-tabse
自己的模板中定义。
所以找到它们需要使用 ContentChildren 来找到。
@ContentChildren(NgbTab) tabs: QueryList<NgbTab>;
不使用 ContentChild 的原因是它没有提供 descendants
的支持。
在 bootstrap 中,每个页签 实际上渲染成两个部分,一个标题的列表,和当前显示的内容。
标题列表使用一个 ul
来处理。其中使用循环来将所有的标题显示出来。
而 titleTpl
是由模板定义的,所以,使用了 [ngTemplateOutlet]
来渲染出来。
<ul [class]="'nav nav-' + type + (orientation == 'horizontal'? ' ' + justifyClass : ' flex-column')" role="tablist">
<li class="nav-item" *ngFor="let tab of tabs">
<a [id]="tab.id" class="nav-link"
[class.active]="tab.id === activeId"
[class.disabled]="tab.disabled"
href (click)="select(tab.id); $event.preventDefault()"
role="tab"
[attr.tabindex]="(tab.disabled ? '-1': undefined)"
[attr.aria-controls]="(!destroyOnHide || tab.id === activeId ? tab.id + '-panel' : null)"
[attr.aria-selected]="tab.id === activeId" [attr.aria-disabled]="tab.disabled">
{{tab.title}}<ng-template [ngTemplateOutlet]="tab.titleTpl?.templateRef"></ng-template>
</a>
</li>
</ul>
title 部分并列使用了两种来源
{{tab.title}}<ng-template [ngTemplateOutlet]="tab.titleTpl?.templateRef"></ng-template>
内容部分,由于具体内容也是使用模板定义出来,所以这里也是使用 [ngTemplateOutlet]
渲染出来。
<div class="tab-content">
<ng-template ngFor let-tab [ngForOf]="tabs">
<div
class="tab-pane {{tab.id === activeId ? 'active' : null}}"
*ngIf="!destroyOnHide || tab.id === activeId"
role="tabpanel"
[attr.aria-labelledby]="tab.id" id="{{tab.id}}-panel">
<ng-template [ngTemplateOutlet]="tab.contentTpl?.templateRef"></ng-template>
</div>
</ng-template>
</div>
投影内容需要在 Content
类型的事件中处理。
ngAfterContentChecked() {
// auto-correct activeId that might have been set incorrectly as input
let activeTab = this._getTabById(this.activeId);
this.activeId =
activeTab ? activeTab.id : (this.tabs.length ? this.tabs.first.id : null);
}
两个指令定义
指令的定义非常简单,就是获取模板的引用,以便后继使用。
可以看到属性名称为 templateRef
@Directive({selector: 'ng-template[ngbTabTitle]'})
export class NgbTabTitle {
constructor(public templateRef: TemplateRef<any>) {}
}
这是 [ngbTabContent]
的定义,与上面相同,依然是定义了属性 templateRef
。
@Directive({selector: 'ng-template[ngbTabContent]'})
export class NgbTabContent {
constructor(public templateRef: TemplateRef<any>) {}
}
Tab 定义
元素型的指令,所以连模板都没有了。
@Directive({selector: 'ngb-tab'})
内容是投影进来的。
由于在 tab
中使用了模板,并且使用指令来标识出来,它们定义在组件的模板之内,所以这里使用了 ContentChildren
来识别。
@ContentChildren(NgbTabTitle, {descendants: false}) titleTpls: QueryList<NgbTabTitle>;
@ContentChildren(NgbTabContent, {descendants: false}) contentTpls: QueryList<NgbTabContent>
以后就可以使用 titleTpls
和 contentTpls
来使用模板了。
由于是内容,需要在 content
的事件中处理,实际上,在每个页签中,我们只有一个标题和一个内容的声明。
ngAfterContentChecked() {
// We are using @ContentChildren instead of @ContentChild as in the Angular version being used
// only @ContentChildren allows us to specify the {descendants: false} option.
// Without {descendants: false} we are hitting bugs described in:
// https://github.com/ng-bootstrap/ng-bootstrap/issues/2240
this.titleTpl = this.titleTpls.first;
this.contentTpl = this.contentTpls.first;
}
See also
ng-bootstrap 组件集中 tabset 组件的实现分析的更多相关文章
- Bootstrap 中的 Typeahead 组件 -- AutoComplete
Bootstrap 中的 Typeahead 组件就是通常所说的自动完成 AutoComplete,功能很强大,但是,使用上并不太方便.这里我们将介绍一下这个组件的使用. 第一,简单使用 首先,最简单 ...
- JS组件系列——表格组件神器:bootstrap table
前言:之前一直在忙着各种什么效果,殊不知最基础的Bootstrap Table用法都没有涉及,罪过,罪过.今天补起来吧.上午博主由零开始自己从头到尾使用了一遍Bootstrap Table ,遇到不少 ...
- JS组件系列——表格组件神器:bootstrap table(二:父子表和行列调序)
前言:上篇 JS组件系列——表格组件神器:bootstrap table 简单介绍了下Bootstrap Table的基础用法,没想到讨论还挺热烈的.有园友在评论中提到了父子表的用法,今天就结合Boo ...
- JS组件系列——表格组件神器:bootstrap table(三:终结篇,最后的干货福利)
前言:前面介绍了两篇关于bootstrap table的基础用法,这章我们继续来看看它比较常用的一些功能,来个终结篇吧,毛爷爷告诉我们做事要有始有终~~bootstrap table这东西要想所有功能 ...
- bootstrap学习之二-组件
一.bootstrap字体图标 以span的形式出现,通常可以用于一个button或者其他元素的内文本, <span class="glyphicon glyphicon-sort-b ...
- Bootstrap中的 Typeahead 组件
Bootstrap 中的 Typeahead 组件其实就是嵌入到其中的typeahead.js插件,可以完成输入框的自动匹配功能,在通过一些人工的调整基本可以胜任所有的匹配功能和场景,下面介绍下简单的 ...
- bootstrap中的dropdown组件扩展hover事件
bootstrap的下拉组件,需要点击click时,方可展示下拉列表.因此对于喜欢简单少操作的大家来说,点击一下多少带来不便,因此,引入hover监听,鼠标经过自动展示下拉框.其实在bootstrap ...
- [转]JS组件系列——表格组件神器:bootstrap table
原文地址:https://www.cnblogs.com/landeanfen/p/4976838.html 前言:之前一直在忙着各种什么效果,殊不知最基础的Bootstrap Table用法都没有涉 ...
- 基于 bootstrap 的 vue 分页组件
申手党点这里下载示例 基于 bootstrap 的 vue 分页组件,我想会有那么一部分同学,在使用Vue的时候不使用单文件组件,因为不架设 NodeJS 服务端.那么网上流传的 *.vue 的各种分 ...
随机推荐
- C、C++笔记
2017年6月 阅读书籍<C和指针> #if 0 #endif 比注释掉代码好.(<C和指针>2017.06.07) 全局变量和全局静态变量的区别 1)全局变量是不显式用sta ...
- 【Windows10 IoT开发系列】开发人员模式设置
原文:[Windows10 IoT开发系列]开发人员模式设置 声明:本文转自微软Windows 开发人员中心(https://msdn.microsoft.com/library/windows/ ...
- Vm安装
说明:都是默认安装,并不需要繁琐设置,所以没有文字说明
- Qt编程中QDiaog的ESC建
最近使用QDialog时,按了下Esc键,导致QDialog被关闭,而后续的数据处理出现了问题.原来在QDialog中按下Esc键会默认调用reject()方法而不是closeEvent(QClose ...
- Qt4.7.4下单独编译QtWebkit
最近编译出了Qt4.7.4的嵌入式版本,但没有编译QtWebkit库.在编译一个使用Webkit的工程时出错,而根据工程的需要,要单独编译QtWebkit库. 由于不想再次编译整个的Qt库,于是 ...
- LINUX下QT FOR ARM开发环境搭建过程 (使用qt-x11-opensource-src-4.5.2.tar.gz进行编译)
在PC上,我们需要得到两个版本的Qt,分别是:Qt-4.5.2和QtEmbedded-4.5.2-arm.前者包括了Qt Designer等基本工具,用于在PC上对程序的开发调试,使我们能确保程序放到 ...
- SQL server 2008 防火墙设置
zh以前应为有特殊需求,需要在副武器外连接数据库,需要打开TCPIP服务. 但是因为有防火墙,经常连接不成功. 根据网上的资料总结,写了一个小的bat,来解决这个问题: @echo ========= ...
- 统计插件,Highcharts,以及modelformset
一.modelfromset组件 1.作用:用于批量处理多个表单 form表单对应的组件是formset Modelform对应的组件是modelformset 2.引入 From django.fo ...
- Nginx多种负载均衡策略搭建
背景介绍 上篇介绍了利用Nginx反向代理实现负载均衡,本文详细讲述Nginx下的几种负载均衡策略. 轮询 轮询,顾名思义,就是轮流请求,基于上篇文章的介绍,我们将负载均衡策略聚焦于default.c ...
- Hadoop —— 单机环境搭建
一.前置条件 Hadoop的运行依赖JDK,需要预先安装,安装步骤见: Linux下JDK的安装 二.配置免密登录 Hadoop组件之间需要基于SSH进行通讯. 2.1 配置映射 配置ip地址和主机名 ...