react-grapesjs——开源代码学习与修改(初出茅庐)

news2024/11/25 13:55:31

文章目录

    • ⭐前言
    • ⭐grapesjs初始化过程
      • 💖 渲染大体流程
        • 💖 Editor对象 创建
        • 💖 EditorModel 对象创建
        • 💖 load modules 加载定义的目录模块Module
        • 💖 StyleManager渲染过程
    • ⭐修改grapesjs配置项
    • ⭐总结
      • ⭐ 如何修改开源代码
      • ⭐如何高效阅读开源代码
    • ⭐结束

yma16-logo

⭐前言

大家好,我是yma16,本文分享关于react-grapesjs——源码学习。
该系列往期文章:
react搭建在线编辑html的站点——引入grapes实现在线拖拉拽编辑html
结果演示:
https://yongma16.xyz/react-mjml/
demo

⭐grapesjs初始化过程

源码:https://github.com/GrapesJS/grapesjs
目录结构
dir
运行源码
在这里插入图片描述

💖 渲染大体流程

💖 Editor对象 创建

  1. new Editor进入 Editor对象
  2. class Editor implements IBaseModule<EditorConfig> 执行构造函数 constructor
  constructor(config: EditorConfig = {}, opts: any = {}) {
    this.config = {
      ...defaults,
      ...config,
      pStylePrefix: config.stylePrefix ?? defaults.stylePrefix,
    };
    this.em = new EditorModel(this.config);
    this.$ = opts.$;
    this.em.init(this);
    this.editor = this.em;
  }

💖 EditorModel 对象创建

  1. class EditorModel extends Model 执行构造函数
  constructor(conf: EditorConfig = {}) {
   super();
   this._config = conf;
   const { config } = this;
   this.set('Config', conf);
   this.set('modules', []);
   this.set('toLoad', []);
   this.set('storables', []);
   this.set('selected', new Selected());
   this.set('dmode', config.dragMode);
   const { el, log } = config;
   const toLog = log === true ? keys(logs) : isArray(log) ? log : [];
   bindAll(this, 'initBaseColorPicker');

   if (el && config.fromElement) {
     config.components = el.innerHTML;
   }

   this.attrsOrig = el
     ? toArray(el.attributes).reduce((res, next) => {
         res[next.nodeName] = next.nodeValue;
         return res;
       }, {} as Record<string, any>)
     : '';

   // Move components to pages
   if (config.components && !config.pageManager) {
     config.pageManager = { pages: [{ component: config.components }] };
   }

   // Load modules
   deps.forEach(constr => this.loadModule(constr));
   storableDeps.forEach(constr => this.loadStorableModule(constr));
   this.on('change:componentHovered', this.componentHovered, this);
   this.on('change:changesCount', this.updateChanges, this);
   this.on('change:readyLoad change:readyCanvas', this._checkReady, this);
   toLog.forEach(e => this.listenLog(e));

   // Deprecations
   [{ from: 'change:selectedComponent', to: 'component:toggled' }].forEach(event => {
     const eventFrom = event.from;
     const eventTo = event.to;
     this.listenTo(this, eventFrom, (...args) => {
       this.trigger(eventTo, ...args);
       this.logWarning(`The event '${eventFrom}' is deprecated, replace it with '${eventTo}'`);
     });
   });
 }

💖 load modules 加载定义的目录模块Module

deps的类型

const deps: (new (em: EditorModel) => IModule)[] = [
  UtilsModule,
  I18nModule,
  KeymapsModule,
  UndoManagerModule,
  StorageManager,
  DeviceManager,
  ParserModule,
  StyleManager,
  SelectorManager,
  ModalModule,
  CodeManagerModule,
  PanelManager,
  RichTextEditorModule,
  TraitManager,
  LayerManager,
  CanvasModule,
  CommandsModule,
  BlockManager,
];
    // Load modules
    deps.forEach(constr => this.loadModule(constr));

💖 StyleManager渲染过程

路径 src/style_manager

在这里插入图片描述

构造函数

