深入浅析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

tabset

总结

以上所述是小编给大家介绍的深入浅析ng-bootstrap 组件集中 tabset 组件的实现分析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

(0)

相关推荐

  • Angular2中Bootstrap界面库ng-bootstrap详解

    准备 Angular 2 环境 ng-bootstrap 是基于 Angular 2 的, 因此需要先准备 Angular 2 的环境. 使用 ng-bootstrap 下载 ng-bootstrap ng-bootstrap 使用 bootstrap 4.0 alpha2 , 因此需要先下载 bootstrap , 推荐使用 npm 包的形式: npm install bootstrap@4.0.0-alpha.2 --save 接着下载 ng-bootstrap , 同样使用 npm 包的形

  • 详解在Angular项目中添加插件ng-bootstrap

    npm 安装 ng-bootstrap 模块 npm install @ng-bootstrap/ng-bootstrap --save 在 Angular 项目配置 app.module.ts 添加 import { NgbModule } from "@ng-bootstrap/ng-bootstrap"; imports: [ /** * ngx-bootstrap */ NgbModule.forRoot() ], 添加 bootstrap.min.css 样式 在 asset

  • 深入浅析ng-bootstrap 组件集中 tabset 组件的实现分析

    ng-bootstrap: tabset 本文介绍了 ng-bootstrap 项目中,tabset 的实现分析. 使用方式 <ngb-tabset> 作为容器元素,其中的每个页签以一个 <ngb-tab> 元素定义,在 <ngb-tabset> 中包含若干个 <ngb-tab> 子元素. 在 <ngb-tab> 元素中,使用 <ng-template> 模板来定义内容,内容分为两种:标题和内容. 标题使用 [ngbTabTitle]

  • 浅析Bootstrap组件之面板组件

    Bootstrap,来自 Twitter,是目前最受欢迎的前端框架.Bootstrap 是基于 HTML.CSS.JAVASCRIPT 的,它简洁灵活,使得 Web 开发更加快捷. 面板组件主要作用是用来处理一些其他组件无法完成的功能,在不同的版本中具有不同的源码: LESS:panels.less SASS:_panels.scss 基础面板非常简单,就是一个div容器中运用了类.panel的样式,产生一个具有边框的文本显示块,由于panel不控制主题颜色,所以在.panel基础上增加一个控制

  • 基于Bootstrap的标签页组件及bootstrap-tab使用说明

    bootstrap-tab bootstrap-tab组件是对原生的bootstrap-tab组件的封装,方便开发者更方便地使用,主要包含以下功能: tab页初始化 关闭tab页 新增tab 显示tab页 获取tab页ID 使用 Step1 :引入样式 <link rel="stylesheet" href="bootstrap/css/bootstrap.min.css" rel="external nofollow" > <

  • Bootstrap创建可折叠的组件

    本文将学习如何通过Bootstrap创建可折叠的组件,具体内容如下 什么是必需的 您必须引用 jquery.js 和 bootstrap-collapse.js - 这两个 JavaScript 文件都位于 docs/assets/js 文件夹内. 您可以在不编写大量 JavaScript 或者不调用 JavaScript 的情况下创建可折叠的组件. 实例 第一个实例演示如何不调用 JavaScript 创建可折叠的组件. <!DOCTYPE html> <html> <he

  • Bootstrap文件上传组件之bootstrap fileinput

    前言:之前的三篇介绍了下bootstrap的一些常用组件,发现博主对这种扁平化的风格有点着迷了.前两天做一个excel导入的功能,前端使用原始的input type='file'这种标签,效果不忍直视,于是博主下定决心要找一个好看的上传组件换掉它.既然bootstrap开源,那么社区肯定有很多关于它的组件,肯定也有这种常见的上传组件吧.经过一番查找,功夫不负有心人,还是被博主找到了这个组件:bootstrap fileinput.在此记录下,就算做个学习笔记,也给需要使用的朋友提供点方便. Bo

  • bootstrap组件之导航组件使用方法

    在上篇文章给大家介绍了bootstrap组件之按钮式下拉菜单小结,下面通过本文给大家介绍bootstrap导航组件的使用方法,一起看看吧! Bootstrap 中的导航组件都依赖同一个 .nav 类和ul,状态类也是共用的.改变修饰类可以改变样式. 1.标签页 .nav-tabs <ul class="nav nav-tabs" role="tablist"> <li role="presentation" class=&quo

  • BootStrap实现树形目录组件代码详解

    需求描述 产品添加页面,需要选择车型.在bootStrap的modal上弹出子modal来使用. 车型一共有4级目录.要使用目录树. 然后分活动和商品两种,需要能够通过不通参数来调用该组件. 车型品牌要使用字母导航. 技术实现 数据都是后端传json过来,我们ajax获取然后操作. 由于车型总数据有几万条以上,不可能一次性请求过来.这里我们使用异步的方式,每点击一次目录节点,加载它的下一级. 这里我们用两个参数来控制活动和商品的不同加载._showPrice和opened 后端传过来的第一级数据

  • JS组件中bootstrap multiselect两大组件较量

    两个这种组件,大体样式和功能基本相同,本文就来带领大家看看这两个组件的用法. 一.组件说明以及API 1.第一个组件--multiple-select.这个组件风格简单.文档全.功能强大.但是觉得它选中的效果不太好.关于它的效果展示,我们放在后面. 2.第二个组件--bootstrap-multiselect.这个组件风格和第一个非常相似,文档也挺全面. 二.Multiple-select组件 1.组件说明 这个组件需要的浏览器支持如下: IE 7+ Chrome 8+ Firefox 10+

  • 基于BootStrap的文本编辑器组件Summernote

    Summernote是一个基于jquery的bootstrap超级简单WYSIWYG在线编辑器.Summernote非常的轻量级,大小只有30KB,支持Safari,Chrome,Firefox.Opera.Internet Explorer 9 +(IE8支持即将到来). 特点: 世界上最好的WYSIWYG在线编辑器 极易安装 开源 自定义初化选项 支持快捷键 适用于各种后端程序言语 Summernote官网地址 :https://summernote.org/ 这是官网的一个例子: <!DO

  • 浅析微信小程序自定义日历组件及flex布局最后一行对齐问题

    最近为我开源的小项目:微信小程序扩展自定义组件库(点击去GitHub) 增加了一个新组件 -- 日历组件. 效果演示: 在编写过程中,因为大家都知道,日历组件是有固定行数和每一行的固定列数的(即使当前方块内没有值),所以结合小程序"数据优先"的特点,最合适的布局方式一定是flex了! 先说一下大致思路(布局上),笔者将整个组件分为两部分:分别是 头部的当前日期(年月)显示,以及左右两侧的切换按钮 当前切换月份的日期显示 头部的布局自不多说:一个 display:flex; 加上 ali

随机推荐