无法在Angular中使用Bootstrap 4切换导航栏

35

为什么在使用Bootstrap 4和Angular 4时,当屏幕大小调整到移动设备尺寸时,无法切换导航栏?我已经将Bootstrap相关的脚本和样式文件添加到了Angular CLI中,并引入了相应的Node模块。代码中是否有遗漏之处?请您检查一下以下代码。是否有问题?请帮忙解决。

<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
  <a class="navbar-brand" href="#">Dashboard</a>
  <button class="navbar-toggler d-lg-none" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>

  <div class="collapse navbar-collapse" id="navbarsExampleDefault">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Settings</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Profile</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Help</a>
      </li>
    </ul>
    <form class="form-inline mt-2 mt-md-0">
      <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
      <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
    </form>
  </div>
</nav>

.angular-cli.json

.angular-cli.json

 "styles": [
    "styles.css",
     "../node_modules/bootstrap/dist/css/bootstrap.min.css"
  ],
  "scripts": [

    "../node_modules/popper.js/dist/umd/popper.min.js",
    "../node_modules/jquery/dist/jquery.min.js",
    "../node_modules/bootstrap/dist/js/bootstrap.min.js"

  ],
{"package.json"}
      {
  "name": "dashboard2",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^4.0.0",
    "@angular/common": "^4.0.0",
    "@angular/compiler": "^4.0.0",
    "@angular/core": "^4.0.0",
    "@angular/forms": "^4.0.0",
    "@angular/http": "^4.0.0",
    "@angular/platform-browser": "^4.0.0",
    "@angular/platform-browser-dynamic": "^4.0.0",
    "@angular/router": "^4.0.0",
    "bootstrap": "^4.0.0-beta",
    "core-js": "^2.4.1",
    "jquery": "^3.2.1",
    "popper.js": "^1.12.5",
    "rxjs": "^5.4.1",
    "zone.js": "^0.8.14"
  },
  "devDependencies": {
    "@angular/cli": "1.2.7",
    "@angular/compiler-cli": "^4.0.0",
    "@angular/language-service": "^4.0.0",
    "@types/jasmine": "~2.5.53",
    "@types/jasminewd2": "~2.0.2",
    "@types/node": "~6.0.60",
    "codelyzer": "~3.0.1",
    "jasmine-core": "~2.6.2",
    "jasmine-spec-reporter": "~4.1.0",
    "karma": "~1.7.0",
    "karma-chrome-launcher": "~2.1.1",
    "karma-cli": "~1.0.1",
    "karma-coverage-istanbul-reporter": "^1.2.1",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.1.2",
    "ts-node": "~3.0.4",
    "tslint": "~5.3.2",
    "typescript": "~2.3.3"
  }
}

你是如何在你的Angular应用程序中包含依赖项的? - Jade Cowan
@cwanjt。你能再检查一下我的angular-cli吗? - Joseph
11个回答

55

看起来你可能正在查看Bootstrap的这个示例。我也是,并且遇到了相同的问题。

问题是这不是一个Angular示例,所以它不会起作用。要使其正常工作,你需要使用(click)事件和一个变量。所以将你的模板更改为:

<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
  <a class="navbar-brand" href="#">Dashboard</a>
  <button class="navbar-toggler d-lg-none" type="button" (click)="isCollapsed = !isCollapsed" [attr.aria-expanded]="!isCollapsed" aria-controls="navbarsExampleDefault" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>

  <div class="collapse navbar-collapse" id="navbarsExampleDefault" [ngbCollapse]="isCollapsed">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Settings</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Profile</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Help</a>
      </li>
    </ul>
    <form class="form-inline mt-2 mt-md-0">
      <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
      <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
    </form>
  </div>
</nav>

如果您希望默认情况下折叠菜单,则应在类中将变量设置为 true(在组件的 .ts 文件中) public isCollapsed = true;

这是一个 plunker

还有一件事;如果您的导航位于共享模块中,则必须在此处记得导入 NgbCollapseModule。

也就是说,shared.module.ts 应该是:

import { NgModule } from '@angular/core';
import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap';
/*Plus all your other modules*/

@NgModule({
  imports: [NgbCollapseModule],
  declarations: [],
  exports: []
})
export class SharedModule {}