constructor(em: EditorModel) {
    super(em, 'StyleManager', new Sectors([], { em }), stylesEvents, defaults);
    bindAll(this, '__clearStateTarget');
    const c = this.config;
    const ppfx = c.pStylePrefix;
    if (ppfx) c.stylePrefix = ppfx + c.stylePrefix;
    this.builtIn = new PropertyFactory();
    this.properties = new Properties([], { em, module: this });
    this.sectors = this.all; // TODO check if (module: this) is required
    const model = new Model({ targets: [] });
    this.model = model;

    // Triggers for the selection refresh and properties
    const ev = 'component:toggled component:update:classes change:state change:device frame:resized selector:type';
    this.upAll = debounce(() => this.__upSel(), 0);
    model.listenTo(em, ev, this.upAll as any);
    // Clear state target on any component selection change, without debounce (#4208)
    model.listenTo(em, 'component:toggled', this.__clearStateTarget);

    // Triggers only for properties (avoid selection refresh)
    const upProps = debounce(() => {
      this.__upProps();
      this.__trgCustom();
    }, 0);
    model.listenTo(em, 'styleable:change undo redo', upProps);

    // Triggers only custom event
    const trgCustom = debounce(() => this.__trgCustom(), 0);
    model.listenTo(em, `${evLayerSelect} ${evTarget}`, trgCustom);

    // Other listeners
    model.on('change:lastTarget', () => em.trigger(evTarget, this.getSelected()));
  }

⭐修改grapesjs配置项

屏蔽 views的两个按钮
原来的样式
init

panels/config配置
change-panels
更改配置项 注释不需要的配置

import { PanelProperties } from '../model/Panel';

const swv = 'sw-visibility';
const expt = 'export-template';
const osm = 'open-sm';
const otm = 'open-tm';
const ola = 'open-layers';
const obl = 'open-blocks';
const ful = 'fullscreen';
const prv = 'preview';

interface ButtonProps {
  id?: string;
  active?: boolean;
  togglable?: boolean;
  className?: string;
  command?: string | (() => any);
  context?: string;
  attributes?: Record<string, any>;
}

interface PanelProps extends Omit<PanelProperties, 'id' | 'buttons'> {
  id?: string;
  buttons?: ButtonProps[];
}

export interface PanelsConfig {
  stylePrefix?: string;

  /**
   * Default panels.
   */
  defaults?: PanelProps[];
}

const config: PanelsConfig = {
  stylePrefix: 'pn-',
  defaults: [
    {
      id: 'commands',
      buttons: [{}],
    },
    {
      id: 'options',
      buttons: [
        {
          active: true,
          id: swv,
          className: 'fa fa-square-o',
          command: 'core:component-outline',
          context: swv,
          attributes: { title: 'View components' },
        },
        {
          id: prv,
          className: 'fa fa-eye',
          command: prv,
          context: prv,
          attributes: { title: 'Preview' },
        },
        {
          id: ful,
          className: 'fa fa-arrows-alt',
          command: ful,
          context: ful,
          attributes: { title: 'Fullscreen' },
        },
        {
          id: expt,
          className: 'fa fa-code',
          command: expt,
          attributes: { title: 'View code' },
        },
      ],
    },
    {
      id: 'views',
      buttons: [
        {
          id: osm,
          className: 'fa fa-paint-brush',
          command: osm,
          active: true,
          togglable: false,
          attributes: { title: 'Open Style Manager' },
        },
        // {
        //   id: otm,
        //   className: 'fa fa-cog',
        //   command: otm,
        //   togglable: false,
        //   attributes: { title: 'Settings' },
        // },
        // {
        //   id: ola,
        //   className: 'fa fa-bars',
        //   command: ola,
        //   togglable: false,
        //   attributes: { title: 'Open Layer Manager' },
        // },
        {
          id: obl,
          className: 'fa fa-th-large',
          command: obl,
          togglable: false,
          attributes: { title: 'Open Blocks' },
        },
      ],
    },
  ],
};

export default config;

修改成功!
result
同理合并配置项也是合并配置module的代码可以实现

⭐总结

⭐ 如何修改开源代码

修改开源代码的步骤如下:

  1. 首先要获取并安装开发环境。这包括编译器、文本编辑器和版本控制软件等。

  2. Fork开源项目,即在GitHub或其他代码托管平台上复制一份项目,这样你就有了自己的独立分支。

  3. 在你的本地机器上克隆你所Fork的项目。通过clone命令将整个项目下载到你的本地机器上。

  4. 创建新的分支。你需要创建一个新的分支,以便你可以在不影响其他贡献者的情况下进行更改。

  5. 对代码进行修改。使用你的文本编辑器打开项目文件并进行所需的更改,完成后保存文件。

  6. 运行测试。运行项目的测试套件,确保你的修改没有破坏现有代码的功能。

  7. 提交修改。使用git提交修改到你的本地分支并将这些更改推送到你的Fork仓库。

  8. 发送一个合并请求。你可以向原始项目的所有者发送一个请求,请求将你的分支合并到他们的主分支上。

