易企秀前端压缩源码分析与还原

你是否想知道易企秀炫酷的H5是如何实现的,原理是什么,本文会为你揭秘并还原压缩过的源代码。

易企秀是一款h5页面制作工具,因方便易用成为业界标杆。后续一个项目会用到类似易企秀这样的自定义H5的功能,因此首先分析下易企秀的前端代码,看看他们是怎么实现的,再取其精华去其糟粕。
由于代码较多,且是压缩处理过的,阅读和还原起来较为困难,不过可以先大概分析下原理,然后有针对性的看主要代码,并借助VS Code等工具对变量、函数进行重命名,稍微耐心一点就能大概还原源代码。

分析数据模型

前端分析第一步,看看易企秀的数据模型:

数据模型

dataList是页面配置信息,elemengts是页面元素的配置信息,obj是H5的配置信息,

加载流程分析

查看H5源代码,发现入口函数是:

 eqShow.bootstrap();

顺藤摸瓜,大概分析下,主要流程如下:

加载主要流程

主要的功能函数在eqxiu和window对象下面,其中的重点是parsePage、renderPage和app,下面一一来分析。

parsePage

先看主要代码(重命名后的),主要功能是为每一页生成一个section并appendTo(".nr"),另外如果页面有特效,加载相关js库并执行,最后再renderPage。

function parsePage(dataList, response) {

        for (var pageIndex = 1; pageIndex <= dataList.length; pageIndex++) {
            // 分页容器
            $('<section class="main-page"><div class="m-img" id="page' + pageIndex + '"></div></section>').appendTo(".nr");

            if (10 == pageMode) {
                $("#page" + pageIndex).parent(".main-page").wrap('<div class="flip-mask" id="flip' + pageIndex + '"></div>'),
                    $(".main-page").css({
                        width: $(".nr").width() + "px",
                        height: $(".nr").height() + "px"
                    });
            }

            if (dataList.length > 1 && 14 != pageMode && !response.obj.property.forbidHandFlip) {
                if (0 == pageMode || 1 == pageMode || 2 == pageMode || 6 == pageMode || 7 == pageMode ||
                    8 == pageMode || 11 == pageMode || 12 == pageMode || 13 == pageMode || 14 == pageMode) {
                    $('<section class="u-arrow-bottom"><div class="pre-wrap"><div class="pre-box1"><div class="pre1"></div></div><div class="pre-box2"><div class="pre2"></div></div></div></section>')
                        .appendTo("#page" + pageIndex)
                } else if (3 == pageMode || 4 == pageMode || 5 == pageMode || 9 == pageMode || 10 == pageMode) {
                    $('<section class="u-arrow-right"><div class="pre-wrap-right"><div class="pre-box3"><div class="pre3"></div></div><div class="pre-box4"><div class="pre4"></div></div></div></section>')
                        .appendTo("#page" + pageIndex);
                }
            }

        
          ....
         renderPage(eqShow, pageIndex, dataList);

                // 最后一页
                if (pageIndex == dataList.length) {
                    eqxiu.app($(".nr"), response.obj.pageMode, dataList, response);
                    addEnabledClassToPageCtrl(response);
                }
            }

        }

        hasSymbols || addReportToLastPage(dataList, response);
    }

渲染页面和组件

parsePage搭建了页面框架,renderPage实现页面渲染。

rendepage里,核心代码是:

eqShow.templateParser("jsonParser").parse({
    def: dataList[pageIndex - 1],
    appendTo: "#page" + pageIndex,
    mode: "view",
    disEvent: disEvent
});

