欧美三级国产三级日韩三级_亚洲熟妇丰满大屁股熟妇_欧美亚洲成人一区二区三区_国产精品久久久久久模特

小程序直播-評論彈幕是如何“練”成的? - 新聞資訊 - 云南小程序開發(fā)|云南軟件開發(fā)|云南網(wǎng)站建設(shè)-昆明葵宇信息科技有限公司

159-8711-8523

云南網(wǎng)建設(shè)/小程序開發(fā)/軟件開發(fā)

知識

不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價值,我們在追求其視覺表現(xiàn)的同時,更側(cè)重于功能的便捷,營銷的便利,運(yùn)營的高效,讓網(wǎng)站成為營銷工具,讓軟件能切實(shí)提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序?yàn)楹笃谏壧峁┍憬莸闹С郑?

您當(dāng)前位置>首頁 » 新聞資訊 » 小程序相關(guān) >

小程序直播-評論彈幕是如何“練”成的?

發(fā)表時間:2021-1-5

發(fā)布人:葵宇科技

瀏覽次數(shù):108

1 前言


近期,電商直播業(yè)務(wù)熱火朝天,為了烘托直播間的氛圍,達(dá)到主播與觀眾的有效正反饋,彈幕、點(diǎn)贊用戶行為提示三件套成為一個標(biāo)準(zhǔn)的直播間必不可少的裝備。兩個月前,作者曾解析了點(diǎn)贊動畫的實(shí)現(xiàn)原理,雖文筆粗糙,但在總結(jié)中,對技術(shù)原理有了更加透徹的理解。恰逢近期沉淀直播間業(yè)務(wù),重新封裝了彈幕組件,對代碼的設(shè)計有了新的理解,總結(jié)成一篇文章,與君共享。

提起彈幕(dànmù),大家都會想到「視頻彈幕」。視頻彈幕是指網(wǎng)友們在觀看視頻的同時參與評論,即所謂“即時反饋”, 評論以飛行形式橫穿屏幕,視覺效果類似多發(fā)密集的子彈飛速而過,故稱之為“彈幕”。“彈幕”最大的特點(diǎn)就是允許受眾在觀看直播的同時將評論內(nèi)容發(fā)送到服務(wù)器與直播同步播放,這可以讓觀眾的反饋瞬間產(chǎn)生,與主播發(fā)生即時互動,甚至可以形成隔空對話

隨著手機(jī)豎屏直播時代的到來,彈幕也從原本的“橫穿飛行”,衍生出一種新的模式——在屏幕左下方豎向滾動。實(shí)際效果如下圖所示。

從效果圖上我們還看到有幾點(diǎn)重要信息:

  • 歷史彈幕上屏:為了活躍氣氛,觀眾初次進(jìn)入直播間可以觀看前 30 條歷史彈幕。
  • 即時彈幕消息上屏:即時收到的彈幕消息從底部上屏,并實(shí)現(xiàn)自動滾動。
  • 個人評論消息上屏:個人評論的消息“優(yōu)先”上屏,不受即時消息堆積影響。
  • 系統(tǒng)提示消息上屏:系統(tǒng)提示消息分兩種,一種是固定提示,固定在彈幕列表頭部,不會消失。另外一種是主播操作產(chǎn)生的臨時提示,跟彈幕消息一起,超過數(shù)量限制時,就會被清理。

看似簡單,實(shí)現(xiàn)的過程中卻需考慮如下幾點(diǎn):

  • 即時消息堆積問題: 在李佳琦、薇婭等超級主播的直播間,每秒接收到的消息數(shù)以千計,如果不做“屏控”處理,且有計劃地過濾掉“低質(zhì)”彈幕,而是一股腦地將消息上屏,彈幕便會飛速滾動,那么觀眾和主播都無法有效地獲取內(nèi)容信息。
  • 上屏彈幕堆積問題: 隨著時間的推移,上屏彈幕數(shù)量逐漸累積,如果不及時清理陳舊的DOM節(jié)點(diǎn),會導(dǎo)致系統(tǒng)卡頓,甚至程序崩潰。
  • 用戶互動體驗(yàn)優(yōu)化問題: 當(dāng)用戶滾動彈幕時,需要暫停彈幕上屏邏輯,便于用戶進(jìn)行操作;當(dāng)彈幕滾動到底部時,自動恢復(fù)彈幕上屏邏輯;長期暫停的彈幕需要設(shè)有自動恢復(fù)機(jī)制,等等體驗(yàn)問題都是需要優(yōu)化的內(nèi)容。
  • 歷史彈幕上屏問題: 如若 30 條歷史彈幕一窩蜂上屏,彈幕會飛速滾動,給用戶極差的體驗(yàn)觀感,需要制定策略實(shí)現(xiàn)分布式上屏。

