首次開發H5長圖頁總結


首次開發H5長圖頁總結.

資源統一加載

資源統一加載, 分開獲取

定義資源標識符

  • src/resources目錄下 定義各個資源模塊.
  • Asset.js中獲取定義好的所有模塊, 循環出具體的文件路徑, 統一數組.
  • 按照一定規則組件文件id, 方便頁面中獲取.

暴露方法, 掛載全局

在全局app.init的時候, 進行資源的初始化, 並把初始化的資源對象掛載到Global對象上, 方面后續其他頁面的資源獲取.(Global用作全局屬性管理).代碼的執行順序為:

app.init() => new Asset() => asset.load() => asset.onComplete() => initStage() => ....

  • load: 可開始加載全部資源
  • onComplete: 資源全部加載完成
  • getAsset: 獲取指定資源

切換思想

全局只存在兩個container; 所有頁面交替出現

創建舞台的過程

所有的頁面均在initStage()初始化舞台時, 進行創建, 以確保資源全部加載完成. 舞台初始化完成, 所有的頁面也均初始化完成.

initStage()過程包括:

  1. initBus(): 初始化全局的事件訂閱系統
  2. createStage(): 創建舞台, 在創建舞台的時候, 就和綁定好了滾動函數.
  3. initScene: 因為剛開始的代碼邏輯出現問題, 全局只有一個場景, 是起初沒有考慮到的
  4. 完成, 即可把第一個頁面推出顯示棧.

頁面創建過程

在創建舞台的時候, 會初始化場景, 我們的頁面總體分成: 舞台 > 場景 > 部分(頁面)

初始化場景的過程, 也就是初始化所有頁面的過程:
new Scene() => init partMap() => partMap.push(new Part)

partMap是所有頁面的集合, 按照顯示順序進行創建.

  • 每當執行new part時, 就是頁面執行自身constructor, 並調用init方法的過程.
  • 因每一個頁面都是通過push方法, 放入到parMap中的, 故初始化過程的中partMap的長度就是, 當前頁面所在partMap中的位置
  • 頁面創建后, 會包含所有后續需要的屬性, 以及頁面聲明周期中所有狀態的初始化.
  • 並在創建過程中完成各個模塊的監聽

頁面生命周期

正序執行過程: p1.start => p1.next => p2.start => p1.end => p2.next => ....
倒序執行過程: p2.prev => p1.restart => p2.end => ....

每次聲明周期函數, 為避免計算錯誤, 只在特定的時間執行一次, 故需要一些關鍵的狀態管理

  • start: 頁面開始函數, 即讓頁面執行addTo()添加到舞台中

  • reStart: 重新展示頁面, 讓頁面的執行addTo(stage, 0), 讓頁面插入到舞台的最底層位置

  • prev: 上一個頁面戰術, 即讓上一個頁面執行reStart()重新展示

  • next: 下一個頁面戰術, 即下一個頁面執行start()方法

  • end: 頁面展示結束, 從父元素中remove出來, 並重置方法執行狀態.

    除next方法, 需要在頁面內具體實現外, 其他方法均為統一處理

  • shouldUpdate: 監聽到滾動, 執行頁面內具體邏輯

滑動高度

initStage的時候, 綁定滾動事件. 並廣播全局事件.

動態計算

  • 全局總高度: 每一次new part的時候, 都會累加整個頁面需要的總高度, 並以此設計能夠滑動的高度.
  • 頁面高度計算方式: 頁面的高度, 是通過參數傳入的.
  • 頁面開始高度:
    • 從全局看: 當前頁面高度是, 之前所有頁面的累加高度, 也就是全局的高度.
    • 從頁面看: 所有的頁面都是從0開始.

當前頁面的滾動位置

當前頁面滾動的位置 = 總共滾動過的高度 - 當前頁面開始的高度

  • <0的部分還和上一個頁面重疊
  • >0之后, 自己完全出現
  • 合適的時機 調用, next, 下一個頁面就可以開始<0的過程了.
  • 當滾動的高度大於當前頁面的高度時, 就是執行end的時候了.

附上核心實現函數

// Part.js
// 注: 此函數依賴全局模塊
import Global from './Global'