templateParser负责将页面上的elements还原为组件,因此这里核心是要了解下templateParser,大致还原的代码如下:

            var jsonTemplateParser = eqShow.templateParser("jsonParser", function () {

                function createContainerFunction(container) {
                    return function (key, value) {
                        container[key] = value
                    }
                }

                function wrapComp(element, mode) {
                    try {
                        var comp = components[("" + element.type).charAt(0)](element, mode)
                    } catch (e) {
                        return
                    }
                    if (comp) {
                        var elementContainer = $('<li comp-drag comp-rotate class="comp-resize comp-rotate inside" id="inside_' + element.id + '" num="' +
                                element.num + '" ctype="' + element.type + '"></li>'),
                            elementType = ("" + element.type).charAt(0);

                        if ("3" !== elementType && "1" !== elementType) {
                            elementContainer.attr("comp-resize", "")
                        }

                        // 组件类型
                        /**
                         *  2 文本
                         *  3 背景
                         *  9 音乐
                         *  v video
                         *  4 图片
                         *  h shape形状
                         *  p 图集
                         *  5 输入框
                         *  r radio
                         *  c checkbox
                         *  z 多选按钮
                         *  a 评分组件
                         *  b 留言板
                         *  6 提交按钮
                         */
                        switch (elementType) {
                            case "p":
                                elementContainer.removeAttr("comp-rotate");
                                break;
                            case "1":
                                elementContainer.removeAttr("comp-drag");
                                break;
                            case "2": // 文本
                                elementContainer.addClass("wsite-text");
                                break;
                            case "3":
                                // 背景
                                break;
                            case "x":
                                elementContainer.addClass("show-text");
                                break;
                            case "4":
                                // image
                                element.properties.imgStyle && $(comp).css(element.properties.imgStyle), elementContainer.addClass("wsite-image");
                                break;
                            case "n":
                                elementContainer.addClass("wsite-image");
                                break;
                            case "h":
                                elementContainer.addClass("wsite-shape")
                                break;
                            case "5":
                                elementContainer.removeAttr("comp-input");
                                break;
                            case "6":
                            case "8":
                                elementContainer.removeAttr("comp-button");
                                break;
                            case "v":
                                elementContainer.removeAttr("comp-video");
                                elementContainer.addClass("wsite-video");
                                if (element.properties && element.properties.lock) {
                                    elementContainer.addClass("alock")
                                }
                                break;
                            case "b":
                                elementContainer.removeAttr("comp-boards");
                                elementContainer.attr("min-h", 60),
                                    elementContainer.attr("min-w", 230);
                                break;
                            default:
                                break;
                        }

                        elementContainer.mouseenter(function () {
                                $(this).addClass("inside-hover")
                            }),
                            elementContainer.mouseleave(function () {
                                $(this).removeClass("inside-hover")
                            });

                        // edit或者非文本type,再套一层
                        if ("edit" === jsonTemplateParser.mode || "x" !== ("" + element.type).charAt(0)) {
                            var elementBoxContent = $('<div class="element-box-contents">'),
                                elementBox = $('<div class="element-box">').append(elementBoxContent.append(comp));
                            elementContainer.append(elementBox),
                                "5" !== ("" + element.type).charAt(0) && "6" !== ("" + element.type).charAt(0) && "r" !== element.type && "c" !== element.type && "a" !== element.type && "8" !== element.type && "l" !== element.type && "s" !== element.type && "i" !== element.type && "h" !== element.type && "z" !== element.type || "edit" !== mode || $(comp).before($('<div class="element" style="position: absolute; height: 100%; width: 100%;z-index: 1;">'))
                        }

                        // 文本类型,处理font
                        var k, eleFonts = element.fonts || element.css.fontFamily || element.fontFamily;
                        if ("2" === elementType || "x" === elementType) {
                            for (var content = element.content, font_pattern = /font-family:(.*?);/g, matchResults = [], fonts = []; null !== (matchResults = font_pattern.exec(content));)
                                fonts.push(matchResults[1].trim());
                            if (1 !== fonts.length || "defaultFont" !== fonts[0] && "moren" !== fonts[0] || (eleFonts = null),
                                eleFonts) {
                                if ("view" === jsonTemplateParser.mode && element.css.fontFamily && window.scene && (window.scene.publishTime || !mobilecheck() && !tabletCheck() || (k = "@font-face{font-family:" + element.css.fontFamily + ';src: url("' + element.properties.localFontPath + '") format("truetype");}',
                                     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值