2 千里之行,始于布局


2.1 組件的 data 與 properties

一口吃不成胖子,先從效果圖顯示的布局入手,思考封裝這個組件,需要傳入哪些參數(shù),哪些是通過properties由父組件傳入,哪些通過data來維護(hù),與視圖進(jìn)行通信。

  data = http://www.wxapp-union.com/{
    toLast: 'item0', // 彈幕滾動索引
    realBarrage: [], // 實(shí)際上屏的彈幕
  };
  properties = {
    barrageHeight: {
      type: Number,
      value: 500,
    }, // 彈幕容器高度
    config: {
      type: Object,
      value: DEFAULT_CONFIG,
    }, // 彈幕配置
    tagConfig: {
      type: Array,
      value: TAG_DEFAULT_CONFIG,
    }, // 標(biāo)簽配置信息
    systemHint: {
      type: String,
      value: DEFAULT_SYSTEM_HINT,
    }, // 系統(tǒng)提示信息
  };
復(fù)制代碼

先來談?wù)?code>properties屬性:

  • barrageHeightNumber類型,彈幕容器高度,可動態(tài)調(diào)節(jié),如下圖所示,超級彈幕出現(xiàn)時,需要縮小彈幕高度。

  • systemHintString類型,系統(tǒng)提示信息內(nèi)容,長期存在于彈幕列表頭部,默認(rèn)配置信息如下。
const DEFAULT_SYSTEM_HINT =
  '系統(tǒng)提示:歡迎來到直播間!直享倡導(dǎo)綠色直播,文明互動,購買直播推薦商品時,請確認(rèn)購買鏈接描述與實(shí)際商品一致,避免上當(dāng)受騙。如遇違法違規(guī)現(xiàn)象,請立即舉報!';
復(fù)制代碼
  • configObject類型,彈幕配置信息, 可配置參數(shù)如下:
const DEFAULT_CONFIG = {
  INTERVAL: 300, // 刷新頻率,默認(rèn)300ms
  BARRAGE_MAX_COUNT: 50, // 上屏彈幕的最大數(shù)量
  POOL_MAX_COUNT: 50, // 彈幕池(未上屏)彈幕上限
  BARRAGE_MAX_FRAME: 6, // 屏控處理,每次同時上屏彈幕的數(shù)量
  SLEEP_TIME: 5000, // 彈幕休眠時間,默認(rèn)5000ms
  CHECK_SLEEP: true, // 是否休眠,休眠超過 SLEEP_TIME ,則開啟自動滾動
};
復(fù)制代碼
  • tagConfigArray類型,標(biāo)簽配置信息,主要用于自定義化標(biāo)簽的樣式和內(nèi)容,當(dāng)前的默認(rèn)配置如下:
const TAG_DEFAULT_CONFIG = [
  {
    bgColor: 'linear-gradient(to right, #fb3e3e, #ff834a)',
    tagName: '主播',
  },
  {
    bgColor: 'linear-gradient(to top, #ffb365, #ff8c17)',
    tagName: '號主',
  },
  {
    bgColor: 'linear-gradient(to left, #8bb1ff, #5195ff)',
    tagName: '粉絲',
  },
];
復(fù)制代碼

然后,再談?wù)?code>data屬性:

  • realBarrage: Array類型,實(shí)際上屏的彈幕列表,分兩種,一種是評論消息,一種是系統(tǒng)消息。彈幕列表中每一項(xiàng)包含的屬性類型說明如下:
interface queueI {
  name?: string; // 用戶昵稱
  comment?: string; // 評論內(nèi)容
  isMe?: boolean; // 是否自己發(fā)送的彈幕
  tagIndex?: number; // 標(biāo)簽索引,可自定義,默認(rèn)情況 0-主播,1-號主,2-粉絲
  systemInfo?: string; // 系統(tǒng)提示消息,如果存在這個屬性,則前面四個屬性無需存在
}
復(fù)制代碼

其中,namecomment為普通評論消息的必須屬性,systemInfo為系統(tǒng)消息的必須屬性,兩者互斥。 彈幕數(shù)據(jù)tagIndex屬性與標(biāo)簽配置信息中TAG_DEFAULT_CONFIG數(shù)組的索引一一對應(yīng),默認(rèn)情況 0-主播,1-號主,2-粉絲。如果修改標(biāo)簽配置信息,那么tagIndex屬性值的對應(yīng)關(guān)系也要重新梳理。

  • toLast: String類型,彈幕索引,隨著新彈幕不斷上屏,彈幕列表需要實(shí)現(xiàn)自動滾動,小程序提供的組件的scroll-into-view屬性支持滾動到對應(yīng)的子元素 id,所以需要維護(hù)toLast來指定。

2.2 開始布局

知道了每個dataproperties的含義,可以根據(jù)設(shè)計稿,對布局一把梭了。為了實(shí)現(xiàn)可滾動視圖區(qū)域,組件外層使用包裹。用到的屬性如下表所示:

屬性類型說明默認(rèn)值必填
scroll-yboolean允許縱向滾動false
scroll-with-animationboolean在設(shè)置滾動條位置時使用動畫過渡false
scroll-into-viewstring值應(yīng)為某子元素 id(id 不能以數(shù)字開頭)。設(shè)置哪個方向可滾動,則在哪個方向滾動到該元素-
lower-thresholdnumber/string距底部/右邊多遠(yuǎn)時,觸發(fā) scrolltolower 事件50
bindscrolltolowereventhandle滾動到底部/右邊時觸發(fā)-
bindscrolleventhandle滾動時觸發(fā),event.detail = {scrollLeft, scrollTop, scrollHeight, scrollWidth, deltaX, deltaY}-
bindtouchstarteventhandle手指觸摸動作開始-
bindtouchendeventhandle手指觸摸動作開始-

容器內(nèi)的子元素包含兩部分,一部分的直播間提示消息,放在滾動列表的頭部,永遠(yuǎn)不會被清理。另外一部分是即時消息,分為評論消息和系統(tǒng)消息,放在realBarrage中,達(dá)到數(shù)量最大限制時會被清理。

視圖布局代碼如下所示:

<scroll-view class="live-barrage wr-class" style="max-height:{{barrageHeight}}rpx;" scroll-y="true" scroll-with-animation="true" scroll-into-view="{{toLast}}" bindtouchstart="barrageTouchStart" bindtouchend="barrageTouchEnd" lower-threshold="100" bindscroll="handleScrollBarrageContainer" bindscrolltolower="handleScrollBottom">
  
  <view class="live-barrage-system system-class" id="item0">{{systemHint}}view>
  
  <view class="{{item.systemInfo? 'live-barrage-system' : 'live-barrage-item item-class'}}" wx:for="{{realBarrage}}" wx:for-item="item" wx:key="index" id="item{{index+1}}">
    
    <view class="live-barrage-item-content" wx:if="{{!item.systemInfo}}">
      <view class="live-barrage-item-content-tag" wx:if="{{item.tagIndex >= 0 &&  tagConfig[item.tagIndex]}}" style="background-image: {{tagConfig[item.tagIndex].bgColor}}">
        {{tagConfig[item.tagIndex].tagName}}
      view>
      <view class="{{item.isMe ? 'live-barrage-item-content-name-me' :  'live-barrage-item-content-name'}}">
        {{item.name}}:\t
      view>
      {{item.comment}}
    view>
    
    <view wx:else>{{item.systemInfo}}view>
  view>
scroll-view>
復(fù)制代碼

3 封裝一個類

