# 第4节 api与callback调用场景示例



## 4.1 API

### 4.1.1 调用方式

    在js方法中 var api = new MagicalApi();
    即可使用api.getHtml();等各种方法

### 4.1.2 详情路径

    可参考 magicaldrag/assets/drag/js/user/api.js

### 4.1.3 接口详情

    /**
     * 获取布局器HTML源码
     */
    string getHtml()


    /**
     * 获取布局器脚本
     */
    string getJavascript()


    /**
     * 获取布局器根节点json
     */
    object getRootNode()


    /**
     * 能获取表单条目下的控件数据
     */
    object[] getFormItemNodes()


    /**
     * 插入源码到布局器
     * @param html
     */
    void insertHtml(html)


    /**
     * 插入javascript脚本 请尽量在insertHtml方法之后执行 因为大部分脚本操作的是html 必须先有html
     * @param javascript
     */
    void insertJavascript(javascript)


    /**
     * 插入html javascript 常用于初始化布局器
     * @param html
     * @param javascript
     */
    void insert(html,javascript)


    /*根据root 还原布局器*/
    void insertNode(rootNode)


    /**
     * 聚焦某个结构
     * @param magicalCoderIds 数组[] 结构的唯一magicalCoder.id
     */
    void focus(magicalCoderIds)


    /**
     * 获取constatn.js实例
     * 这样就可以灵活的根据事件情况来调整配置
     */
    object getConstant()


    /**
     * 获取iframe-ui.js实例
     * 这样就可以灵活的根据事件情况来调整配置
     */
    object getIframeUi()


    /**
     * 把html转换成magicalCoderNode数据
     * @param html
     */
    object htmlToRootNode(html)


    /**
     * 把magicalCoder node数据转换成html
     * @param nodes [] 数组 可以通过rootNode.magicalCoder.children传入
     * @param htmlWithMagicalCoderAttr true|false 是否包含magicalcode属性 默认false
     */
    string nodesToHtml(nodes,htmlWithMagicalCoderAttr)


    /**
     * 重新设置孩子节点 比如您想在某个节点插入html 那么可以先把html调用htmlToRootNode得到node,
     * 然后childrenNodes = node.magicalCoder.children; 然后就可以调用此方法了 一般用在回调处理上
     * @param parentId 父节点magicalCoder.Id string
     * @param childrenNodes 子节点数组 []
     */
    void resetChildren(parentId,childrenNodes)


    /**
     * 主动触发布局器重绘工作区
     */
    void refreshWorkspace()


    /**
     * 仅仅把中间html重绘 并不触发节点变更
     */
    void onlyCenterRefreshHtml()


    /**
     * 根据magicalCoderParam查询结构
     * @param fromNode 从哪个节点开始往下搜索 如果为null 则默认从根节点
     * @param magicalCoderParam 查询参数例如 查看node.magicalCoder属性即可得知参数 {id:1,....}
     * return []
     */
    object[] searchNodes(fromNode,magicalCoderParam)


    /**
     * 重新构造左侧组件列表:如果您动态的向左侧增删组件 可以使用此方法
     * 您只需要修改完constant中的配置后 直接调用此方法 无法额外调用constant.refresh();
     */
    void rebuildLeftComponents()


    /**
     * 刷新拖拽事件
     */
    void refreshDragEvent()


    /**
     * 刷新右侧属性面板
     * @param magicalCoderId
     */
    void refreshRightAttrPane(magicalCoderId)


    /**
     * 在节点中追加html
     * @param node
     * @param html
     * @return true|false
     */
    void appendHtml(parentNode,html,preNode)


    /**
     * 删除多个节点
     * @param nodes []
     */
    void deleteNodes(nodes)


    /**
     * 查找前置节点
     * @param node
     */
    object findPreNode(magicalCoderId)


    /**
     * 查找后置节点
     * @param node
     */
    object findNextNode(magicalCoderId)


    /**
     * 查找父亲节点
     * @param magicalCoderId
     */
    object findParentNode(magicalCoderId)


    /**
     * 移动节点
     * @param dragMcId 要移动的id
     * @param targetMcId 目标id
     * @param moveType inner prev next
     */
    void moveExistNode(dragMcId, targetMcId, moveType)


## 4.2 CALLBACK 回调

### 4.2.1 调用方式

    由于布局器会持续不断升级，但是我们的api 回调等会向前兼容，如果您直接把业务代码写在callback.js
    更新代码会覆盖callback.js,要么就需要自己合并，耗费时间


    正确的做法是：
        1 重写callback.js提供的方法 新建一个您自己的js 在里面重写callback.js提供的方法
        比如 保存按钮点击
        MagicalCallback.prototype.save_html = function (html,rootNode,vueData) {
            //加入你自己的逻辑:保存到数据库等等
        }
        //布局器加载完成 会自动调用此方法
        MagicalCallback.prototype.after_start = function (api) {
            //您可以根据浏览器的入参，来初始化获取数据库保存的数据，可以使用api.insertHtml(您的html)来初始化布局器
        }

        2 在index-xxx.html的callback.js后紧跟着引入此文件 这样就把callback.js的部分方法重写了 记得参数和名称一定要一致
        例如：
        <script type="text/javascript" src="assets/drag/js/user/callback.js"></script>
        <script type="text/javascript" src="assets/drag/js/user/my-callback.js"></script>


    原理：浏览器在加载完callabck.js后 加载到save_html
         那么当我们让浏览器继续加载我们的my-callback.js
            MagicalCallback.prototype.save_html = function (html,rootNode,vueData) {
                //加入你自己的逻辑:保存到数据库等等
            }
         那么callback.js中的
         MagicalCallback.prototype.save_html = function (html,rootNode,vueData) {}
         就失效了，转而让my-callback.js中的save_html 生效


