Angular中点击按钮复制Div内容时如何保留换行格式?
The issue you're facing is that textContent strips out all HTML structure and line breaks, resulting in a single continuous string. To fix this, we need to manually construct the copy string with proper newlines that match your visual layout, and use either the modern Clipboard API (preferred) or a textarea element to ensure newlines are preserved during copying.
Step-by-Step Fix
1. Use @ViewChild to Reference the Data Container
Instead of querying the document directly, use Angular's @ViewChild to get a reference to your .data div. This is more maintainable and aligns with Angular's best practices.
2. Construct the Formatted Copy String
Iterate through each section of your data, adding headings and items with appropriate newlines. Include blank lines between sections to match the page's visual flow.
3. Copy Using the Clipboard API (or Fallback to execCommand)
The Clipboard API is the modern way to copy text, handling multi-line strings natively. We'll add a fallback for older browsers where the API isn't supported.
Modified Component Code
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core'; @Component({ selector: 'visualization-source-packet-dialog', templateUrl: './visualization-source-packet-dialog.component.html', styleUrls: './visualization-source-packet-dialog.component.scss' }) export class VisualizationSourcePacketDialogComponent implements OnInit { public sampleSources = ['ADS-B: 200', 'MIDB: 150', 'Twitter: 0']; public sampleOverlay = ['overlay1: url', 'overkay2: url', 'overlay3: url']; public sampleKmls = ['kml1: url', 'kml2: url', 'kml3: url']; @ViewChild('dataContainer') dataContainer!: ElementRef<HTMLElement>; constructor() { } ngOnInit() { console.log("hitting") } public async copy() { let copyString = ''; const sections = this.dataContainer.nativeElement.children; for (let i = 0; i < sections.length; i++) { const section = sections[i] as HTMLElement; // Extract and add the section heading const heading = section.querySelector('h4')?.textContent?.trim(); if (heading) { copyString += `${heading}\n`; } // Extract and add each item in the section const items = section.querySelectorAll('div'); items.forEach(item => { const itemText = item.textContent?.trim(); if (itemText) { copyString += `${itemText}\n`; } }); // Add a blank line between sections (skip after the last one) if (i !== sections.length - 1) { copyString += '\n'; } } // Remove any trailing newlines to clean up the output copyString = copyString.trimEnd(); try { // Use modern Clipboard API await navigator.clipboard.writeText(copyString); console.log('Formatted text copied successfully!'); } catch (err) { console.error('Clipboard API failed, falling back to execCommand:', err); // Fallback for older browsers const dummyTextarea = document.createElement('textarea'); document.body.appendChild(dummyTextarea); dummyTextarea.value = copyString; dummyTextarea.select(); document.execCommand('copy'); document.body.removeChild(dummyTextarea); } } }
Modified HTML Template
Add the #dataContainer template reference to your .data div, and include a copy button to trigger the function:
<div class="data" #dataContainer> <div> <h4>Data Sources:</h4> <div *ngFor="let source of sampleSources"> {{ source }} </div> </div> <div> <h4>Overlay:</h4> <div *ngFor="let source of sampleOverlay"> {{ source }} </div> </div> <div> <h4>KML:</h4> <div *ngFor="let source of sampleKmls"> {{ source }} </div> </div> <div> <h4>Callouts:</h4> <div *ngFor="let source of sampleSources"> {{ source }} </div> </div> <div> <h4>LiveFeeds:</h4> <div> No LiveFeeds </div> </div> </div> <button (click)="copy()">Copy Formatted Data</button>
Why This Works
- Manual String Construction: We build the copy string by iterating through each section and item, adding
\nto create line breaks that match your visual layout. - Clipboard API: This modern API supports multi-line text natively, ensuring newlines are preserved in the copied content.
- Fallback Support: The
execCommandfallback ensures compatibility with older browsers, using a textarea (which handles multi-line text better than an input element).
After implementing this, copying will produce the following formatted text:
Data Sources: ADS-B: 200 MIDB: 150 Twitter: 0 Overlay: overlay1: url overkay2: url overlay3: url KML: kml1: url kml2: url kml3: url Callouts: ADS-B: 200 MIDB: 150 Twitter: 0 LiveFeeds: No LiveFeeds
内容的提问来源于stack exchange,提问作者Karam