根據(jù)需求,對功能進(jìn)行思考和拆分,抽象出一個通用類,此處定義為QueueBarrage。這個類維護(hù)兩個優(yōu)先級隊(duì)列,一個是彈幕池,一個是上屏彈幕。服務(wù)器推送的彈幕消息進(jìn)入彈幕池,池子里的彈幕需要進(jìn)行過濾重排、溢出處理。設(shè)置輪詢機(jī)制,對彈幕進(jìn)行分批次上屏,同時上屏彈幕也設(shè)有溢出處理策略。自己發(fā)送的彈幕不走彈幕池,直接上屏。


3.1 類的屬性定義和構(gòu)造器

下列代碼是類的屬性定義和構(gòu)造器。

  • queueList:彈幕池,包括所有未上屏的彈幕。
  • barrageList:上屏的彈幕列表。
  • changeCallback:彈幕上屏回調(diào),彈幕上屏邏輯是業(yè)務(wù)邏輯,需要以回調(diào)的形式傳入。
  • config: 彈幕配置信息,通過創(chuàng)建類實(shí)例傳參,可以覆蓋默認(rèn)配置信息。
export default class QueueBarrage {
  queueList: queueI[]; // 彈幕池,包括所有彈幕
  barrageList: queueI[]; // 上屏彈幕
  changeCallback; // 彈幕上屏回調(diào)
  config; // 配置信息
  isPaused: boolean; // 彈幕是否暫停
  isActive: boolean; // 彈幕是否休眠
  timer;
  private checkActiveTimer;
  constructor(config = {}) {
    this.config = { ...defaultConFig, ...config };
    this.queueList = [];
    this.barrageList = [];
    this.isPaused = false;
    this.isActive = false;
    this.flush();
  }
}
復(fù)制代碼

3.2 接收到的消息進(jìn)入彈幕池

前面提到過,在李佳琦、薇婭等超級主播的直播間,每秒接收到的消息數(shù)以千計,如果直接一股腦地將消息上屏,彈幕便會飛速滾動,那么觀眾和主播都無法有效地獲取內(nèi)容信息。因此,需要維護(hù)一個「彈幕池」,能對彈幕進(jìn)行優(yōu)先級排序,有效地過濾掉“低質(zhì)”彈幕,同時對池子的容量做限制,添加“溢出”處理策略。

代碼實(shí)現(xiàn)如下所示,將消息放入彈幕池,如果彈幕數(shù)量超出最大數(shù)量限制,則對彈幕進(jìn)行過濾,同時刪除超出的那部分彈幕。當(dāng)然,歷史彈幕信息為了保證上下文邏輯的嚴(yán)謹(jǐn)性,是無需進(jìn)行優(yōu)先級排序的,所以只需要截取超出的部分。為了區(qū)分兩種彈幕類型,本函數(shù)的第二個參數(shù)isFilter用來控制是否進(jìn)行過濾。

  barrageEnterQueue(queue: queueI[], isFilter = true) {
    queue.forEach(v => {
      this.queueList.push(v);
    });
    // 進(jìn)入直播間歷史彈幕不進(jìn)行過濾
    if (this.queueList.length > this.config.POOL_MAX_COUNT) {
      if (isFilter)
        this.queueList = filter(this.queueList, this.config.POOL_MAX_COUNT);
      else
        this.queueList.splice(
          0,
          this.queueList.length - this.config.POOL_MAX_COUNT,
        );
    }
    if (!this.isPaused) {
      !this.timer && this.flush();
    }
  }
復(fù)制代碼

那么過濾規(guī)則是怎么樣的呢?這得視業(yè)務(wù)情況而定,下面貼出本業(yè)務(wù)的彈幕過濾邏輯:

  • 無意義彈幕的權(quán)重降低 0.5
  • 短彈幕的權(quán)重降低 0.2
  • 自己發(fā)送的彈幕的權(quán)重提高 1.0

這里需要注意的是,自己發(fā)送的彈幕的權(quán)重優(yōu)先級是最高的,可以走彈幕池,通過過濾提高優(yōu)先級,但這需要一定的時間消耗。不走彈幕池,直接上屏是比較合理的實(shí)現(xiàn)方案。

