Angular实现屏幕缩小时将换行工具项移入弹窗的方法
实现响应式工具栏:超出项移入弹窗
我有如下Angular项目中的工具数据数组:
public tools: Tool[] = [ { image: './assets/img/OpenFolder.svg', title: 'Upload' }, { image: './assets/img/Save.png', title: 'Save' }, { image: './assets/img/Printer.png', title: 'Printing' }, { image: './assets/img/Delete.png', title: 'Delete' }, { image: './assets/img/Paste.svg', title: 'Paste' }, { image: './assets/img/Copy.png', title: 'Copy' }, { image: './assets/img/favicon.png', title: 'Rotate left' }, { image: './assets/img/favicon.png', title: 'Rotate right' }, { image: './assets/img/favicon.png', title: 'Flip vertical' }, { image: './assets/img/favicon.png', title: 'Flip horizontal' }, { image: './assets/img/favicon.png', title: 'Crop picture' }, { image: './assets/img/favicon.png', title: 'Resize picture' }, { image: './assets/img/favicon.png', title: 'Brightness' }, { image: './assets/img/favicon.png', title: 'Color' }, { image: './assets/img/favicon.png', title: 'Opacity' }, ];
当前的HTML和SCSS代码如下:
<ul> <li *ngFor="let tool of tools" title="{{ tool.title }}"><img src="{{ tool.image }}"></li> </ul>
ul { display: flex; flex-wrap: wrap; flex-direction: row; }
当前效果是屏幕宽度小于max-width时,工具项会水平换行。我需要实现:当屏幕缩小到小于max-width时,把换行的项移入弹窗,只有点击按钮时弹窗才会显示。
解决方案
步骤1:组件逻辑(TypeScript)
监听窗口宽度变化,拆分工具数组为主栏显示项和弹窗隐藏项,同时控制弹窗的显示状态:
import { Component, OnInit, HostListener } from '@angular/core'; interface Tool { image: string; title: string; } @Component({ selector: 'app-toolbar', templateUrl: './toolbar.component.html', styleUrls: ['./toolbar.component.scss'] }) export class ToolbarComponent implements OnInit { public tools: Tool[] = [ { image: './assets/img/OpenFolder.svg', title: 'Upload' }, { image: './assets/img/Save.png', title: 'Save' }, { image: './assets/img/Printer.png', title: 'Printing' }, { image: './assets/img/Delete.png', title: 'Delete' }, { image: './assets/img/Paste.svg', title: 'Paste' }, { image: './assets/img/Copy.png', title: 'Copy' }, { image: './assets/img/favicon.png', title: 'Rotate left' }, { image: './assets/img/favicon.png', title: 'Rotate right' }, { image: './assets/img/favicon.png', title: 'Flip vertical' }, { image: './assets/img/favicon.png', title: 'Flip horizontal' }, { image: './assets/img/favicon.png', title: 'Crop picture' }, { image: './assets/img/favicon.png', title: 'Resize picture' }, { image: './assets/img/favicon.png', title: 'Brightness' }, { image: './assets/img/favicon.png', title: 'Color' }, { image: './assets/img/favicon.png', title: 'Opacity' }, ]; public visibleTools: Tool[] = []; public hiddenTools: Tool[] = []; public showPopup = false; private maxWidth = 768; // 自定义响应式阈值 private toolItemWidth = 48; // 单个工具项的总宽度(含间距) ngOnInit(): void { this.updateToolGroups(); } @HostListener('window:resize') onWindowResize(): void { this.updateToolGroups(); } private updateToolGroups(): void { const windowWidth = window.innerWidth; if (windowWidth >= this.maxWidth) { // 屏幕足够宽,显示所有工具 this.visibleTools = [...this.tools]; this.hiddenTools = []; this.showPopup = false; } else { // 计算主栏可容纳的工具数量 const containerAvailableWidth = windowWidth - 32; // 减去容器左右内边距 const visibleCount = Math.floor(containerAvailableWidth / this.toolItemWidth); this.visibleTools = this.tools.slice(0, visibleCount); this.hiddenTools = this.tools.slice(visibleCount); } } togglePopup(): void { this.showPopup = !this.showPopup; } }
步骤2:模板(HTML)
添加主工具栏、弹窗触发按钮和弹窗容器:
<div class="toolbar-wrapper"> <!-- 主工具栏 --> <ul class="main-tools"> <li *ngFor="let tool of visibleTools" title="{{ tool.title }}"> <img src="{{ tool.image }}" alt="{{ tool.title }}"> </li> <!-- 仅当有隐藏工具时显示弹窗按钮 --> <li *ngIf="hiddenTools.length > 0" class="more-btn" (click)="togglePopup()"> <img src="./assets/img/more-icon.svg" alt="更多工具"> </li> </ul> <!-- 工具弹窗 --> <div class="tools-popup" *ngIf="showPopup && hiddenTools.length > 0"> <ul class="popup-tools"> <li *ngFor="let tool of hiddenTools" title="{{ tool.title }}"> <img src="{{ tool.image }}" alt="{{ tool.title }}"> </li> </ul> </div> </div>
步骤3:样式(SCSS)
完善布局样式,控制主栏不换行、弹窗定位和响应式显示:
.toolbar-wrapper { position: relative; padding: 8px; } .main-tools { display: flex; flex-direction: row; flex-wrap: nowrap; // 禁止主栏换行 gap: 8px; list-style: none; margin: 0; padding: 0; li { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; cursor: pointer; border-radius: 4px; transition: background-color 0.2s; &:hover { background-color: #f5f5f5; } img { width: 24px; height: 24px; } } .more-btn { background-color: #f0f0f0; } } .tools-popup { position: absolute; top: calc(100% + 4px); right: 8px; background-color: #fff; border: 1px solid #e0e0e0; border-radius: 6px; box-shadow: 0 2px 12px rgba(0,0,0,0.1); z-index: 100; .popup-tools { display: flex; flex-direction: column; gap: 4px; list-style: none; margin: 0; padding: 8px; li { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; cursor: pointer; border-radius: 4px; transition: background-color 0.2s; &:hover { background-color: #f5f5f5; } img { width: 24px; height: 24px; } } } } // 屏幕宽度达标时隐藏弹窗按钮 @media (min-width: 768px) { .more-btn { display: none !important; } }
关键说明
- 参数调整:根据实际设计修改
maxWidth(响应式阈值)和toolItemWidth(单个工具项总宽度),确保主栏容纳数量计算准确。 - 实时更新:通过
resize监听事件,窗口大小变化时自动重新拆分工具组。 - 交互逻辑:无隐藏工具时自动关闭弹窗,避免无效显示;点击按钮切换弹窗状态。
内容的提问来源于stack exchange,提问作者Lê Anh Đức
相关产品推荐
相关产品推荐

