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

如何让hcard.js在Angular 2+与CKEditor 5中实现联系人拖拽功能

实现CKEditor 5 Angular项目中的联系人(Hcard)拖拽功能

核心思路

CKEditor 5的拖拽功能需要结合自定义Widget插件与DragDrop模块实现,核心是监听外部拖拽事件,将目标元素转换为编辑器可识别的模型结构,再通过转换器映射为视图Widget。

具体实现步骤

1. 编写自定义Hcard Widget插件

创建hcard-widget.plugin.ts文件,实现Widget的模型定义、转换规则及拖拽处理逻辑:

import { Plugin } from '@ckeditor/ckeditor5-core';
import { Widget } from '@ckeditor/ckeditor5-widget';
import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils';
import { DragDrop } from '@ckeditor/ckeditor5-upload';

export class HcardWidget extends Plugin {
  static get requires() {
    return [Widget, DragDrop];
  }

  init() {
    const editor = this.editor;
    const schema = editor.model.schema;
    const conversion = editor.conversion;

    // 注册模型结构
    schema.register('hcard', {
      allowWhere: '$block',
      isObject: true,
      allowContentOf: '$block'
    });
    schema.register('hcardName', {
      allowIn: 'hcard',
      allowContentOf: '$text'
    });

    // 视图→模型转换(处理拖拽进来的HTML)
    conversion.for('upcast').elementToElement({
      model: 'hcard',
      view: { name: 'div', classes: 'hcard' }
    });
    conversion.for('upcast').elementToElement({
      model: 'hcardName',
      view: { name: 'span', classes: 'hcard-name' }
    });

    // 模型→视图转换(渲染编辑器内的Widget)
    conversion.for('downcast').elementToElement({
      model: 'hcard',
      view: (_, { writer }) => {
        const div = writer.createContainerElement('div', { class: 'hcard' });
        return toWidget(div, writer, { label: '联系人卡片' });
      }
    });
    conversion.for('downcast').elementToElement({
      model: 'hcardName',
      view: (_, { writer }) => writer.createEditableElement('span', { class: 'hcard-name' })
    });

    // 监听编辑器drop事件,处理外部拖拽
    editor.plugins.get(DragDrop).on('drop', (evt, data) => {
      const dragHtml = data.dataTransfer.getData('text/html');
      const doc = new DOMParser().parseFromString(dragHtml, 'text/html');
      const hcardEl = doc.querySelector('.hcard');

      if (hcardEl) {
        evt.stop(); // 阻止默认拖拽行为
        const name = hcardEl.querySelector('.hcard-name')?.textContent || '';

        // 插入到编辑器模型
        editor.model.change(writer => {
          const hcard = writer.createElement('hcard');
          const nameNode = writer.createElement('hcardName');
          writer.appendText(name, nameNode);
          writer.append(nameNode, hcard);
          editor.model.insertContent(hcard, editor.model.document.selection);
        });
      }
    }, { priority: 'high' });
  }
}

2. Angular组件中集成插件与拖拽触发元素

在使用CKEditor的组件中配置编辑器,并添加可拖拽的联系人卡片:

import { Component } from '@angular/core';
import { ClassicEditor } from '@ckeditor/ckeditor5-editor-classic';
import { Essentials, Paragraph } from '@ckeditor/ckeditor5-core';
import { HcardWidget } from './hcard-widget.plugin';

@Component({
  selector: 'app-ckeditor-hcard',
  template: `
    <div class="hcard draggable" draggable="true" (dragstart)="handleDragStart($event)">
      <span class="hcard-name">张三</span>
    </div>
    <ckeditor 
      [editor]="Editor" 
      [config]="editorConfig" 
      [(ngModel)]="editorContent">
    </ckeditor>
  `,
  styles: [`
    .hcard { 
      padding: 8px; border: 1px solid #ddd; border-radius: 4px; 
      margin: 10px 0; cursor: grab; background: #f8f8f8;
    }
    .hcard-name { font-weight: 600; }
    ckeditor { margin-top: 20px; }
  `]
})
export class CkeditorHcardComponent {
  Editor = ClassicEditor;
  editorContent = '';
  editorConfig = {
    plugins: [Essentials, Paragraph, HcardWidget],
    toolbar: ['undo', 'redo']
  };

  handleDragStart(event: DragEvent) {
    const target = event.target as HTMLElement;
    event.dataTransfer?.setData('text/html', target.outerHTML);
  }
}

3. 模块中导入CKEditor依赖

在对应Angular模块中引入CKEditor模块:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { CKEditorModule } from '@ckeditor/ckeditor5-angular';
import { CkeditorHcardComponent } from './ckeditor-hcard.component';

@NgModule({
  imports: [BrowserModule, FormsModule, CKEditorModule],
  declarations: [CkeditorHcardComponent],
  bootstrap: [CkeditorHcardComponent]
})
export class AppModule { }

关键注意点

  • 拖拽时必须传递text/html格式的数据,确保编辑器能解析目标元素
  • 自定义Widget的Schema配置需严格遵循CKEditor 5的模型规则,避免内容过滤
  • drop事件监听需设置高优先级,防止默认拖拽行为覆盖自定义逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 15:18:13