想必你必定使用過易企秀或其它微場景生成工具製做過炫酷的h5頁面,除了感嘆其神奇之處有沒有想過其實現方式呢?
從設計者的角度來看待問題,會有不同的收穫,本文將從零開始,使用node技術來設計實現一款精簡版的易企秀javascript
自動化/可視化工具的實現,無不是大量重複實例的一種模板化,微場景生成工具也不例外,因此首先須要探討具體的一個微場景是怎麼實現的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
所謂模板化,無非是在重複實例中提取共性的東西定義數據模型,而且使用模板標籤來描述,渲染的過程當中用數據填充模板佔位符
在此選用了nunjucks做爲模板引擎web
咱們先來分析下,微場景頁面的組成部分:
因而數據模型能夠定義爲:
//頁面數據
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 // 去掉過多的空行
}));複製代碼
在上一步模板化以後,咱們已經能夠根據數據和模板生成場景實例,那麼前端可視化操做要作什麼就比較清晰了,前端可視化操做的目的在於根據數據模型構造數據實例,前端的可視化操做應該包括設置每一屏的背景色/背景圖片,而且能夠增長或刪除一頁,在每一屏中能夠增長文本或者圖片項目,而且設置對應的屬性
在此採用了以上兩圖的設計風格:
一樣的,咱們要將任務分解:
這些個步驟每一步要寫的話,篇幅均可以長到獨立成文,例如,另外一篇文章:div拖拽縮放jquery插件編寫——帶8個控制點已經詳細說過,本文就再也不拓展,若是有須要,能夠私信我,有必要再整理
經過前端可視化的操做,構造數據模型實例,傳入後臺,後臺再經過上一步的模板進行渲染,那麼整一個核心功能就走通了~~~
其它的入庫保存,展現,預覽功能,則是須要慢慢豐富的過程
先把核心骨架搭建完畢,再去豐富皮肉,是一個軟件從無到有的重要心法
本文重在說明設計步驟和實現思路,省去了不少實現細節,並不是面面俱到,而且也不方便公佈全部源代碼,更細緻的討論,能夠私信我,定盡力解答。
本文方法論:
1)任務分解
2)實例模板化
3)核心骨架搭建、再豐富皮肉功能