成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

從0到1,開發(fā)一個動畫庫(2)

adam1q84 / 2956人閱讀

摘要:傳送門從到,開發(fā)一個動畫庫上一節(jié)講到了最基礎(chǔ)的內(nèi)容,為動畫構(gòu)建幀值對應(yīng)的函數(shù)關(guān)系,完成由幀到值的計(jì)算過程。這一節(jié)將在上節(jié)代碼的基礎(chǔ)上談?wù)勅绾谓o一個完整的動畫添加各類事件。

傳送門:從0到1,開發(fā)一個動畫庫(1)

上一節(jié)講到了最基礎(chǔ)的內(nèi)容,為動畫構(gòu)建“幀-值”對應(yīng)的函數(shù)關(guān)系,完成“由幀到值”的計(jì)算過程。這一節(jié)將在上節(jié)代碼的基礎(chǔ)上談?wù)勅绾谓o一個完整的動畫添加各類事件。

在添加各類事件之前,我們先對_loop循環(huán)函數(shù)進(jìn)行一些改進(jìn):

_loop() {
  const t = Date.now() - this.beginTime,
        d = this.duration,
        func = Tween[this.timingFunction] || Tween["linear"];

  if (this.state === "end" || t >= d) {
    this._end();
  } else if (this.state === "stop") {
    this._stop(t);
  } else if (this.state === "init") {
    this._reset();
  } else {
    this._renderFunction(t, d, func)
    window.requestAnimationFrame(this._loop.bind(this));
  }
}

可以清晰地看到,我們在循環(huán)中增加了很多類型的判斷,根據(jù)state當(dāng)前不同的狀態(tài)執(zhí)行相應(yīng)的處理函數(shù):我們新增了_end_stop、_reset方法分別去處理結(jié)束、暫停和重置這三種狀態(tài),接下來我們依次講解這些狀態(tài)的處理。

End

我們在Core類下增加_endendrenderEndState方法,end方法用于主動結(jié)束動畫:

end() {
  this.state === "play" ? (this.state = "end") : this._end();
}

_end() {
  this.state = "end";
  this._renderEndState();
  this.onEnd && this.onEnd();
}

_renderEndState() {
  const d = this.duration,
        func = Tween[this.timingFunction] || Tween["linear"];
  this._renderFunction(d, d, func);
}

通過執(zhí)行end方法,我們可以主動結(jié)束動畫:如果當(dāng)前目標(biāo)處于運(yùn)動狀態(tài),則將其設(shè)置為end,因此下一個_loop函數(shù)被執(zhí)行的時(shí)候,程序就被流向了_end處理函數(shù);若為其他狀態(tài),意味著循環(huán)沒有被打開,我們就直接調(diào)用_end方法,使其直接到終止?fàn)顟B(tài)。

_end函數(shù)的作用有三個:

將當(dāng)前狀態(tài)設(shè)置為end(為何要重復(fù)設(shè)置一次狀態(tài)呢?這不是多余的嗎?其實(shí),倘若我們主動觸發(fā)end去結(jié)束動畫,這的確是多余的,但如果是動畫自己進(jìn)行到了末尾,也就是t >= d的時(shí)刻,則必須得在_end中去設(shè)置狀態(tài),以確保它處于結(jié)束狀態(tài))

通過_renderEndState方法,將目標(biāo)變成結(jié)束狀態(tài)

若有回調(diào)函數(shù)則執(zhí)行回調(diào)

Reset

重置動畫的方式也是大同小異,與上面一樣

reset() {
  this.state === "play" ? (this.state = "init") : this._reset();
}

_reset() {
  this.state = "init";
  this._renderInitState();
  this.onReset && this.onReset();
}

_renderInitState() {
  const d = this.duration,
        func = Tween[this.timingFunction] || Tween["linear"];
  this._renderFunction(0, d, func);
}
Stop

讓動畫暫停也是與上述兩者一樣,但唯一的區(qū)別是,需要給_renderStopState方法傳入當(dāng)前時(shí)間進(jìn)度:

stop() {
  if (this.state === "play") {
    this.state = "stop";
  } else {
    // 使目標(biāo)暫停,無需像end或reset那樣將目標(biāo)變成結(jié)束/起始狀態(tài),保持當(dāng)前狀態(tài)即可
    this.state = "stop";
    this.onStop && this.onStop();
  }
}

_stop(t) {
  this.state = "stop";
  this._renderStopState(t);
  this.onStop && this.onStop();
}

_renderStopState(t) {
  const d = this.duration,
        func = Tween[this.timingFunction] || Tween["linear"];
  this._renderFunction(t, d, func);
}
play

我們要在動畫開始執(zhí)行的時(shí)候觸發(fā)onPlay事件,只需在_play方法內(nèi)增加一行代碼即可:

_play() {
      this.state = "play";
  
      // 新增部分
    this.onPlay && this.onPlay();
  
      this.beginTime = Date.now();
      const loop = this._loop.bind(this);
    window.requestAnimationFrame(loop);
}```

完整代碼如下:

import Tween from "./tween";

class Core {
    constructor(opt) {
        this._init(opt);
        this.state = "init";
    }

    _init(opt) {
    this._initValue(opt.value);
    this.duration = opt.duration || 1000;
    this.timingFunction = opt.timingFunction || "linear";
    this.renderFunction = opt.render || this._defaultFunc;

    /* Events */
    this.onPlay = opt.onPlay;
    this.onEnd = opt.onEnd;
    this.onStop = opt.onStop;
    this.onReset = opt.onReset;
  }

  _initValue(value) {
      this.value = [];
      value.forEach(item => {
          this.value.push({
              start: parseFloat(item[0]),
              end: parseFloat(item[1]),
          });
      })
  }

  _loop() {
    const t = Date.now() - this.beginTime,
      d = this.duration,
      func = Tween[this.timingFunction] || Tween["linear"];

    if (this.state === "end" || t >= d) {
      this._end();
    } else if (this.state === "stop") {
      this._stop(t);
    } else if (this.state === "init") {
      this._reset();
    } else {
      this._renderFunction(t, d, func)
      window.requestAnimationFrame(this._loop.bind(this));
    }
  }

  _renderFunction(t, d, func) {
      const values = this.value.map(value => func(t, value.start, value.end - value.start, d));
      this.renderFunction.apply(this, values);
  }
  
  _renderEndState() {
    const d = this.duration,
      func = Tween[this.timingFunction] || Tween["linear"];
    this._renderFunction(d, d, func);
  }

  _renderInitState() {
    const d = this.duration,
      func = Tween[this.timingFunction] || Tween["linear"];
    this._renderFunction(0, d, func);
  }

  _renderStopState(t) {
    const d = this.duration,
      func = Tween[this.timingFunction] || Tween["linear"];
    this._renderFunction(t, d, func);
  }

  _stop(t) {
    this.state = "stop";
    this._renderStopState(t);
    this.onStop && this.onStop();
  }

  _play() {
      this.state = "play";
    this.onPlay && this.onPlay();
    
      this.beginTime = Date.now();
      const loop = this._loop.bind(this);
    window.requestAnimationFrame(loop);
  }

  _end() {
    this.state = "end";
    this._renderEndState();
    this.onEnd && this.onEnd.call(this);
  }

  _reset() {
    this.state = "init";
    this._renderInitState();
    this.onReset && this.onReset();
  }

  play() {
      this._play();
  }

  end() {
    this.state === "play" ? (this.state = "end") : this._end();
  }

  reset() {
    this.state === "play" ? (this.state = "init") : this._reset();
  }

  stop() {
    if (this.state === "play") {
      this.state = "stop";
    } else {
      this.state = "stop";
      this.onStop && this.onStop();
    }
  }
}

window.Timeline = Core;

相應(yīng)地,html的代碼也更新如下,添加了各類按鈕,主動觸發(fā)目標(biāo)的各類事件:




    
    


看到這里,我們第二節(jié)的內(nèi)容就結(jié)束啦,下一節(jié),我們將介紹:

支持自定義路徑動畫

動畫間的鏈?zhǔn)秸{(diào)用

下一節(jié)再見啦^_^

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/92829.html

相關(guān)文章

  • 01開發(fā)一個畫庫(1)

    摘要:傳送門從到,開發(fā)一個動畫庫如今市面上關(guān)于動畫的開源庫多得數(shù)不勝數(shù),有關(guān)于甚至是渲染的,百花齊放,效果炫酷。當(dāng)你看到的時(shí)候可能不大明白外界傳入的到底是啥其實(shí)是一個數(shù)組,它的每一個元素都保存著獨(dú)立動畫的起始與結(jié)束兩種狀態(tài)。 傳送門:從0到1,開發(fā)一個動畫庫(2) 如今市面上關(guān)于動畫的開源庫多得數(shù)不勝數(shù),有關(guān)于CSS、js甚至是canvas渲染的,百花齊放,效果炫酷。但你是否曾想過,自己親手...

    canopus4u 評論0 收藏0
  • 01,開發(fā)一個畫庫(1)

    摘要:傳送門從到,開發(fā)一個動畫庫如今市面上關(guān)于動畫的開源庫多得數(shù)不勝數(shù),有關(guān)于甚至是渲染的,百花齊放,效果炫酷。當(dāng)你看到的時(shí)候可能不大明白外界傳入的到底是啥其實(shí)是一個數(shù)組,它的每一個元素都保存著獨(dú)立動畫的起始與結(jié)束兩種狀態(tài)。 傳送門:從0到1,開發(fā)一個動畫庫(2) 如今市面上關(guān)于動畫的開源庫多得數(shù)不勝數(shù),有關(guān)于CSS、js甚至是canvas渲染的,百花齊放,效果炫酷。但你是否曾想過,自己親手...

    jerry 評論0 收藏0
  • [譯]2018年值得關(guān)注的10大JavaScript畫庫

    摘要:幸運(yùn)的是,供應(yīng)似乎與需求相匹配,并且有多種選擇。讓我們來看看年值得關(guān)注的十大動畫庫。八年了,仍然是一個強(qiáng)大的動畫工具。接下來在這個令人驚嘆的動畫庫列表上的就是了。,通常被稱為動畫平臺,我們忽略它在列表中的排名,它是列表中最受歡迎的庫之一。 原文鏈接原譯文鏈接 現(xiàn)代網(wǎng)站的客戶端依靠高質(zhì)量的動畫,這就使得JavaScript動畫庫的需求不斷增加。幸運(yùn)的是,供應(yīng)似乎與需求相匹配,并且有多種選...

    Me_Kun 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<