從零打造在線版H5頁面生成器

想必你必定使用過易企秀或其它微場景生成工具製做過炫酷的h5頁面,除了感嘆其神奇之處有沒有想過其實現方式呢?
從設計者的角度來看待問題,會有不同的收穫,本文將從零開始,使用node技術來設計實現一款精簡版的易企秀javascript

Github: 傳送門
演示地址:傳送門css

目錄

  1. 實例實現
  2. 實例模板化與渲染
  3. 前端可視化操做
  4. 總結

1、實例實現

自動化/可視化工具的實現,無不是大量重複實例的一種模板化,微場景生成工具也不例外,因此首先須要探討具體的一個微場景是怎麼實現的html

來看下面這個實例:前端

要實現這樣的場景,咱們首先得把任務分解下:java

1) 佈局:整個場景能夠分爲不少屏(頁),每一屏上有動畫元素(文字/圖片)node

<!-- --------------html---------- -->
    <div class="page-box" id="page1">
        <div class="item page1-item1">
            ...
        </div>
        <div class="item page1-item2">
            ...
        </div>
        <div class="pre-item">
            ...
        </div>
    </div>
    <div class="page-box" id="page2">
        <div class="item page2-item1" data-cls="bounceIn1000" data-ts="0">
            ...
        </div>
        <div class="item page2-item2" data-cls="bounceIn1000" data-ts="1000">
            ...
        </div>
        <div class="pre-item">
            ...
        </div>
    </div>


    <!-- --------------css---------- -->
    // 每一屏(page-box)都是absolute佈局,便於爲每屏增長入場出場動畫(減小重繪重排)
    // 每一屏寬高皆爲100%,默認隱藏,入場增長入場動畫,並設置爲可見
    .page-box {
        position: absolute;
        top: 0;
        z-index: 1;
        width: 100%;
        height: 100%;
        visibility: hidden;
        background: no-repeat center center #FFFFFF;
        background-size: 100% 100%;
    }

    .page-box.show {
        visibility: visible;
    }
    // 屏內動畫項目,也都採用abasolute佈局,just由於,是動畫元素
    .item {
        position: absolute;
        background-repeat: no-repeat;
        opacity: 0;
        text-align: center;
    }複製代碼

2) 屏間切換:事件觸發,過渡動畫jquery

/** * 下滑手勢,頁面上翻 * 上一屏(prev)增長入場動畫slideZoom_tInt,本屏增長離場動畫slideZoom_tOut */
    pre: function() {
        var $el = $(".page-box.show");
        var $prev = $el.prev(".page-box")[0] ? $el.prev() : $(".page-box").last();
        $prev.addClass("show").show().css({
            "-webkit-animation":"slideZoom_tInt 0.5s linear",
            "animation":"slideZoom_tInt 0.5s linear"    
        });
        $el.css({
            "-webkit-animation":"slideZoom_tOut 0.5s linear",
            "animation":"slideZoom_tOut 0.5s linear"
        });
        setTimeout(function(){
            $el.removeClass("show");
            ...
        },500);
    }

    /** * 滑動事件監聽 */
    //控制滑動
    //不由止默認事件 他丫的不能滑
    document.addEventListener('touchmove', function(event) {
        event.preventDefault();
    }, false);
    $(document).on('swipeUp', function() {
        slider.next();
    }).on('swipeDown', function() {
        //手勢下滑,向上翻頁
        slider.pre();
    });複製代碼

3) 屏內項目控制(文字和圖片):引入動畫庫animate.css來設置屏內項目的動畫效果(因此說是精簡版易企秀)git

/** * 動畫效果控制,動畫效果播放、時間間隔 */

    //動畫一個個播放,遞歸調用
    var i = 0;
    function startShow(callback) {
        if(i === itemLength){
            callback && callback();
            return ;
        }
        var item = items.eq(i);
        var cls = item.attr('data-cls');//動畫類
        var ts = item.attr('data-ts');//下一個動畫開始間隔時間
        item.addClass(cls);
        i++;
        setTimeout(function() {
            startShow(callback);
        },ts);
    };

    //播放某一屏的動畫
    function showItem(id, callback) {
        var self = this;
        i = 0;
        items =  $('#' + id + " .item");
        itemLength = items.length;
        if(!callback) {
            callback = function() {
                self.showPreItem(id);
            }
        }
        startShow(callback);
    },複製代碼

