記錄發(fā)布的第一個(gè)javascript項(xiàng)目及遇到的一些問題

前言

在去年12月份剛開始學(xué)習(xí)編程的時(shí)候,看到這樣一句話:“初學(xué)者不要寫博客,要多記筆記。”
細(xì)想言之有理,便沒有申請(qǐng)博客,開始在Onenote上記錄各種網(wǎng)上復(fù)制下來的筆記。

然而過了沒多久,又看到這么一句話:“好的代碼就相當(dāng)于筆記。”
細(xì)想亦言之有理,便停了onenote的筆記,導(dǎo)致在這半年多的時(shí)間里除了代碼基本上沒有寫過些什么。

而在前兩天,發(fā)布了自己的第一個(gè)npm包之后,覺得似乎應(yīng)該記錄下自己編寫代碼和發(fā)布包的過程中遇到的問題,順便發(fā)布項(xiàng)目Demo,
便花一天時(shí)間開始一步步折騰搞定github pages,hexo,和域名之類。

項(xiàng)目預(yù)覽及地址

功能:Youtube之類網(wǎng)站在進(jìn)行ajax請(qǐng)求時(shí)頂部出現(xiàn)的載入條

Demo

Github地址

為什么要寫這個(gè)項(xiàng)目

之前在一個(gè)天氣預(yù)報(bào)App的Demo,搜索然后ajax請(qǐng)求是基本功能,請(qǐng)求過程中就想到了實(shí)現(xiàn)載入效果,便在github上尋找開源項(xiàng)目。

因?yàn)橄M@個(gè)天氣預(yù)報(bào)App盡量輕便(使用了React,撇除React-Router及Redux之類),所以放棄一些包含各種載入效果的庫,
最后使用了NprogressNanobar兩個(gè)功能簡(jiǎn)單的庫。

這倆個(gè)庫相比較,Nanobar體積更小,功能更簡(jiǎn)單(只有一個(gè)go函數(shù)),Nprogress則更漂亮(有一個(gè)peg元素,制造了box-shadow陰影),
可以調(diào)用的函數(shù)也更多(有漸漸載入的效果)。

但是這兩個(gè)庫年代都比較久遠(yuǎn),都沒有選擇構(gòu)造函數(shù)來創(chuàng)建對(duì)象,所有函數(shù)都沒有綁在原型鏈上(當(dāng)然對(duì)于這種功能簡(jiǎn)單的庫來說沒有什么大的影響)、
都是使用setTimeout方式實(shí)現(xiàn)動(dòng)畫(當(dāng)然對(duì)這種簡(jiǎn)單的動(dòng)畫也沒有什么大的影響)、都需要引入css文件使用transform作為實(shí)現(xiàn)動(dòng)畫效果的輔助。
最終在參考了兩個(gè)庫的源代碼后決定自己寫一個(gè)。

在項(xiàng)目中遇到的問題和解決方法

構(gòu)造函數(shù)、打包工具

使用ES6 class構(gòu)造對(duì)象,使用rollup打包成umd形式的函數(shù)。

rollup在打包之后不是生成傳統(tǒng)的Object.prototype形式,而是定義了一個(gè)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;
  };
}();

動(dòng)畫函數(shù)

使用window.requestAnimationFrame來進(jìn)行動(dòng)畫,使用了一般通用的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ù)。

合并對(duì)象

在庫中使用了Object.assign函數(shù)合并對(duì)象,該函數(shù)有瀏覽器兼容問題,需要額外使用babel插件進(jìn)行編譯。

一般比較大的庫都會(huì)定義自己的merge函數(shù),lodashunderscore也定義了合并函數(shù),另外ES6有實(shí)驗(yàn)性質(zhì)的展開對(duì)象合并的方法,
這應(yīng)該也是極為遙遠(yuǎn)的將來展開和合并對(duì)象的標(biāo)準(zhǔn)方法

限制對(duì)象屬性的值

渲染進(jìn)度條最重要的是確定什么時(shí)候渲染完成,按照邏輯來說進(jìn)度條達(dá)到最大值的時(shí)候就應(yīng)該淡出,
用代碼表示就應(yīng)該是if (this.barWidth === this.maxWidth) this.stop();,
但實(shí)際運(yùn)行中發(fā)現(xiàn)由于遞增barWidth使用的是緩動(dòng)函數(shù),
所以barWidth未必會(huì)接觸到maxBarWitdh,可能上一幀在99.8%,下一幀卻出現(xiàn)在100.2%。

nanobar解決這個(gè)問題是直接重新創(chuàng)建實(shí)例

if (p >= 100) {
  init()
}

這個(gè)方式可能有點(diǎn)太粗暴了。而我最終選擇的是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,就會(huì)被設(shè)置成100,進(jìn)而出發(fā)stop函數(shù)。

當(dāng)然這個(gè)方法是否有什么弊端我還沒有研究過。

youtube的進(jìn)度條在淡出的時(shí)候是定格在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();
}

最終還是因?yàn)闉g覽器兼容問題選擇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的緩動(dòng)函數(shù),看了很多資料還是一知半解,項(xiàng)目里使用的歡動(dòng)函數(shù)屬于比較簡(jiǎn)單的

const easing = (t, b, c, d) => c * t / d + b;

如果有興趣的話可以參考這里看更多緩動(dòng)函數(shù)資料

如果你對(duì)該項(xiàng)目有興趣,歡迎你貢獻(xiàn)代碼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容