### 4.2.2 详情路径
    magicaldrag/assets/drag/js/user/calllback.js

### 4.2.3 接口详情

    /**
     * 初始化布局器成功后执行：您可以调用api.insert(html,javascript)来初始化布局器的默认数据
     * @param api 接口api对象 具体方法参考api.js
     */
    MagicalCallback.prototype.after_start = function (api) {
    }


    /**
     * 保存按钮
     * @param html 源码部分
     * @param rootNode 当前布局器JSON
     * @param javascript 脚本
     */
    MagicalCallback.prototype.save_html = function (html,rootNode,javascript) {
    }


    /**
     * 扩展配置钩子 这里做一些demo 注意请不要删除此demo 因为是图标的扩展配置
     * @param uiType 当前ui类型 在Constant.getUiType配置
     * @param configElem 右侧面板中 当前扩展配置按钮 左侧的dom结构
     * @param rightPanelItemObj 配置条目  {type:this.type.TEXT      ,clearAttr:true       ,oneLine:true     ,change:this.change.CLASS   ,title:'图标',extend:true    }
     * @param focusNode 聚焦结构 调试查看 attributes是结构的各种属性
     * @param callback(attrName,attrValue) 记得回调
     */
    MagicalCallback.prototype.extend_config = function (uiType,configElem,rightPanelItemObj,focusNode,callback) {
        //您可以在这里初始化你自己的控件,使用layui.open弹窗方式打开 参考 https://www.layui.com/doc/modules/layer.html
        if(rightPanelItemObj.extendKey =='icon'){

        }else {

        }
    }


    /**
     * 右侧属性配置属性变更前的回调事件 变更非文本
     * @param obj.focusNode 当前聚焦的节点
     * @param obj.changeAttrName 修改的属性名
     * @param obj.changeAttrValue 修改后的属性值
     * @param obj.originAttrValue 修改前的属性值
     * @param obj.itemObj 配置属性
     */
    MagicalCallback.prototype.before_change_attr_callback = function (obj) {return true;}


    /**
     * 右侧属性配置属性变更后的回调事件 变更非文本
     * @param obj.focusNode 当前聚焦的节点
     * @param obj.changeAttrName 修改的属性名
     * @param obj.changeAttrValue 修改后的属性值
     * @param obj.originAttrValue 修改前的属性值
     * @param obj.itemObj 配置属性
     */
    MagicalCallback.prototype.after_change_attr_callback = function (obj) {}


    /**
     * 右侧属性配置属性变更前的回调事件 注意变更文本（就是结构内的文本 change:this.change.TEXT）
     * @param obj.focusNode 当前聚焦的节点
     * @param obj.changeAttrName null
     * @param obj.changeAttrValue 修改后的文本值
     * @param obj.originAttrValue 修改前的文本值
     * @param obj.itemObj 配置属性
     */
    MagicalCallback.prototype.before_change_text_callback = function (obj) {return true;}


    /**
     * 右侧属性配置属性变更后的回调事件 注意变更文本（就是结构内的文本 change:this.change.TEXT）
     * @param obj.focusNode 当前聚焦的节点
     * @param obj.changeAttrName null
     * @param obj.changeAttrValue 修改后的文本值
     * @param obj.originAttrValue 修改前的文本值
     * @param obj.itemObj 配置属性
     */
    MagicalCallback.prototype.after_change_text_callback = function (obj) {}


    /**
     * 布局器顶端重置按钮点击之前
     */
    MagicalCallback.prototype.reset_before = function () {}


    /**
     * 布局器顶端重置按钮点击后
     */
    MagicalCallback.prototype.reset_after = function () {}


    /**
     * 构建右侧属性面板
     * @param focusNode
     * @return  true:继续构建 false:终止构建
     */
    MagicalCallback.prototype.pre_build_attrs = function (focusNode) {
        return true;
    }


    /**
     * 当工作区变更后：比如拖拽 删除 等操作触发的
     * 请不要跟api.refreshWorkspace()配合使用 否则就会无限递归死循环
     * 可配合onlyCenterRefreshHtml把您修改的节点属性绘制出来
     */
    MagicalCallback.prototype.after_workspace_change = function () {}


# 4.3 示例场景(陆续添加中)

    下面就让我们来看一下这类场景如何实现

## 4.3.1 示例一、动态从后端加载数据 放到右侧属性中

### 4.3.1.1思路

    首先我们知道 属性都在constant.js的this.rightPanel中控制的，
    也就是说 只要我们在布局器加载完毕后(1)，使用ajax向后端请求数据，
    然后去更新constant.js中this.rightPanel的结构就能解决问题(2)

### 4.3.1.2 可能用到的api和callback

    1 callback.js
    MagicalCallback.prototype.after_start = function (api) {
    }
    2 api.js
    getConstant();

### 4.3.1.3 实现示例参考



    此为markdown文档，请使用Typora软件访问 或者支持markdown的软件皆可
