You need to enable JavaScript to run this app.
导航
魔方-二开教程
最近更新时间:2025.07.17 10:38:07首次发布时间:2025.07.17 10:34:25
复制全文
我的收藏
有用
有用
无用
无用

一、文档说明

本文档主要用于对于魔方组件、action、plugin插件二开流程的梳理以及发布。

二、区分组件种类

魔方组件分为两种:

  • 左侧通用组件:可拉入编辑框的通用组件。
  • 右侧配置组件:如下是一个 Select 选择组件,可用于传入数据或支持请求拉取数据。

三、组件开发流程

3.1 进行cli工具安装

详见 魔方Cli工具使用指南

3.2 通用组件开发流程

3.2.1 确认组件配置

魔方组件配置包括:样式配置 以及 个性化配置 部分,在 editor.js 或者 组件的 props 目录,前者是旧版,后者是新版。

  1. 样式配置:分为两部分 priorStyleConfig 和 optionalStyleConfig 。
    • 图中,部分 1 是 priorStyleConfig,表示优先级最高的样式设置,是在右侧编排配置中展示配置的最上面部分。
    • 部分 3 是 optionalStyleConfig,表示可选的样式配置部分,在右侧编排配置展示配置的最下面部分。
    • optionalStyleConfig面前的勾选代表这一项配置有没有值或initValue,去掉勾选可以去掉值。
  2. 个性化配置:在 props 字段配置,部分 2 就是个性化配置项。

3.2.2 元素配置

区分一下旧版和新版,旧版是在 editor.js 下编写一堆对象,新版是 基于magicProps、magicElements、magicElementsProps 去注入配置生成。

  1. 旧版:对于元素而言(通过在组件中,设置 html 元素添加 data-editable 属性,如 data-editable="inputLabel" ,去指定可配置元素的类名),样式配置和个性化配置均配置在 elementsConfig 字段下,需要注意:
    1. className一定要指定和data-editable设置的一样的类名。
    2. 样式配置 priorStyleConfig 和 optionalStyleConfig 与组件的配置方式一致 。
    3. 个性化配置则不同,通过字段 effectCptKeys 配置数组(数组中的元素为组件的个性化配置 props 项的 cpt_key)来显式指定,当前元素要设置哪些继承的组件中的个性化配置项。如果只需要在选中元素时展示此个性化配置项,组件选中时不展示,则需要在组件的 props 里设置此个性化配置的 hide 属性为 true 。

元素默认是可以拖拽来调整大小和位置的,如果要禁用该行为,可以添加 data-elemdraggable="false" 属性,如:

<div
    className="play-btn btn"
    data-editable="play-btn"
    data-elemdraggable="false"
    onClick={this.handleClick}
/>
  1. 新版

旧版基于className和data-editable的元素选中有两个问题 ① 元素渲染的 DOM 层级必须在组件层级下面 ② 最终注入的 css 选择器为 ID + Classname,一些跨端方案如 Lynx 不支持。

说明

新版方案的几个修改:

  1. 若生成样式对应唯一元素,该元素需绑定id,格式如 ${props.id}_${elementId}
  2. 若生成对应一组元素,该元素的dom需要绑定className,格式如${props.id}_magic_class_${elementId}

其中,props.id 即为注入给组件的id, elementId 为组件自定义的唯一id。

新、旧版的配置对比,旧版都是写在 editor.js 里,新版抽取了三个配置设置。

// 旧版 editor.js 配置
const config = {
    category: 'lottery',
    name: 'lotteryspin',
    priorStyleConfig: [
       'MagicLayerMode',
       {
         type: 'MagicPosXSize',
         initValue: {
             width: '640px',
             height: '143px',
          },
        },
    ],
    props: [{
      cpt_key: 'dataSource',
      type: 'MagicSelect',
      uiType: "block",
      desc: {
        _MDS_KEY: "dataSource_desc",
        _MDS_VALUE: "数据来源",
      },
      multiple: true,
      optionList: [],
    }],
    elementsConfig: [elementsConfig],
    optionalStyleConfig: [optionalStyleConfig],
    extra: [extra]
}

