递归组件中JSON键映射拖拽功能异常问题排查
JSON拖拽键映射功能问题修复
我正在实现两个JSON之间的拖拽键映射功能,用递归组件JsonViewerComponent展示JSON结构,通过isSourceJson标识区分源/目标:源JSON显示可拖拽的扁平化键,目标JSON显示放置区域。目前碰到两个具体问题:
- 可拖拽元素的
dragstart事件能触发,但UI没有拖拽视觉效果;换成drag事件或移除事件绑定后,UI拖拽显示正常。 - 目标JSON的放置区域
dragover事件能正常触发,但drop事件完全没响应。
问题1修复:dragstart事件导致UI无拖拽反馈
问题根源有两个:一是模板里绑定的是drag事件而非dragstart,二是dragstart事件处理逻辑没有让浏览器生成默认拖拽UI。
修复步骤:
- 把模板中可拖拽元素的
(drag)替换为(dragstart),并传入事件对象和当前扁平化键值 - 在
dragstart事件处理中正确设置dataTransfer数据,让浏览器识别拖拽行为并生成默认UI
问题2修复:drop事件无响应
drop事件不触发的核心原因是dragover事件中没有阻止默认行为——浏览器默认会阻止拖拽到非标准区域,必须调用event.preventDefault()才能启用drop事件。另外drop事件中也需要阻止默认行为,避免浏览器尝试打开拖拽的文本数据。
修改后的核心代码
json-viewer.component.html
<ng-container *ngIf="data"> <ng-container *ngIf="isObject(data)"> <span>{{'{'}}</span><br> <div *ngFor="let item of getFormattedData(data)" [style.marginLeft.px]="20"> <span>{{item.key}}: </span><app-json-viewer [data]="item.value" [previousKey]="previousKey+item.key+'.'" [isSourceJson]="isSourceJson"></app-json-viewer> </div> <span>{{'}'}}</span> </ng-container> <ng-container *ngIf="isArray(data)"> <span>{{'['}}</span><br> <div *ngFor="let item of data" [style.marginLeft.px]="20"> <app-json-viewer [data]="item" [previousKey]="previousKey" [isSourceJson]="isSourceJson"></app-json-viewer> </div> <span>{{']'}}</span><br> </ng-container> <ng-container *ngIf="!isObject(data) && !isArray(data)"> <span>{{data}},</span> <ng-container *ngIf="isSourceJson"> <!-- 替换drag为dragstart,传递事件和键值 --> <span class="draggable" draggable="true" (dragstart)="onDragStart($event, previousKey.slice(0, -1))">{{previousKey.slice(0, -1)}}</span> </ng-container> <ng-container *ngIf="!isSourceJson"> <span class="drop-area" (dragover)="onDragOver($event)" (drop)="onDrop($event)">{{ sourceKey || '拖拽到这里' }}</span> </ng-container> </ng-container> </ng-container>
json-viewer.component.ts
import { Component, Input } from '@angular/core'; @Component({ selector: 'app-json-viewer', templateUrl: './json-viewer.component.html', styleUrls: ['./json-viewer.component.less'] }) export class JsonViewerComponent { @Input() data: any; @Input() previousKey: string = ''; @Input() isSourceJson: boolean = true; sourceKey?: string; isObject(val: any): boolean { return val && typeof val === 'object' && !Array.isArray(val); } isArray(val: any): boolean { return Array.isArray(val); } getFormattedData(data: any): Array<{ key: string, value: any }> { let result = []; for (let key in data) { if (data.hasOwnProperty(key)) { result.push({ key, value: data[key] }); } } return result; } onDragStart(event: DragEvent, key: string) { console.log("拖拽开始", key); // 必须设置dataTransfer数据,否则浏览器可能不触发后续拖拽流程 event.dataTransfer!.setData('text/plain', key); event.dataTransfer!.effectAllowed = "copyMove"; } onDragOver(event: DragEvent) { // 阻止默认行为是触发drop事件的核心 event.preventDefault(); event.dataTransfer!.dropEffect = "copyMove"; } onDrop(event: DragEvent) { console.log('拖拽完成'); // 阻止默认行为,避免浏览器打开拖拽的文本内容 event.preventDefault(); const data = event.dataTransfer!.getData('text/plain'); if(data) this.sourceKey = data; event.dataTransfer!.clearData(); } }
内容的提问来源于stack exchange,提问作者sooraj
相关产品推荐
相关产品推荐