4) 頁面加載進度控制:阻塞頁面加載進度的無非圖片,枚舉頁面使用到的全部圖片(可使用程序遍歷目錄),判斷Image對象的complete狀態或者監聽onload事件來判斷圖片是否加載完成,篇幅緣由,代碼就不貼出來了github

2、實例模板化與渲染

所謂模板化,無非是在重複實例中提取共性的東西定義數據模型,而且使用模板標籤來描述,渲染的過程當中用數據填充模板佔位符
在此選用了nunjucks做爲模板引擎web

咱們先來分析下,微場景頁面的組成部分:

  1. 屏/頁(page-box):背景色、背景圖片、入場動畫和出場動畫
  2. 屏內項目:位置、寬高、透明度、動畫類、動畫持續時間、下一個動畫的間隔時間、圖片路徑/文字以及文字效果

因而數據模型能夠定義爲:

//頁面數據
    pages: [
        {
            burl: String, //背景圖片
            inAnimate: String,
            outAnimate: String,
            bgColor: String,
            items: [ //頁面項目
                {
                    px: String, //位置x 必選
                    py: String, //位置y 必選
                    width: String, //寬度 必選
                    height: String, //高度 必選
                    transparent: String,//透明度 可選
                    animateClass: String,//動畫 可選
                    animateDuration: String, //動畫持續時間,默認2000
                    nextAnimateTime: String, //下一個item動畫開始的時間間隔
                    zIndex: String, //可選
                    imgUrl: String,// 圖片路徑 //可選
                    text: String, //文本
                    textStyle: {
                        'color': String,
                        'font-size': String
                    }
                }
                ...
            ]
        },
        {
            ...
        }
        ...
    ]複製代碼

根據數據模型來編寫模板

<!-- ---------html模板片斷--------- -->
    //遍歷pages生成每一屏的div
    //遍歷page的items生成動畫項目div
    {% set i = 0 %}
    {% for page in pages %}
        {% set i = i+1 %}
        {% set j = 0 %}
        <div class="page-box" id="page{{i}}">
            {% for item in page.items %}
                {% set j = j+1 %}
                <div class="item page{{i}}-item{{j}}" data-cls="{{ item.animateClass }}{{item.animateDuration}}" {% if item.nextAnimateTime %} data-ts="{{ item.nextAnimateTime }}" {% else %} data-ts="500" {% endif %}  >
                    {% if item.text %}
                        {{ item.text }}
                    {% endif %}
                    {% if item.imgUrl %}
                        ![]({{ item.imgUrl }})
                    {% endif %}
                </div>
            {% endfor %}
            <div class="pre-item"><div class="pre-wrap"><div class="pre-box1"><div class="pre1"></div></div><div class="pre-box2"><div class="pre2"></div></div></div></div>
        </div>  
    {% endfor %}

    <!-- ---------css模板片斷--------- -->
    /************* item style ***********************/
    {% set i = 0 %}
    {% for page in pages %}
        {% set i = i+1 %}
        {% set j = 0 %}
        #page{{i}} {
            {% if page.burl %}
                background-image: url({{page.burl}});
            {% endif %}
            background-color: {{page.bgColor}};
        }
        {% for item in page.items %}
            {% set j = j+1 %}
            .page{{i}}-item{{j}} {
                width: rem({{item.width}});
                height: rem({{item.height}});
                left: rem({{item.px}});
                top: rem({{item.py}});
                {% for key, value in item.textStyle %}
                    {{key}}: {{value}};
                {% endfor %}
            }
        {% endfor %}
    {% endfor %}

    //這裏要重點說明的,數據模型中的全部item對應的,動畫類和持續時長做爲key值
    //去重以後,構造animateClasses對象,遍歷該對象,生成相應的動畫類
    //例如動畫類bounceIn1000:就表示動畫庫中的bounceIn,而且持續時長1000毫秒
    /**************** animate class **************************/
    {% for cname, cvalue in animateClasses %}
        .{{cname}} {
            -webkit-animation: {{cvalue.ac}} {{cvalue.ad}}s ease 1 both;
            -webkit-animation-play-state: initial;  
            animation: {{cvalue.ac}} {{cvalue.ad}}s ease 1 both;
            animation-play-state: initial;
            opacity: {% if cvalue.isOut %}0 {% else %} 1 {% endif %};
        }
    {% endfor %}複製代碼