新版
Cli 提供三种设置配置的方式,config 与旧版的属性字段一致。

  • magicProps(key, config) // 组件属性的配置,等同于props[]​内的配置。
  • magicElements(key, config) // 选中元素的配置,等同于elementsConfig[]​的配置。
  • magicElementsProps(elementKey, propKey, config) // 选中元素内属性配置。
//panel.ts
magicProps('dataSource', {
  type: 'MagicSelect',
  uiType: 'block',
  desc: {
    _MDS_KEY: 'dataSource_desc',
    _MDS_VALUE: '抽奖数据来源',
  },
  multiple: true,
  optionList: [],
});
magicElements('address-wrapper', {
  name: { _MDS_VALUE: '地址填写页'}
})
magicElementsProps('address-wrapper', 'addressBgCollapse', {
  type: 'MagicCollapse',
  showDivide: true,
  desc: '背景及标题',
  initValue: true,
})
// index.tsx 引入panel.ts
import './panel';

magicElements与magicElementsProps区别:magicElementsProps能直接配置选中元素内部属性,下面两种写法效果一致。

magicElements("title", {
  name: "标题",
  optionalStyleConfig: ["MagicFont"],
  props: [{ cpt_key: "text", type: "MagicInput", desc: "文本" }],
});

magicElementsProps("title", "text", { type: "MagicInput", desc: "文本" });

3.2.3 旧版开发示例

magic-cli 进行项目初始化,组件类型自选,其他常规。

editor.js 配置示例:

module.exports = {
  category: "other", // 组件类型,上方选择
  appId: ["0"], // 0 表示公共业务线
  name: "testOldComponent", // 组件名称
  // 个性化配置
  // hide 字段不传默认是false
  // props 选项是对象形式
  props: [{
      cpt_key: 'contentSetting',
      type: 'MagicCollapse',
      desc: { _MDS_KEY: 'contentSetting_desc', _MDS_VALUE: '内容设置' },
      initValue: true,
    },
    {
      cpt_key: 'formNamespace',
      type: 'MagicInput',
      desc: {
        _MDS_: '表单名称',
      },
      initValue: '',
      hide: true,
      disabled: true,
      filterRegExp: '\\S+',
      filterFailDesc: {
        _MDS_VALUE: '表单名称不能为空',
      },
    },
    {
      cpt_key: 'formItemName',
      type: 'MagicInput',
      initValue: '',
      desc: { _MDS_KEY: 'formItemName_desc', _MDS_VALUE: '表单项名称' },

      hide: false,
      filterFunc: `function (props, dispatch, UI) {
        if (props.contentSetting === false) {
          dispatch({ 'hide': true });
        }
      }`,
    },
  ],
  // 优先的样式配置部分,可自定义选择
  // 灵活支持字符串和对象两种配置方式,对象配置,传入该组件需要的参数
  priorStyleConfig: [
    { 
      type: "MagicWidthXHeight",
      initValue: {
        width: '300px',
        height: '100px'
      }
    },
  ],
  
  // 底部允许的样式配置部分,可选 
  //  MagicBorder, MagicFont, MagicBackgroundImage, MagicBackgroundColor, MagicBackground, MagicOpacity
  optionalStyleConfig: [
    "MagicBackground",
    "MagicOpacity"
  ],
  // 元素配置
  // 显示说明可配置元素会被哪些配置影响,不指定则选中元素时不展示配置
  elementsConfig: [{
    className: "usename", // 类名,不带.号
    name: { _MDS_: "用户昵称"}, // B端右侧配置区最上方的展示title
    optionalStyleConfig: [],
    // 受影响的配置项的cpt_key集合
    effectCptKeys: ["formItemName"],
    props: [
      {
        cpt_key: 'name',
        type: 'MagicInput',
        desc: {
          _MDS_: '用户名称',
        },
        initValue: '',
      }
    ],
    // 元素可配置的样式
    priorStyleConfig: [
      'MagicWidthXHeight',
      {
        type: 'MagicLeftXTop',
      },

      'MagicOpacity',
      {
        type: 'MagicTRBL',
        styleName: 'border-radius',
      },
      'MagicDivide',
    ],
  }],
  desc: {
    "_MDS_KEY": "desc",
    "_MDS_VALUE": "测试旧版"
  }, // 描述内容,左侧组件卡片展示出来的名称
  introduction: {
    "_MDS_KEY": "introduction",
    "_MDS_VALUE": "测试旧版组件介绍" // 填入组件介绍
  },
  preview:"../assets/logo.png", //组件预览图路径相对地址
  thumbnail: "", // 组件icon路径相对地址
  thumbnailType: "icon", // 组件类型:image/icon
  tutorial: "", //教程地址,填写doc链接即可
  abilities: {},  // 组件能力,可以定义组件的能力,可见 附录
  extra: { // 配置一些额外能力
    "action": false, // 配置事件动作能力,需要的传入对象
    "api": false,  // api配置信息
    "tea": [ {event: "TEATEST", eventDesc: { _MDS_VALUE : "tea打点描述,参数有inappEvent:Test" }}], // 挂载tea上报事件
  }
}