4
是的。这正是我一直在寻找的,尽管我试图避免使用ng-bootstrap,但似乎这个解决方案比引入popper和jQuery更好。 - mutantkeyboard
1
适用于 Bootstrap 4 和 Angular 5。我创建了一个名为 isCollapsed 的成员布尔变量,并在 ngOnInit() 中将其设置为 true,以便默认为折叠状态。 - bbarke
这实际上解决了我的问题。这应该是正确的答案。您还成功摆脱了像jquery或popper.js这样的JS库,这在纯Angular应用程序中不需要。 - CesarD
这确实非常非常有帮助。 - Connie H.
这真的很有帮助! - Dialvive

16

@Joseph,看起来你还没有安装导航栏切换所需的Bootstrap依赖(以及Bootstrap本身)。

如果你打开终端或命令行,并导航到包含你的package.json文件的目录,运行以下命令:

npm install --save jquery
npm install --save popper.js
npm install --save bootstrap@4.0.0-beta
这些命令将为您的项目安装必要的依赖项。它们在执行时相当明确,但如果您需要了解它们在做什么或如何工作的刷新,请参阅此处npm install文档。
安装完成后,您需要确保在您的.angular-cli.json文件中包含它们,这样您的Angular应用程序才能使用它们。

我只安装了npm install --save bootstrap@4.0.0-beta - Joseph
它起作用了吗?如果是的话,太好了,您仍然需要在项目中使用另外两个库,因为Bootstrap依赖于它们。您还需要将它们添加到.angular-cli.json文件中。 - Jade Cowan
在.angular-cli.json脚本中,添加bootstrap.min.js的路径。 - Jade Cowan
4
这对我来说行不通,因为我没有安装popper.js。感谢cwanjt的建议。请注意,我的安装命令是“npm install --save popper.js”,而不是“popperjs”。 - Matthew Meppiel
根据之前的评论,答案应该被编辑以显示'popper.js'而不是'popperjs'。 - obaylis
我重新安装了它们,但仍然有问题。属性data-toggle在此处不允许属性data-target在此处不允许属性aria-controls在此处不允许属性aria-expanded在此处不允许属性aria-label在此处不允许属性placeholder在此处不允许 - Davoud Badamchi

12

如所述,您需要一个属性(例如isShown),其初始值为false

然后使用。
[ngClass]="{ 'show': isShown }" 

这里

<div class="collapse navbar-collapse" [ngClass]="{ 'show': isShown }" id="navbarSupportedContent" >

点击链接时会触发点击事件,确保当链接被点击后菜单会重新折叠

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {


  isShown:boolean = false;
  constructor() { }

  ngOnInit() {
  }
  
}
<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <a class="navbar-brand" routerLink="/"><img width="20%" src="/assets/logo.svg"></a>
  <button #navbarToggler class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" (click)="isShown = !isShown" [attr.aria-expanded]="isShown"  aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>

  <div class="collapse navbar-collapse" [ngClass]="{ 'show': isShown }" id="navbarSupportedContent" >
    <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
        <a class="nav-link" (click)="isShown = false" routerLink="/">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" (click)="isShown = false" routerLink="/contact">Contact</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" (click)="isShown = false" routerLink="/imprint">Imprint</a>
      </li>
    </ul>
  </div>
</nav>