const CONTENT_FIELD = 'comment';
const REG_MEANINGLESS = /^[\d\s\!\@\#\$\%\^\&\*\(\)\-\=]+$/;
// 權(quán)重計算規(guī)則
const rules = [
  function meaningless(this: any, weight) {
    return this[CONTENT_FIELD] && REG_MEANINGLESS.test(this[CONTENT_FIELD])
      ? weight - 0.5
      : weight;
  },
  function barrage2short(this: any, weight) {
    return this[CONTENT_FIELD] && this[CONTENT_FIELD].length < 3
      ? weight - 0.2
      : weight;
  },
];
復(fù)制代碼

接下來,便可根據(jù)權(quán)重計算規(guī)則對彈幕進(jìn)行排序且篩選。第一個參數(shù)是彈幕列表,第二個參數(shù)是最大數(shù)量限制。

export function filter(barrages, limit) => {
  barrages.forEach(barrage => {
    barrage.weight = rules.reduce((weight, rule) => {
      return rule.call(barrage, weight);
    }, 1);
  });
  return barrages
    .sort((a, b) => b.weight - a.weight)
    .slice(barrages.length - limit);
};
復(fù)制代碼

3.3 輪詢上屏

將消息放入彈幕池后,接下來的操作便是輪詢從彈幕池里取固定數(shù)量的彈幕上屏。實(shí)現(xiàn)邏輯如下所示:

  • 第一步,從彈幕池里取出固定數(shù)量為BARRAGE_MAX_FRAME(默認(rèn)為 6)的彈幕,添加到barrageList(上屏彈幕列表)中。如上效果圖所示,6 條彈幕同時上屏,正好在一個屏幕高度內(nèi),不影響用戶獲取內(nèi)容信息。
  • 第二步,對barrageList列表做溢出處理,超出最大數(shù)量限制BARRAGE_MAX_COUNT(默認(rèn)為 50),刪除列表頭部超出數(shù)量的彈幕。這樣可以將上屏彈幕的數(shù)量維持在一個最大閾值內(nèi)。如上效果圖所示,彈幕列表數(shù)量超出閾值,頭部的彈幕已經(jīng)被清理,用戶只能獲取最新的 50 條彈幕。
  • 第三步,barrageList得到更新后,需要執(zhí)行changeCallback回調(diào)做真正的上屏處理,這個回調(diào)涉及業(yè)務(wù)邏輯操作,需要在類實(shí)例化的時候進(jìn)行賦值。
  • 使用setTimeout實(shí)現(xiàn)輪詢機(jī)制,每INTERVALms(默認(rèn)為 300)執(zhí)行如上 3 步操作,如果上屏彈幕列表為空,表示沒有新的彈幕消息,則不執(zhí)行上屏回調(diào)處理。需要注意的是,這里用setTimeout模擬setInterval實(shí)現(xiàn)輪詢,這是因?yàn)楫?dāng)回調(diào)函數(shù)的執(zhí)行被阻塞時,setInterval會產(chǎn)生回調(diào)堆積。
 private flush() {
    this.timer = setTimeout(() => {
      if (this.queueList.length > 0) {
        // 從彈幕池中取彈幕
        this.barrageList = [
          ...this.barrageList,
          ...this.queueList.splice(0, this.config.BARRAGE_MAX_FRAME),
        ];

        // 判斷上屏彈幕是否超過最大限制,如超過,刪除舊彈幕
        if (this.barrageList.length > this.config.BARRAGE_MAX_COUNT) {
          this.barrageList.splice(
            0,
            this.barrageList.length - this.config.BARRAGE_MAX_COUNT,
          );
        }
        // 彈幕上屏
        this.barrageList.length > 0 &&
          this.changeCallback &&
          this.changeCallback(this.barrageList);
      }
      this.flush();
    }, this.config.INTERVAL);
  }

// 彈幕上屏回調(diào)函數(shù)賦值
  emitQueueChange(cb) {
    this.changeCallback = cb;
  }
復(fù)制代碼

3.4 自己發(fā)的彈幕直出