index.js / index.jsx上修改

import React from 'react';
import './index.scss';

const TestOldComponent = (props) => {
  return (
    <div
      id={props.id}
      className="mtestOldComponent"
      data-comp-type={props.magicComType}
    >
      {/* elementsConfig 设置选中元素的classname需要 对应注入 */}
      <div className='usename' data-editable="usename">
        {props.usename_name || '用户名称'}
      </div>
      <input />
    </div>
  );
}

export default TestOldComponent;

本地开发调试 & 上线

// 选择你所需要的地址
~ mgx region use xxx
// 本地开放
~ mgx dev 

打开编辑器页面,加入?debug=1,找到本地开发的组件。

调试完成之后上线。

// 上传
~ mgx bundle 
// 发布
~ mgx deploy  

说明

以上代码可以直接copy进cli init后的对应文件,进行本地调试。

3.2.4 新版开发

目前对外不支持新版开发,原因是能力引用了内部模块内容待后续有需要看如何开放兼容

3.2.5 组件分类category

类型值

类型名称

common

基础

button

按钮类

form

表单类

container

容器类

tab

选项卡

lottery

抽奖类

vote

投票类

question

答题类

audiovideo

音视频

list

列表类

poi

poi类

animation

动画效果

other

其他

develop

本地开发

3.2.6 样式配置 / 个性化配置 和一些配置能力支持的组件类型及方法

可详见这里,找出自定义想要的配置方法 B端控件editor.js配置手册(对外)

3.3 配置组件开发流程

3.3.1 初始化

装完magic-cli后,进行项目初始化。

3.3.2 自定义组件开发,编写代码

进入目录,修改./src/index.tsx,根据自身需要实现的功能编写代码。

~ cd testeditor

写入一些自定义的逻辑,如下测试用例:功能是 根据输入框的值,会在下方进行输出。

import React, { useState, useMemo } from 'react';
import MagicInput from '@editorcomponent/MagicInput';

import './index.scss';
const Testeditor = (props) => {
  const {
    compValue,
    desc,
    key,
    onChange
  } = props;

  return (
    <div className="editorcomponent-testeditor">
      {desc}:
      <MagicInput
        compValue={compValue}
        onChange={(val: string) => {
          onChange(val);
        }}
      />
      {compValue && `输入内容:${compValue}`}
    </div>
  );
}
export default Testeditor;

3.3.3 修改使用组件中editor的props

进入需要使用的组件目录,修改editor.js/ts 中的 props 。
如在 select 组件增加一个配置,其中 type 值可见 testeditor 目录下的 h5(或者是pc)/configs/base.jsonuniqueId 字段。

