前言
在去年12月份剛開始學(xué)習(xí)編程的時候,看到這樣一句話:“初學(xué)者不要寫博客茬祷,要多記筆記清焕。”
細(xì)想言之有理祭犯,便沒有申請博客秸妥,開始在Onenote上記錄各種網(wǎng)上復(fù)制下來的筆記。
然而過了沒多久沃粗,又看到這么一句話:“好的代碼就相當(dāng)于筆記粥惧。”
細(xì)想亦言之有理最盅,便停了onenote的筆記突雪,導(dǎo)致在這半年多的時間里除了代碼基本上沒有寫過些什么。
而在前兩天檩禾,發(fā)布了自己的第一個npm包之后挂签,覺得似乎應(yīng)該記錄下自己編寫代碼和發(fā)布包的過程中遇到的問題,順便發(fā)布項目Demo盼产,
便花一天時間開始一步步折騰搞定github pages饵婆,hexo,和域名之類。
項目預(yù)覽及地址
功能:Youtube之類網(wǎng)站在進(jìn)行ajax請求時頂部出現(xiàn)的載入條
為什么要寫這個項目
之前在一個天氣預(yù)報App的Demo侨核,搜索然后ajax請求是基本功能草穆,請求過程中就想到了實現(xiàn)載入效果,便在github上尋找開源項目搓译。
因為希望這個天氣預(yù)報App盡量輕便(使用了React悲柱,撇除React-Router及Redux之類),所以放棄一些包含各種載入效果的庫些己,
最后使用了Nprogress和Nanobar兩個功能簡單的庫豌鸡。
這倆個庫相比較,Nanobar體積更小段标,功能更簡單(只有一個go函數(shù))涯冠,Nprogress則更漂亮(有一個peg元素,制造了box-shadow陰影)逼庞,
可以調(diào)用的函數(shù)也更多(有漸漸載入的效果)蛇更。
但是這兩個庫年代都比較久遠(yuǎn),都沒有選擇構(gòu)造函數(shù)來創(chuàng)建對象赛糟,所有函數(shù)都沒有綁在原型鏈上(當(dāng)然對于這種功能簡單的庫來說沒有什么大的影響)派任、
都是使用setTimeout方式實現(xiàn)動畫(當(dāng)然對這種簡單的動畫也沒有什么大的影響)、都需要引入css文件使用transform作為實現(xiàn)動畫效果的輔助璧南。
最終在參考了兩個庫的源代碼后決定自己寫一個掌逛。
在項目中遇到的問題和解決方法
構(gòu)造函數(shù)、打包工具
使用ES6 class
構(gòu)造對象司倚,使用rollup
打包成umd
形式的函數(shù)颤诀。
rollup
在打包之后不是生成傳統(tǒng)的Object.prototype
形式,而是定義了一個createClass
函數(shù)
var createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
動畫函數(shù)
使用window.requestAnimationFrame
來進(jìn)行動畫对湃,使用了一般通用的polyfill
const rAF = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) { window.setTimeout(callback, 1000 / 60); };
setTimeout
函數(shù)間隔為1000 / 60以滿足幀數(shù)。
合并對象
在庫中使用了Object.assign
函數(shù)合并對象遗淳,該函數(shù)有瀏覽器兼容問題拍柒,需要額外使用babel
插件進(jìn)行編譯。
一般比較大的庫都會定義自己的merge
函數(shù)屈暗,lodash
或underscore
也定義了合并函數(shù)拆讯,另外ES6
有實驗性質(zhì)的展開對象合并的方法芯杀,
這應(yīng)該也是極為遙遠(yuǎn)的將來展開和合并對象的標(biāo)準(zhǔn)方法
限制對象屬性的值
渲染進(jìn)度條最重要的是確定什么時候渲染完成蜒什,按照邏輯來說進(jìn)度條達(dá)到最大值的時候就應(yīng)該淡出继准,
用代碼表示就應(yīng)該是if (this.barWidth === this.maxWidth) this.stop();
煮盼,
但實際運行中發(fā)現(xiàn)由于遞增barWidth
使用的是緩動函數(shù)澡匪,
所以barWidth
未必會接觸到maxBarWitdh
缝左,可能上一幀在99.8%温自,下一幀卻出現(xiàn)在100.2%已维。
nanobar
解決這個問題是直接重新創(chuàng)建實例
if (p >= 100) {
init()
}
這個方式可能有點太粗暴了淆攻。而我最終選擇的是Object.defineProperty
方法:
Object.defineProperties(this, {
// constant max width
'maxWidth': { value: 100 },
// limit bar width
'barWidth': {
get() { return barWidth; },
set(value) {
if (value <= 0) value = 0;
// set to 0 if width touch 100%
if (value >= 100) value = 100;
barWidth = value;
}
}
});
一旦barWidht
超過100阔墩,就會被設(shè)置成100嘿架,進(jìn)而出發(fā)stop
函數(shù)。
當(dāng)然這個方法是否有什么弊端我還沒有研究過啸箫。
youtube的進(jìn)度條在淡出的時候是定格在101%的耸彪。
Promise
原本處理進(jìn)度條淡出后移除DOM是選擇了Promise
_fadeOut(el) {
if (!el.style.opacity) el.style.opacity = 1;
el.style.opacity -= 0.1;
if (el.style.opacity > 0) rAF(this._fadeOut.bind(this, el));
return Promise.resolve();
}
最終還是因為瀏覽器兼容問題選擇callback
_fadeOut(el, callback) {
el.style.opacity -= 0.1;
if (el.style.opacity > 0) {
rAF(this._fadeOut.bind(this, el, callback));
} else {
setTimeout(() => { callback(); }, 300);
}
}
ease function
第一次接觸了javascript的緩動函數(shù),看了很多資料還是一知半解忘苛,項目里使用的歡動函數(shù)屬于比較簡單的
const easing = (t, b, c, d) => c * t / d + b;
如果有興趣的話可以參考這里看更多緩動函數(shù)資料
如果你對該項目有興趣蝉娜,歡迎你貢獻(xiàn)代碼。