13 小时以前 35722562e9e13f0504acc15b740d042ecb810199
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
 * 画布文字与业务属性的双向同步
 * <p>
 * 用户在画布内直接改文字,改的是组件的 content;在属性面板改值,改的是 data-qc-* 属性。
 * 保存时以属性为准,不打通的话画布里的修改会在下一次保存时被静默丢弃。
 */
import type { Component, Editor } from 'grapesjs';
 
import { QUALITY_TYPE_ATTR, propAttrName } from './attrs';
import { buildQualityTraits } from './factory';
import { definitionOf } from './lookup';
 
/**
 * 载入模板后重建属性面板字段。
 * <p>
 * traits 不参与 GrapesJS 项目数据的序列化,保存再打开时组件只剩框架自带的 id/title 两个字段,
 * 这里按 data-quality-type 从注册表重建。属性值仍以组件上的 data-qc-* 为准
 * (trait 初始化优先读组件属性,读不到才用默认值),所以不会把用户改过的值冲掉。
 */
export function restoreQualityTraits(editor: Editor): void {
  editor
    .getWrapper()
    ?.find(`[${QUALITY_TYPE_ATTR}]`)
    .forEach((component) => {
      const definition = definitionOf(component);
      if (definition) {
        component.setTraits(buildQualityTraits(definition));
      }
    });
}
 
export function bindQualityCanvasSync(editor: Editor): void {
  // 画布内改文字 → 回写业务属性
  editor.on('component:update:content', (component: Component) => {
    const contentKey = definitionOf(component)?.contentKey;
    if (!contentKey) {
      return;
    }
    const text = component.get('content');
    if (typeof text !== 'string') {
      return;
    }
    const attrName = propAttrName(contentKey);
    if (component.getAttributes()[attrName] === text) {
      return;
    }
    component.addAttributes({ [attrName]: text });
  });
 
  // 属性面板改值 → 同步画布可见文字
  editor.on('trait:value', ({ component, trait, value }) => {
    const contentKey = definitionOf(component)?.contentKey;
    if (!contentKey || typeof value !== 'string') {
      return;
    }
    if (trait?.getName() !== propAttrName(contentKey)) {
      return;
    }
    if (component.get('content') === value) {
      return;
    }
    component.set('content', value);
  });
}