3.3.4 本地开发验证

本地开放时,在使用组件 【select】组件目录 和 自定义组件【testeditor】目录下,启动 socket 服务。
在自定义右侧配置组件目录,即【testeditor】和 使用的组件目录【select】目录下,启动socket服务。

// 切换到 testeditor目录终端
~ cd testeditor/h5
~ mgx dev
//  切换到 select 目录终端
~ cd select/h5
~ mgx dev

testeditor:dev打包

select:dev打包

3.3.5 代理网页连接验证

打开编辑器网页,开启 Socket 监听,进入开发者模式。
Image
测试一下功能:底下会打印输出的内容,测试成功。

3.3.6 调试

进行功能开发&调试,比如我需要在原先下方输出值的同时,再加一个计算含有数字总值的功能。

import React, { useState, useMemo } from 'react';
import MagicInput from '@editorcomponent/MagicInput';

import './index.scss';
const Testeditor = (props) => {
  const {
    compValue,
    desc,
    key,
    onChange
  } = props;
  const [numList, setNumList] = useState([]);

  const total = useMemo(() => {
    return numList.reduce((prev, next) => {
      return prev + Number(next)
    }, 0)
  }, [numList])

  return (
    <div className="editorcomponent-testeditor">
      {desc}:
      <MagicInput
        compValue={compValue}
        onChange={(val: string) => {
          setNumList(val.match(/\d/g) || []);
          onChange(val);
        }}
      />
      {compValue && `输入内容:${compValue}`}
      {total > 0 && `含有数字总值为:${total}`}
    </div>
  );
}
export default Testeditor;

效果如下:

3.3.7 上线

本地开发调试完毕之后,保存代码,关掉socket连接,确认无误之后,发布上线。

~ mgx upload
~ mgx publish

3.3.8 附录

react

react-dom

react-redux

@ies/semi-ui-react

@editorcomponent/MagicInput

@editorcomponent/MagicSelect

@editorcomponent/.......

@editor/utils

四、action 动作开发流程

4.1 action是什么

action动作是一个方法的声明,包括方法的类型、名称、参数以及方法代码。
动作概念,是以配置的方式,将事件(click、change)与动作关联起来,即可以以配置的方式实现页面交互。

4.2 开发流程

4.2.1 初始化

  1. 执行 mgx init ,初始化名为 testaction 的动作,选择 action 类型。
testaction/h5
├── configs
│   ├── base.json
│   └── editor.js
├── dist // 初始化的时候没有
├── entry // 初始化的时候没有
├── package.json
└── src
    └── index.js
  1. 动作不支持本地调试,需要上传,在运行时调试,预览的beta页面上进行 console
// 上传
~ mgx bundle 
// 发布
~ mgx deploy

完成上传后用到action动作的组件会看到新动作插入。

4.2.2 开发

比如要开发一个点击跳转到其他网页的功能。
先编写配置文件

// editor.js
module.exports = {
    // appId: ['0'], // 提供给业务线使用,可选
    actionType: 'custom', // 动作类型
    actionName: 'testaction', // 动作名
    actionDesc: { // 动作描述
      _MDS_KEY: 'desc',
      _MDS_VALUE: '测试动作',
    },
    actionParams: [ // action组件的参数对象,
      {
        cpt_key: 'locationHref',
        desc: {
          _MDS_VALUE: '网址',
        },
        type: 'MagicInput',
        initValue: {
          _MDS_VALUE: '',
        },
        width: '100%',
      },
    ],
   env: ['in', 'out', 'all'], // 执行环境 in 端内 out 端外 all 全部
   hide: false, // 编辑器事件动作配置面板中显示、隐藏
};

代码实现:index.js

function (actionParams,node,extra,args) {
  location.href = actionParams.locationHref;
}

参数说明:

参数名

类型

详情

actionParams

object

