You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 14实现Bootstrap Offcanvas中登录/注册组件显隐切换

实现步骤

1. 重构Navbar组件,统一Offcanvas容器

把登录/注册的Offcanvas合并成一个,放在Navbar组件中,通过状态变量控制内部显示的表单:

navbar.component.html

<nav class="navbar">
  <div class="container-fluid">
    <div class="d-flex">
      <a href="#" class="nav-link" data-bs-toggle="offcanvas" data-bs-target="#authOffcanvas" aria-controls="authOffcanvas">Log in</a>
    </div>
  </div>
</nav>

<!-- 统一的认证Offcanvas容器 -->
<div class="offcanvas offcanvas-end" id="authOffcanvas" tabindex="-1" aria-labelledby="authOffcanvasLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="authOffcanvasLabel">
      {{ isLoginActive ? 'Log In' : 'Register' }}
    </h5>
    <button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
  </div>
  <div class="offcanvas-body">
    <!-- 根据状态切换显示登录/注册组件 -->
    <app-login *ngIf="isLoginActive" (switchToRegister)="toggleAuthForm(false)"></app-login>
    <app-register *ngIf="!isLoginActive" (switchToLogin)="toggleAuthForm(true)"></app-register>
  </div>
</div>

navbar.component.ts

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

@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.css']
})
export class NavbarComponent {
  isLoginActive = true;

  toggleAuthForm(showLogin: boolean) {
    this.isLoginActive = showLogin;
    // 确保切换表单时Offcanvas保持打开状态
    const offcanvasElement = document.getElementById('authOffcanvas');
    if (offcanvasElement) {
      const offcanvasInstance = Offcanvas.getInstance(offcanvasElement);
      if (offcanvasInstance && !offcanvasInstance._isShown) {
        offcanvasInstance.show();
      }
    }
  }
}

2. 修改Login组件,移除独立Offcanvas并添加切换事件

去掉组件自身的Offcanvas容器,只保留表单内容,通过事件通知父组件切换到注册表单:

login.component.html

<div class="auth-form">
  <form>
    <!-- 原有登录表单输入项 -->
    <div class="mb-3">
      <label for="loginEmail" class="form-label">Email address</label>
      <input type="email" class="form-control" id="loginEmail">
    </div>
    <div class="mb-3">
      <label for="loginPassword" class="form-label">Password</label>
      <input type="password" class="form-control" id="loginPassword">
    </div>
    <button type="submit" class="btn btn-primary w-100">Log In</button>
    
    <!-- 切换到注册的链接 -->
    <div class="text-center mt-3">
      <p>Don't have an account? <a href="#" (click)="switchToRegister.emit($event)">Register</a></p>
    </div>
  </form>
</div>

login.component.ts

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

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent {
  @Output() switchToRegister = new EventEmitter<Event>();
}

3. 修改Register组件,移除独立Offcanvas并添加切换事件

同理,去掉自身Offcanvas容器,添加切换到登录的事件:

register.component.html

<div class="auth-form">
  <form>
    <!-- 原有注册表单输入项 -->
    <div class="mb-3">
      <label for="registerName" class="form-label">Full Name</label>
      <input type="text" class="form-control" id="registerName">
    </div>
    <div class="mb-3">
      <label for="registerEmail" class="form-label">Email address</label>
      <input type="email" class="form-control" id="registerEmail">
    </div>
    <div class="mb-3">
      <label for="registerPassword" class="form-label">Password</label>
      <input type="password" class="form-control" id="registerPassword">
    </div>
    <button type="submit" class="btn btn-primary w-100">Register</button>
    
    <!-- 切换到登录的链接 -->
    <div class="text-center mt-3">
      <p>Already have an account? <a href="#" (click)="switchToLogin.emit($event)">Log in</a></p>
    </div>
  </form>
</div>

register.component.ts

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

@Component({
  selector: 'app-register',
  templateUrl: './register.component.html',
  styleUrls: ['./register.component.css']
})
export class RegisterComponent {
  @Output() switchToLogin = new EventEmitter<Event>();
}

核心逻辑说明

  • 共用一个Offcanvas容器,避免多弹窗混乱,通过*ngIf实现表单的条件渲染
  • 子组件通过@Output事件向父组件传递切换请求,由父组件统一管理显示状态
  • 切换时检查Offcanvas实例状态,确保表单切换过程中弹窗不会意外关闭
  • 拆分独立Offcanvas到父组件,让子组件专注于表单逻辑,符合职责单一原则

内容的提问来源于stack exchange,提问作者AntonioS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 11:06:19