以上是修改开源代码的基本步骤,需要结合实际情况进行具体操作。在修改开源代码时,不仅要尊重原作者的版权,还要了解开源授权协议及相应的规定。

⭐如何高效阅读开源代码

阅读开源代码可以帮助你学习其他程序员的技术,尤其是在你遇到类似的问题时,可以参考开源代码中的解决方案。以下是一些高效阅读开源代码的技巧:

  1. 了解项目结构:先了解项目的目录结构和代码风格,可以帮助你更快地定位代码位置和理解代码。

  2. 建立索引:可以使用工具或者手动建立索引,以便于更快地查找关键代码和内容。

  3. 浅阅读:先快速浏览代码,了解项目的整体结构和大致流程。

  4. 深度阅读:对于关键的代码部分,进行深度阅读,仔细理解其实现和作用。

  5. 调试代码:在自己的环境中运行代码,通过调试来理解代码的执行过程和实际效果。

  6. 参考文档:阅读开源项目的文档和介绍,可以更好地理解代码和项目。

  7. 学习工具:学习使用开源代码的工具,如IDE、版本控制软件等,可以更好地理解和使用开源代码。

最重要的是,在阅读开源代码时,要注重理解代码的思路和设计方式,而不是仅仅复制代码。

⭐结束

本文分享到这结束,如有错误或者不足之处欢迎指出!
light

👍 点赞,是我创作的动力!
⭐️ 收藏,是我努力的方向!
✏️ 评论,是我进步的财富!
💖 最后,感谢你的阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/977857.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

英诺森 “供应链智能数据平台”荣获“科技进步奖”

近日&#xff0c;2023年中国物流与采购联合会科学技术奖正式公布&#xff0c;该奖项经国家科技部批准&#xff0c;在国家科学技术奖励工作办公室登记备案&#xff0c;是我国物流行业最具影响力的奖项之一。 英诺森联合客户申报的科技项目“英诺森供应链智能数据平台”&#xf…

如何查找GNU C语言参考手册

快捷通道 标准C/C参考手册 GNU C参考手册HTML版 GNU C参考手册PDF版本 HTML版本部分目录预览 从GNU官网找那个GNU C参考手册 访问gnu.org 点击软件 下滑找到gnu-c-manual或者在这个页面Ctrl-f搜索"manual" 点进去即可看到HTML版本和PDF版本

slog实战:文件日志、轮转与kafka集成

《slog正式版来了&#xff1a;Go日志记录新选择&#xff01;[1]》一文发布后&#xff0c;收到了很多读者的反馈&#xff0c;意见集中在以下几点&#xff1a; 基于slog如何将日志写入文件slog是否支持log轮转(rotation)&#xff0c;如果slog不支持&#xff0c;是否有好的log轮转…

【力扣每日一题05】数组篇--加一

一、题目 给定一个由 整数 组成的 非空 数组所表示的非负整数&#xff0c;在该数的基础上加一。 最高位数字存放在数组的首位&#xff0c; 数组中每个元素只存储单个数字。 你可以假设除了整数 0 之外&#xff0c;这个整数不会以零开头。 示例 1&#xff1a; 输入&#xff1…

Codeforces Round 806 (Div. 4) D 字符串

题目链接&#xff1a;Codeforces Round 806 (Div. 4) D 给你长度最多为 8的 n个字符串 s1,s2,…,sn。 对于每个字符串 si&#xff0c;判断是否存在两个字符串 sj和 sk&#xff0c;使得 sisjsk。也就是说&#xff0c;si&#xfffd;&#xfffd;是sj&#xfffd;&#xfffd;和…

「网页开发|前端开发|Vue」05 Vue实战:从零到一实现一个网站导航栏

本文主要介绍如何从最开始的草图&#xff0c;通过确定基本结构、修改元素布局、美化外观来实现一个网站导航栏&#xff0c;从而熟悉网页开发的基本流程。同时&#xff0c;我们会把性能、规范性、可维护性方面的代码优化也考虑其中。 文章目录 本系列前文传送门一、场景说明&am…

【LeetCode】双指针求解和为s的两个数字

Problem: 剑指 Offer 57. 和为s的两个数字 文章目录 题目解析算法思路分析复杂度Code 题目解析 首先来讲解一下本题的思路 我们看到本题的意思很简单&#xff0c;就是去这个nums这个数组中进行寻找&#xff0c;如果找到了两个数相加之和为target的话&#xff0c;那构成一个结果…

C++11新特性① | C++11 常用关键字实战详解

目录 1、引言 2、C11 新增关键字详解 2.1、auto 2.2、override 2.3、final 2.4、nullptr 2.5、使用delete阻止拷贝类对象 2.6、decltype 2.7、noexcept 2.8、constexpr 2.9、static_assert VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xf…