用戶自己發(fā)送的彈幕,不走彈幕池過濾,無視網(wǎng)絡(luò)質(zhì)量,無條件優(yōu)先上屏。代碼如下所示:

  // 自己的彈幕直出
  barrageEnterQueueSelf(queue: queueI) {
    this.barrageList.push(queue);
    this.changeCallback && this.changeCallback(this.barrageList);
  }
復(fù)制代碼

3.5 輪詢控制系統(tǒng)

  • 當(dāng)用戶滑動彈幕列表時,為了方便用戶執(zhí)行截圖、賦值、搜索等操作,彈幕上屏邏輯需要暫停。
  • 當(dāng)用戶將列表滾動到底部時,恢復(fù)輪詢。
  • 同時需要設(shè)置重啟機(jī)制,當(dāng)彈幕暫停時間超過SLEEP_TIMEms(默認(rèn)為 5000),且用戶不在執(zhí)行其它操作,彈幕恢復(fù)輪詢。

具體的處理邏輯如下所示:

// 檢查彈幕是否激活
  setActiveAndAutoRestart() {
    // 如果沒有開啟
    if (!this.config.CHECK_SLEEP) return;
    if (this.checkActiveTimer) {
      clearTimeout(this.checkActiveTimer);
    }
    this.checkActiveTimer = setTimeout(() => {
      this.restart();
    }, this.config.SLEEP_TIME);
  }

  // 彈幕暫停滾動
  pause() {
    if (this.isPaused) return;
    this.isPaused = true;
    if (this.timer) {
      clearTimeout(this.timer);
      this.timer = null;
    }

    this.setActiveAndAutoRestart();
  }

  // 彈幕重新開始滾動
  restart() {
    if (!this.isPaused) return;
    this.isPaused = false;
    this.queueList.length && this.flush();
  }
復(fù)制代碼

4 組件方法詳解

4.1 組件生命周期操作
  • attached,組件掛載時,創(chuàng)建Barrage類實(shí)例,設(shè)置彈幕上屏的實(shí)際回調(diào)方法,通過toLast值指定列表滾動到該元素,通過更新realBarrage數(shù)據(jù),來更新實(shí)際上屏的數(shù)據(jù)。
  • detached,組件銷毀時,清除Barrage類實(shí)例,同時對定時器進(jìn)行清理。
  attached() {
    // 創(chuàng)建Barrage實(shí)例
    this.barrage = new Barrage(this.properties.config);
    // 初始化輪詢回調(diào)方法
    this.barrage.emitQueueChange(data => {
      this.setData({
        toLast: `item${data.length}`,
        realBarrage: data,
      });
    });
    // 校準(zhǔn)彈幕容器高度
    this.checkContainerClientHeight();
  }

  detached() {
    this.barrage && this.barrage.destroy();
  }
復(fù)制代碼

4.2 三種角色的彈幕消息進(jìn)入彈幕池

父組件可以通過 id 獲取彈幕組件的實(shí)例,從而調(diào)用其封裝的方法。用法如下所示:

<wr-live-barrage id="wr-live-barrage">wr-live-barrage>
復(fù)制代碼
  // 獲取彈幕組件實(shí)例
  getBarrageContext() {
    if (!this.barrageContext) {
      (this.barrageContext as any) = this.selectComponent('#wr-live-barrage');
    }
    return this.barrageContext;
  }

  // 調(diào)用方法示例
  handleSendBarrage() {
    (this.getBarrageContext() as any).sendBarrageBySelf(data);
  }
復(fù)制代碼

彈幕組件暴露的三個方法如下表格所示:

API說明參數(shù)默認(rèn)值
multiPushBarrage初始化直播間時,填充數(shù)十條歷史彈幕數(shù)據(jù),組件已經(jīng)優(yōu)化,實(shí)現(xiàn)分布式上屏queueI[]-
sendBarrageEnterQueue將接收到的彈幕消息放入彈幕池, 第二個參數(shù)表示是否執(zhí)行彈幕過濾規(guī)則<queueI[], Boolean><-, true>
sendBarrageBySelf自己發(fā)送的彈幕消息直接上屏queueI-