渲染過程:
1) 複製用到的圖片
2) rem預處理
3) 根據數據渲染模板

/**************build代碼片斷*************************/
    //解析view
    var content = htmlTemplate.render('view.html', config);
    utils.createFile(target + '/view.html', beautify_html(content, {
        'max_preserve_newlines': 0 // 去掉過多的空行
    }));
    //解析樣式
    var styleContent = htmlTemplate.render('css/style.css', config);
    utils.createFile(target + '/css/style.css', beautify_css(px2rem(styleContent), {
        'max_preserve_newlines': 1 // 去掉過多的空行
    }));

    //解析main.js
    var mainJsContent = htmlTemplate.render('js/main.js', {
        list: images
    });
    utils.createFile(target + '/js/main.js', beautify_js(mainJsContent, {
        'max_preserve_newlines': 1 // 去掉過多的空行
    }));複製代碼

3、前端可視化操做

在上一步模板化以後,咱們已經能夠根據數據和模板生成場景實例,那麼前端可視化操做要作什麼就比較清晰了,前端可視化操做的目的在於根據數據模型構造數據實例,前端的可視化操做應該包括設置每一屏的背景色/背景圖片,而且能夠增長或刪除一頁,在每一屏中能夠增長文本或者圖片項目,而且設置對應的屬性

編輯屏

編輯動畫項目

在此採用了以上兩圖的設計風格:

  1. 頂部文本和圖片按鈕能夠爲當前page增長文本和圖片
  2. 左側控制屏/頁的增刪,以及切換當前編輯屏/頁
  3. 中部爲編輯舞臺,顯示當前屏/頁的背景以及項目
  4. 右側爲屬性設置面板,當屏/頁得到焦點,編輯的是屏/頁屬性(背景和入場出場動畫),當動畫項目(文本或者圖片),編輯的是動畫項目的屬性

一樣的,咱們要將任務分解:

  1. 控制page增刪與切換,屬性設置的Page.js
  2. 控制文本項目增刪,屬性設置的textItem.js
  3. 控制圖片項目增刪,屬性設置的imageItem.js
  4. 右側屬性設置面板控制rTab.js
  5. 拖拽控制ZResize.js
  6. 圖片上傳ZUpload.js

    這些個步驟每一步要寫的話,篇幅均可以長到獨立成文,例如,另外一篇文章:div拖拽縮放jquery插件編寫——帶8個控制點已經詳細說過,本文就再也不拓展,若是有須要,能夠私信我,有必要再整理

經過前端可視化的操做,構造數據模型實例,傳入後臺,後臺再經過上一步的模板進行渲染,那麼整一個核心功能就走通了~~~

其它的入庫保存,展現,預覽功能,則是須要慢慢豐富的過程

先把核心骨架搭建完畢,再去豐富皮肉,是一個軟件從無到有的重要心法

4、總結

本文重在說明設計步驟和實現思路,省去了不少實現細節,並不是面面俱到,而且也不方便公佈全部源代碼,更細緻的討論,能夠私信我,定盡力解答。

本文方法論:
1)任務分解
2)實例模板化
3)核心骨架搭建、再豐富皮肉功能

公衆號:菲麥前端
相關文章
相關標籤/搜索