网络协议从入门到底层原理学习(二)—— Mac地址/IP地址

文章目录 网络协议从入门到底层原理学习&#xff08;二&#xff09;—— Mac地址/IP地址1、MAC地址2、MAC地址的表示格式3、MAC地址表4、MAC地址操作5、MAC地址的获取6、ARP7、ICMP8、IP地址9、IP地址的分类和格式10、不同分类的IP地址的范围11、特殊 IP 地址12、子网掩码13、子…

etcd分布式存储

etcd分布式存储 etcd简介etcd下载安装etcd常用命令etcd配置参数etcd集群golang操作etcd

C语言基础知识——枚举

1. 枚举 枚举&#xff08;Enumeration&#xff09;是一种用户自定义的数据类型&#xff0c;用于定义一组具有离散值的符号常量。枚举使得代码更加可读和易于理解&#xff0c;提高了代码的可读性和可维护性。 //枚举的语法 enum 枚举名称 {值1,值2,值3,... };1.1 枚举成员的类型…

C++中虚继承时的构造函数

在虚继承中,虚基类是由最终的派生类初始化的,换句话说,最终派生类的构造函数必须要调用虚基类的构造函数。对最终的派生类来说,虚基类是间接基类,而不是直接基类。这跟普通继承不同,在普通继承中,派生类构造函数中只能调用直接基类的构造函数,不能调用间接基类的。 下面…

react使用hook封装一个search+input+checkbox组件

目录 react使用hook封装一个searchinputcheckbox组件searchPro.jsx使用组件效果 react使用hook封装一个searchinputcheckbox组件 searchPro.jsx import { Checkbox, Input } from "antd"; import React, { useEffect, useState } from "react"; import S…

激活函数总结(二十七):激活函数补充(Multiquadratic、InvMultiquadratic)

激活函数总结&#xff08;二十七&#xff09;&#xff1a;激活函数补充 1 引言2 激活函数2.1 Multiquadratic激活函数2.2 InvMultiquadratic激活函数 3. 总结 1 引言 在前面的文章中已经介绍了介绍了一系列激活函数 (Sigmoid、Tanh、ReLU、Leaky ReLU、PReLU、Swish、ELU、SEL…

kubernetesl yaml deploy rancher server

文章目录 1. 简介2. 预备条件3. 创建存储目录4. 部署 rancher server5. 访问6. 加入集群 1. 简介 Rancher 是一个开源的企业级全栈化容器部署及管理平台。已有超过 1900 万次下载&#xff0c;4000 生产环境的应用。 简单的说&#xff0c;就是一个可以让你通过 web 界面管理 d…

78 # koa 中间件的实现

上上节实现了上下文的&#xff0c;上一节使用了一下中间件&#xff0c;这一节来实现 koa 的中间件这个洋葱模型。 思路&#xff1a; 储存用户所有的 callback将用户传递的 callback 全部组合起来&#xff08;redux 里的 compose&#xff09;组合成一个线性结构依次执行&#…

input输出的都是字符串,类似拼接的那种

input输出的都是字符串&#xff0c;类似拼接的那种 input()方法返回的所有的结果都是str字符串类型。

一个简单的文件系统(MinixFS)实现解析

1. Minix文件系统概要 Minix file system 是 Andrew S. Tanenbaum 在 1980 年代发明的文件系统, 并随着 Minix 操作系统一起于 1987 年发布。 Linus 编写 Linux 内核第一个版本的时候, 使用的也是 Minix FS, Linux 至今依然提供了对 Minix FS 的支持。Minix FS 结构简单, 易于…

【MyBatis篇】MyBatis框架基础知识笔记

目录 ORM思想&#xff08;对象关系映射思想&#xff09; ORM思想图解 初识MyBatis 什么是MyBatis呢&#xff1f; JDBC弊端 自己总结&#xff1a; chatGPT总结&#xff1a; MyBatis介绍以及本质分析 JDBC编程的劣势&#xff0c;MyBatis提供了以下解决方案&#xff0c;具…

星辰天合 CEO 胥昕受邀参加人民网 2023 “小巨人”发展论坛

为进一步推动专精特新“小巨人”企业高质量发展&#xff0c;近日&#xff0c;由人民网主办&#xff0c;人民网财经研究院、828 企业服务平台共同承办的 2023“小巨人”发展论坛在人民日报社新媒体大厦举行&#xff0c;星辰天合 CEO 胥昕受邀参加。 2023 “小巨人”发展论坛现场…