三個方法的代碼如下所示,都是將彈幕放入彈幕池,唯一的區(qū)別是自己發(fā)送的彈幕時,需要恢復(fù)輪詢機(jī)制。

 // 自己發(fā)彈幕
  sendBarrageBySelf(barrage) {
    this.barrage.barrageEnterQueueSelf(barrage);
    this.barrage.restart();
  }

  // 即時消息彈幕填充
  sendBarrageEnterQueue(list, isFilter = true) {
    this.barrage.barrageEnterQueue(list, isFilter);
  }

  // init直播間的時候,歷史彈幕填充
  multiPushBarrage(list) {
    this.sendBarrageEnterQueue(list, false);
  }
復(fù)制代碼

4.3 用戶行為處理

4.3.1 監(jiān)聽滾動到底部

實(shí)現(xiàn)監(jiān)聽滾到到底部,需要先來了解一下瀏覽器的scrollHegiht、scrollTop、clientHegiht三個屬性。

  • scrollHegiht: 文檔內(nèi)容實(shí)際高度,包括超出視窗的溢出部分。
  • scrollTop: 滾動條滾動距離。
  • clientHeight: 窗口可視范圍高度。

當(dāng) clientHeight + scrollTop >= scrollHeight 時,表示已經(jīng)抵達(dá)內(nèi)容的底部了,可以加載更多內(nèi)容。


4.3.2 滾動事件監(jiān)聽

列表滾動時,由于當(dāng)前實(shí)際上屏的彈幕列表數(shù)量和內(nèi)容(內(nèi)容長度不一,有的 1 行,有的 2 行,有的 3 行)發(fā)生變化,需要先校準(zhǔn)容器的實(shí)際高度,方便后續(xù)做滾動到底部判斷。同時設(shè)置彈幕激活策略,靜止 n 秒后恢復(fù)滾動。

  // 滾動容器會計算高度,并激活彈幕自動恢復(fù)
  handleScrollBarrageContainer({ detail }) {
    this.containerScrollHeight = detail.scrollHeight;
    this.checkContainerClientHeight();
    this.barrage.setActiveAndAutoRestart();
  }

    // 校準(zhǔn)彈幕容器高度
  checkContainerClientHeight() {
    if (!this.containerClientHieghtChecked) {
      wx.createSelectorQuery()
        .in(this as TrivialInstance)
        .select('.live-barrage')
        .fields(
          {
            size: true,
          },
          res => {
            if (res) {
              const { height = 0 } = res;
              if (height === this.containerClientHeight) {
                this.containerClientHieghtChecked = true;
              }
              this.containerClientHeight = height;
            }
          },
        )
        .exec();
    }
  }
復(fù)制代碼

列表滾動到底部,激活彈幕上屏邏輯。

  // 滾動到底部,重新開啟刷新策略
  handleScrollBottom() {
    if (!this.barrageTouch) {
      this.barrage.restart();
    }
  }
復(fù)制代碼

4.3.3 touch 事件監(jiān)聽

用戶觸摸屏幕動作開始時,暫停彈幕上屏邏輯。

  barrageTouchStart() {
    this.barrageTouch = true;
    this.barrage.pause();
  }
復(fù)制代碼

用戶觸摸動作結(jié)束時,判斷是否滾動到底部,如果是的話,恢復(fù)彈幕上屏邏輯

  // 判斷彈幕是否到底
  barrageTouchEnd() {
    this.barrageTouch = false;
    wx.createSelectorQuery()
      .in(this as TrivialInstance)
      .select('.live-barrage')
      .fields(
        {
          scrollOffset: true,
        },
        ({ scrollTop }) => {
          if (
            this.containerClientHeight + scrollTop + 5 >=
            this.containerScrollHeight
          ) {
            this.begainScroll = true;
            this.barrage.restart();
          }
        },
      )
      .exec();
  }
復(fù)制代碼

5 總結(jié)

以上便是我對彈幕組件設(shè)計的理解,花了一個周末,時間略微倉促,寫作水平有限,在某些問題上解釋說明若有出入,還請批評指教!

相關(guān)案例查看更多