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
相关产品推荐
相关产品推荐