编辑器事件动作配置面板,手动配置的参数,静态参数

node

object

schema 节点

extra

object

{
    schemaRenderComponent,
    tool, // 注入tool工具函数
}

args

object

运行时传入的动态参数

4.2.3 action 与组件绑定

使用组件必须在自己的配置文件 editor.js 添加配置项 extra.action,如在 “矩形形状” 组件加入 action 。

action: {
  filterEvent: ['onClick', 'componentDidMount'],
  initValue: [
    {
      options: { env: 'all' },
      eventType: 'onClick',
      eventStop: 'return window.__EDITOR__ === true;',
      hide: true,
    },
  ],
},

打开事件动作弹窗,能看到 自定义的 action -- testaction,触发条件有 点击(onClick)加载(componentDidMount) 的时候。

extra.action 配置

extra: {
    // 值为true时开启将动作代码注入到组件props中的功能, 值为对象时,精确控制可配置的动作类型、参数
    action: true ,// 开启后会将动作配置注入到组件props中

    action: { // 精确配置
        visible:true, // 在编辑器显示动作控制面板,默认为true
      
        filterEvent:['onClick', 'onDoubleClick'], //支持配置的事件,默认所有.
        // 目前魔方支持onClick onDoubleClick, 
        // componentDidMount ,componentWillUnmount onAnimationEnd
        filterType:['jsb', 'goto'],  // 默认所有,与动作的actionType对应支持可配置的动作类型 tool, jsb,go'to
        
        
        //魔方编辑器会将配置的动作代码以eventName名字传入
        // 比如当配置了onClick 这个event对应的action为openLiveRoom , 会将openLiveRoom
        // 对应的代码片段绑定为onClick 作为组件的props传入
    
        initValue: [ // 编辑器动作面板配置的初始值,会依次将对应参数注入到组件props中 ,
        // 当存在多个同名事件时,调用一次, 都会执行。
          eventType: "onAnimationEnd", // 事件名
          eventStop: "return !!window.__EDITOR__" // 不注入到组件props中的场景。代码片段中this指向魔方提供的公用tool
          options: { 
            env: "all" , // 端内外场景  'in'|'out'|'all'
          },
          actionType: "state", // 动作类型 'magicUnifyJsb' 'custom' ... 
          actionName: "resetSchemaByNodeId", // 对应的动作名称
          actionParams: { // 对应动作的参数
            componentId: -1,
            callback: `
              function (props) {
                return { playing: false };
              }
            `,
           hide:false, // 配置该默认值项在编辑器是否可见。
          },
        ] 
    }
}

4.2.4 动作类型

actionType

说明

详情

magicUnifyJsb

魔方统一端能力

动作分类型列表(对外)

custom

自定义动作

动作分类型列表(对外)

4.2.5 端能力调用

务线接入时,会填写业务线对应jsb sdk 的cdn地址和挂载到window对象上的jsb对象名称。魔方在运行时会以script 标签的形式加载该js文件,并将该jsb对象挂载到window.__MAGIC__.action.jsb 这一对象上。业务线在调用端能力时可直接使用该方法。

五、plugin插件开发流程

5.1 插件是啥

插件为业务线的C端页面提供了可插拔的代码植入方式。
通过插件,研发人员可以在页面不同位置植入代码,去执行一些全局定制逻辑。甚至可以替换魔方提供的页面渲染引擎。

5.2 开发流程

5.2.1 初始化

在本地的文件夹中执行 mgx init 进行初始化,选择 plugin 类型。
Image
Image

5.2.2 开发

配置文件

