序
App物件是一個核心的物件之一,它的目的是把一切業務邏輯之外的邏輯全部把它抽象出來,讓業務代碼集中于一個檔案,這樣有助于管理,假如我們把業務的處理演算法分布到services檔案夾中,處理業務的流程放在Page物件中,剩下的事情應該歸屬于App物件了:
- 檔案管理,按需加載,上一篇已經做了介紹,后續彈窗,組件,頁面管理都是一樣思路;
- 路由管理,單頁面重要功能之一,下一篇介紹;
- 影片管理,這一篇介紹;
- 其它配置管理,比如版本號,快取管理等, 這一篇介紹,
需求
假設已經有一個原型物件已經實作了路由管理ReplaceProto物件,我們創建一個App物件,它有以下的功能:
- 版本管理, 讓引入的檔案加上版本號,快取清除;
- 各種檔案管理;
- 影片管理器,
實作思路
根據上面需求,創建一個App物件,代碼如下
function App(name, staticName, currentName, version) {
// 版本管理,可以全域定義,也可以指定,全域定義將版本號掛在index.html上,修改比較方便
version = App.version = App.version || version || Math.random();
this.version = version;
ReplaceProto.call(this, name, staticName, currentName);
// 主要實作
this.animationList = new AnimationList();
// 存盤按需加載管理物件, 上一篇介紹過
this.loadPageUnit = new LoadUnit(this.version);
this.loadComponentUnit = new LoadUnit(this.version);
this.loadPopUpUnit = new LoadUnit(this.version);
}
App.prototype = create(ReplaceProto.prototype, {
constructor: App,
// 增加影片
addAnimation: function (animation) {
this.animationList.add(animation);
},
// 移除影片,htmlProto代表Page物件或Component物件
removeAnimationByTarget: function (htmlProto) {
this.animationList._removeByTarget(htmlProto.uid);
}
});
這里的主要核心在于AnimationList物件的實作,
我們希望AnimationList有以下用途:
- 管理影片,在有影片的時候主動輪循,沒有影片的時候輪循關閉;
- 為了更好的處理,具有暫停恢復等常規功能;
- 提供精確毫秒級的計算,使用requestAnimationFrame,
另外我們希望加入AnimationList的Animation物件有如下功能:
- 精確到毫秒級;
- 提供于css3影片類似的影片方法;
- 能夠影片開始,結束,程序中都可以進行控制和互動,
代碼實作Animation物件
function Animation(time, delay, type) {
BaseProto.call(this);
this.time = time;
// animationType作為影片函式,這里省略不做介紹
this.animationType = type || Animation.linear;
if (type == Animation.normal) this.time = Infinity;
this.delay = delay || 0;
// 計時器物件,簡單實作不做介紹
this.stopwatch = new Stopwatch();
this.ended = false;
};
Animation.prototype = create(BaseProto.prototype, {
constructor: Animation,
//影片開始,如果有系結開始方法,觸發開始方法
_start: function () {
this.stopwatch.start();
this.dispatchEvent("start");
},
// 通過傳入時間值讓影片更新,如果沒有傳入時間值,將會計時器來計算更新
_update: function (elapsed) {
elapsed = elapsed || (this.stopwatch.getElapsedTime() - this.delay);
if (elapsed > 0) {
// 無盡影片,除非手動設定ended
if (this.animationType == Animation.normal) {
if (this.ended) {
this._complete();
return true;
} else {
this.dispatchEvent("update", { elapsed: elapsed });
return false;
}
} else {
if (this.ended || elapsed > this.time) {
this._complete();
return true;
} else {
var k = this.animationType(elapsed, this.time);
this.dispatchEvent("update", { elapsed: k });
return false;
}
}
}
return false;
},
// 影片結束觸發的方法,如果系結結束方法,就會觸發結束方法
_complete: function () {
this.dispatchEvent("complete");
this.stopwatch.stop();
},
// 銷毀影片物件
destroy: function () {
this.eventDispatcher.destroy();
this.stopwatch = null;
}
});
AnimationList的簡單代碼
function AnimationList() {
this.reset();
}
AnimationList.prototype = {
constructor: AnimationList,
// 將影片加入影片序列
add: function (animation) {
// 判斷影片是否再影片序列中,可以防止相同的影片被加入多次
if (!this._contains(animation)) {
animation.stopwatch.reset();
animation._start();
this.animationArray.push(animation);
// 每個添加的Animation都有個target屬性,有助于統一管理包括批量管理
if (!this.animationObj[animation.target]) {
this.animationObj[animation.target] = [animation];
} else {
this.animationObj[animation.target].push(animation);
}
if (!this.running) {
this.running = true;
this.requestId = requestAnimationFrame(this.tick.bind(this));
}
}
},
// 每次更新后呼叫這個方式派發影片的更新方法
tick: function () {
var animationArray = this.animationArray;
var len = animationArray.length;
if (len == 0) {
this.requestId = null;
this.running = false;
return;
}
var removes = [];
for (var i = 0; i < len; i++) {
var aniObj = animationArray[i];
if (!aniObj.stopwatch.running) continue;
if (aniObj._update()) {
removes.push(aniObj);
}
}
for (var i = animationArray.length - 1; i >= 0; i--) {
var a = animationArray[i];
if (removes.indexOf(a) > -1) {
this._remove(a);
}
}
if (animationArray.length > 0)
this.requestId = requestAnimationFrame(this.tick.bind(this));
},
// 移除某個影片物件
_remove: function (animation) {
var animationArray = this.animationArray,
animationObj = this.animationObj,
array = animationObj[animation.target];
var i = animationArray.indexOf(animation);
animationArray.splice(i, 1);
var ii = array.indexOf(animation);
array.splice(ii, 1);
if (array.length == 0) {
delete animationObj[animation.target];
}
// 停止影片輪詢
if (animationArray.length == 0) this.stop(true);
},
// 重置該物件
reset: function () {
this.animationArray = [];
this.animationObj = {};
this.running = false;
this.requestId = null;
},
// 銷毀該物件
destroy: function () {
this.stop();
this.reset();
}
};
案例介紹
將上一章節的內容代碼拷貝下來,并作以下修改
-
修改second.html,添加一個canvas元素
<canvas width="300" height="200" style="width: 300px; height: 200px;"></canvas> -
更改second.js,在init方法中添加代碼
var canvas = this.domList.canvas; var ctx = canvas.getContext("2d"); ctx.strokeStyle = "red"; var animation = new Animation(2000); animation.onUpdate(function (obj) { var elapsed = obj.elapsed; var x = elapsed * canvas.width - 5, y = elapsed * canvas.height - 5; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.beginPath(); ctx.arc(x, y, 5, 0, Math.PI * 2, false); ctx.stroke(); console.log(obj); }).onComplete(function () { console.log("end"); }); this.addAnimation(animation); -
查看效果 (主要針對移動端,可以通過手機端查看或者用瀏覽器模擬移動端),將代碼放在可以訪問的服務器或本地服務上,啟動服務,通過瀏覽器訪問 如下地址
結語
主要介紹了App物件的作用,以及與全域影片的關系,深入的決議了影片的原理實作
推廣
底層框架開源地址:https://gitee.com/string-for-100w/string
演示網站: https://www.renxuan.tech/
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/172608.html
標籤:JavaScript
上一篇:2.模塊化開發
下一篇:6.Page物件詳解