非常有用,点赞...不需要额外的库 :) ...唯一缺少的是“动画” ;( - WasiF
属性 data-toggle 在此处不允许! - Davoud Badamchi

12

这个示例提供了汉堡图标的切换功能(换句话说,如果它在响应模式下运行,则是整个导航栏),以及下拉菜单项的切换。

它使用ng-bootstrap,但我更愿意使用本机Bootstrap导航栏支持,而不是做这些“hack”!?

显然,其他人也遇到了同样的问题:https://github.com/twbs/bootstrap/issues/24227

<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <a class="navbar-brand" href="#">ApplicationName</a>
  <button class="navbar-toggler" type="button" (click)="toggleNavbar = !toggleNavbar">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" [ngbCollapse]="!toggleNavbar">
    <ul class="navbar-nav">
      <li class="nav-item active">
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Features</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Pricing</a>
      </li>
      <li ngbDropdown class="nav-item">
        <a class="nav-link" id="navbarDropdownMenuLink" ngbDropdownToggle aria-haspopup="true" aria-expanded="false">
          Dropdown link
        </a>
        <div ngbDropdownMenu aria-labelledby="navbarDropdownMenuLink">
          <a class="dropdown-item" href="#">Action</a>
          <a class="dropdown-item" href="#">Another action</a>
          <a class="dropdown-item" href="#">Something else here</a>
        </div>
      </li>
    </ul>
  </div>
</nav>

谢谢分享这个。在Angular应用中,这应该是首选的方式!太棒了! - flashjpr

4
为了使Angular中的切换工作,你只需要做4件事:
  1. 安装ng-bootstrap
  2. 将切换点击监听器添加到导航栏开关(click)="isCollapsed = !isCollapsed"
  3. 使用属性绑定来设置aria-expanded,[attr.aria-expanded]="!isCollapsed",这样当您单击时属性就会更改(无论是true还是false)
  4. 以相同的方式将属性绑定到ngCollapse [ngbCollapse]="isCollapsed"

NB:不建议使用JQuery

使用ng-bootstrap而不使用JQuery折叠导航栏


4

它完全正常工作,请试试这个。

<nav class="navbar navbar-expand-md navbar-light">
  <a>Home</a>
  <button
    class="navbar-toggler d-lg-none"
    type="button"
    data-toggle="collapse"
    (click)="isShown=!isShown"
  >
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" [ngClass]="{ 'show': isShown }">
    <ul class="navbar-nav">
      <li class="nav-item active">
        <a class="nav-link" href="#">About</a>
      </li>
    </ul>
  </div>
</nav>

对应的 TypeScript 文件是:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  // title = 'WebApp';
  isShown = false;
}

1
这对我很有帮助!!!
现在我们可以使用Bootstrap 4,在Angular 4中调整大小以适应移动屏幕时切换导航栏。
尝试这段代码。

app.component.html

<nav class="navbar navbar-expand-lg justify-content-between">
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation" id="navButton">
    <i class="fa fa-bars"></i>
  </button>
  <div class="row">
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto">
        <li class="nav-item" *ngFor="let menu of mainmenu, let i = index">
          <a class="nav-link" (click)="findIndex(i)" routerLink="/{{menu.href}}">{{menu.icon}} {{menu.text}}</a>
          <ng-container *ngIf="menu.children && menu.children.length > 0">
            <span class="d-block d-sm-none"><i class="fa fa-chevron-down" aria-hidden="true"></i></span>
          </ng-container>
          <ul class="sub_menu dropdown-menu" [ngClass]="{active : isActive(i)}" *ngIf="menu.children && menu.children.length > 0">
            <li *ngFor="let sub_menu of menu.children"><a class="nav-link" routerLink="/{{sub_menu.href}}" (click)="closeMenu()"><img src="{{sub_menu.icon}}" class="nav-img" /> {{sub_menu.text}}</a></li>
          </ul>
        </li>
      </ul>
    </div>
  </div>
</nav>

app.component.ts

closeMenu() {
    var isMobile = /iPhone|iPad|iPod|BlackBerry|Opera Mini|IEMobile|Android/i.test(navigator.userAgent);
    if (isMobile) {
      document.getElementById('navButton').click();
   }
}

1
如果有人想要动态切换导航栏,可以使用 ViewChild 和模板变量获取按钮的引用,然后触发点击事件。 HTML
<button #menu class="navbar-toggler d-lg-none" type="button"
    data-toggle="collapse" data-target="#navbarsExampleDefault"
    aria-controls="navbarsExampleDefault" aria-expanded="false"
    aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
</button>

TS

import { ViewChild, ElementRef } from '@angular/core';

@ViewChild('menu') menu: ElementRef;

toggleMenu() {
    this.menu.nativeElement.click();
}

closeMenu() {
    const isMenuOpen = this.menu.nativeElement.getAttribute('aria-expanded') === 'true';
    if (isMenuOpen) {
        this.menu.nativeElement.click();
    }
}

我知道这并不是对这个问题的答案,但它与之非常相关,可能会有所帮助。

0

我不知道这是否仍然相关,但当我遇到这个问题时,有助于我的是停止实时服务器,重新编译应用程序,然后使用 ng serve 重新启动它。有时候,当你在运行服务器的时候安装依赖项,即使你插入它们,angular.json 也无法看到这些依赖项。也许对未来的用户有帮助。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接