// editor.js
module.exports = {
  appId: ["0"],
  desc: {
    "_MDS_KEY": "desc",
    "_MDS_VALUE": "背景颜色" // 插件名称
  },
  introduction: '改变背景颜色', // 插件功能描述
  position: "bodyBottom", // 插件插入页面位置 headTop、headBottom,bodyBottom, bundle类型可以注释掉
  online: true,
  pluginType: "ejs", // ejs模板,或者是bundle打包
  panelType: 'smartWindow', // 参数填写弹窗类型,目前仅支持 smartWindow
  // 启用插件时,可填写的的参数
  pluginParams: [
    {
      cpt_key: 'color',
      type:'MagicInput',
      initValue:'#ffffff',
      desc: {
        _MDS_VALUE: '背景颜色'
      },
      placeholder: '请输入'
    }
  ],
}

插件文件

<!-- index.ejs -->
<!-- 编写插件内容 -->
<script>
 // 可通过 ejs 的变量语法,获取启用插件时填写的参数,例如:editor.js 中配置了 color 参数,这里通过 <%= color %> 获取
  document.body.style.backgroundColor = '<%= color %>'
</script>

5.2.3 插件类型

pluginType

  • ejs:格式为ejs模板,一般是script标签。
  • bundle:会被打包成单js文件,通过script src引入活动页,有两种bundlerType
    • default:可以是js/ts或者jsx/tsx
  • amd:格式为 export 出一个对象,支持 init、didMount 生命周期

六、常见知识

6.1 如何在本地开发调试

自定义开发的组件,需要经过注册,编译,结合 proxy 代理到页面上。

  1. 切换目录到组件下 cd ~/xxx 若组件是 h5,还需要往下进去h5层,左图就是 cd /input,右图是cd exchange01/h5

Image
Image

  1. 进行组件注册,如果注册过可跳过,注册后进行本地编译进入开发模式。
mgx -v 
mgx register 
mgx dev 
  1. 在顶部编辑的下拉框选择开启socket监听,在右侧tab栏出现本地开发对应组件即说明连接成功

Image
Image

6.2 引入lib库(TypeScript 场景)

如果需要引入lib中的工具库,如tio tool,需要在package.json中添加,然后pnpm install 。

"devDependencies": {    
    "@magic-module/common-lib-bus": "^1.0.2",    
    "@magic-module/common-lib-tio": "^1.0.1",
    "@magic-module/common-lib-tool": "^1.0.6-beta.0"
  },

然后在src同级增加目录typings,里面新增index.d.ts,并声明模块

declare module '@magic-module/common-lib-tio'
declare module '@magic-module/common-lib-tool'

6.3 组件中获取插件信息

插件的开启状态、配置的属性,可在组件中获取,支持在 2 个场景中获取。

  1. H5 编辑器页面获取

在 editor.js 中添加提个隐藏属性,使用 store 获取活动信息,从中获取插件信息。

{
  // ...
  
  props: [
    // ...
    {
      cpt_key: 'plugin_props_a',
      hidden: true,
      filterFunc: function (props, dispatch) {
        // 1. 需要获取数据的插件名称
        const name = '@magic-module/common-plugin-bodycolor'
        
        // 2. 从 store 中获取插件,插件开启后才能获取到
        const plugin = store.getState().config?.activityData?.plugins?.default?.find(item => item.name === name)
        // 3. 获取属性值,比如属性名为 pageNo
        const value = plugin?.params.pageNo
        
        // 4. 将属性值设置到 plugin_props_a 的值中
        // 组件中通过 this.props.plugin_props_a 获取
        if (value) {
          dispatch({
            initValue: value
          })
        }
      }
    }
  ]
  
  // ...
}

在组件首次添加、再次选中时,将执行 filterFunc 进行获取。
所以,如果开启插件后,没有再选中组件,将无法获取。如果是 C 端场景,请使用 C 端获取方式稳定获取。

  1. C 端 H5 页面获取

通过全局变量获取,获取前需要判断是否在编辑器内,编辑器内无法获取。

if (!tool.isEditor()) {
  // 1. 需要获取数据的插件名称
  const name = '@magic-module/common-plugin-bodycolor'
  
  // 2. 获取属性值,比如属性名为 pageNo
  const value = window.__MAGIC__.plugins[name].params.pageNo
}