const Part = Hilo.Class.create({
  Mixes: Hilo.EventMixin,
  constructor: function (properties) {
    this.parentNode = properties.parentNode || null; // 頁面所屬場景
    this.parentContainer = properties.parentNode ? properties.parentNode.content : null; // 頁面所屬容器
    this.parentName = properties.parentNode ? properties.parentNode.name : ''; // 頁面所屬場景名稱
    this.name = properties.name || ''; // 頁面名稱
    this.partHeight = properties.height || 0; // 頁面的總高度
    this.disappearNext = properties.disappear || 0; // 頁面需要消失的距離

    this.state = 'hide'; // 當前頁面是否展示
    this.nextDone = false; // next函數是否執行過
    this.prevDone = false; // prev函數是否執行過
    this.index = this.parentNode.partMap.length; // 此處為核心概念, 根據數組長度確定當前索引!!
    this.content = new Hilo.Container({
      id: this.name
    });

    this.initStartHeight(); // 計算當前頁面的在全局中的開始高度
    if (this.init instanceof Function) this.init();
    // 監聽用戶滾動, 高度變化.
    Global.bus.on('changeTouchHeight', this.changeTouchHeight.bind(this));
  },
  initStartHeight: function () {
    // 獲得當前頁面在全劇中的高度
    var perNode = this.getPrevNode()
    this.startHeight = perNode ? Global.totalHeight += perNode.partHeight : Global.totalHeight;

    // 頁面能夠滾動到的最大高度
    var maxHeight = (this.startHeight + this.partHeight - Global.height) / Global.touchSpeed;
    Global.scroller.setDimensions(0, 0, 0, maxHeight)
  },
  changeTouchHeight: function (info) { // 監聽高度變化
    if (this.state === 'show' && this.shouldUpdate instanceof Function) {
      var touchHeight = info.detail.distance - this.startHeight; // 頁面內的高度變化值
      var direction = info.detail.direction; // 滾動的方向
      if (direction === 'up' && touchHeight <= 0) { // 向上滾動, 且高度小於0, 上一個頁面展示
        this.prev();
      }
      if (direction === 'down' && touchHeight >= this.partHeight) { // 向下滾動, 超過當前頁面最大高度, 從父容器中抽出
        console.log(this.name, 'down end')
        this.end()
      }
      if (direction === 'up' && this.getPrevNode()  && touchHeight < -this.getDisappearPrev()) { // 向上滾動, 超過上一個頁面的消失高度, 從父元素中抽出
        console.log(this.name, 'up end')
        this.end()
      }
      // 調用生命周期, 通知頁面內變化
      this.shouldUpdate(touchHeight, direction);
    }
  },
  start: function () { // 開始展示
    if (this.state === 'show') return;
    this.state = 'show';
    console.log(this.name, 'start');
    if (this.onStart instanceof Function) this.onStart();
    this.content.addTo(this.parentContainer);
  },
  reStart: function () { // 再次展示, 也就是向上滑動, 展示到舞台的最底層
    if (this.state === 'show') return;
    this.state = 'show';
    console.log(this.name, 'reStart');
    if (this.onreStart instanceof Function) this.onreStart();
    this.content.addTo(this.parentContainer, 0);
  },
  prev: function () { // 展示上一個頁面
    if (this.state === 'hide' || this.prevDone) return;
    if (this.getPrevNode() && this.getPrevNode().state === 'show') return;
    this.prevDone = true;
    console.log(this.name, 'prev')
    if (this.onPrev instanceof Function) this.onPrev();
    this.getPrevNode() && this.getPrevNode().reStart();
  },
  next: function () { // 展示下一個頁面
    if (this.state === 'hide' || this.nextDone) return;
    if (this.getNextNode() && this.getNextNode().state === 'show') return;
    this.nextDone = true;
    console.log(this.name, 'next')
    if (this.onNext instanceof Function) this.onNext();
    this.getNextNode() && this.getNextNode().start();
  },
  end: function () { // 頁面展示結束, 抽出
    if (this.state === 'hide') return;
    console.log(this.name, 'end')
    if (this.onEnd instanceof Function) this.onEnd();
    this.state = 'hide';
    this.content.removeFromParent();
    this.getNextNode() && (this.getNextNode().prevDone = false);
    this.getPrevNode() && (this.getPrevNode().nextDone = false);
  },
  getPrevNode: function () { // 獲取上一個頁面節點
    var map = this.parentNode.partMap;
    var index = this.index;
    return map[index - 1];
  },
  getNextNode: function () { // 獲取下一個頁面節點
    var map = this.parentNode.partMap;
    var index = this.index;
    return map[index + 1];
  },
  getDisappearNext: function () { // 向下滾動消失需要的距離
    return this.disappearNext;
  },
  getDisappearPrev: function () { // 向上滾動消失需要的距離
    return (this.getPrevNode() && this.getPrevNode().getDisappearNext()) || 0;
  },
});

export default Part;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM