亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > HTML5 > 正文

HTML5 直播瘋狂點贊動畫實現代碼 附源碼

2024-09-05 07:23:23
字體:
來源:轉載
供稿:網友

直播有一個很重要的互動:點贊。

為了烘托直播間的氛圍,直播相對于普通視頻或者文本內容,點贊通常有兩個特殊需求:

  • 點贊動作無限次,引導用戶瘋狂點贊
  • 直播間的所有瘋狂點贊,都需要在所有用戶界面都動畫展現出來

我們先來看效果圖:

從效果圖上我們還看到有幾點重要信息:

點贊動畫圖片大小不一,運動軌跡也是隨機的 點贊動畫圖片都是先放大再勻速運動。 快到頂部的時候,是漸漸消失。 收到大量的點贊請求的時候,點贊動畫不扎堆,井然有序持續出現。

那么如何實現這些要求呢?下面介紹兩種實現方式來實現(底部附完整 demo):

CSS3 實現

用 CSS3 實現動畫,顯然,我們想到的是用 animation 。

首先看下 animation 合并寫法,具體含義就不解釋了,如果需要可以自行了解。

animation: name duration timing-function delay iteration-count direction fill-mode play-state;

我們開始來一步一步實現。

Step 1: 固定區域,設置基本樣式

首先,我們先準備 1 張點贊動畫圖片:

看一下 HTML 結構。外層一個結構固定整個顯示動畫區域的位置。這里在一個寬 100px ,高 200px 的 div 區域。

<div class="praise_bubble">  <div class="bubble b1 bl1"></div></div>.praise_bubble{  width:100px;  height:200px;  position:relative;  background-color:#f4f4f4;}.bubble{    position: absolute;    left:50%;    bottom:0;}

 

Step 2: 運動起來

使用 animation 的幀動畫,定義一個 bubble_y 的幀序列。

.bl1{    animation:bubble_y 4s linear 1 forwards ;  }@keyframes bubble_y {    0% {        margin-bottom:0;    }    100% {        margin-bottom:200px;    }}

這里設置運行時間 4s ;

采用線性運動 linear,如果有需求當然也可以使用其他曲線,比如 ease;

每個點贊動畫只運行 1 次;

動畫是只需要向前 forwards。

 

Step 3: 增加漸隱

漸隱效果,使用 opacity 即可。這里我們固定在最后 1/4 開始漸隱。 修改 bubble_y:

@keyframes bubble_y {    0% {        margin-bottom:0;    }    75%{        opacity:1;    }    100% {        margin-bottom:200px;        opacity:0;    }}

 

Step 4: 增加動畫放大效果

在最開始一小段時間,圖片由小變大。

于是我們新增一個動畫:bubble_big_1。

這里從 0.3 倍原圖放大到 1 倍。這里注意運行時間,比如上面設置,從動畫開始到結束總共是 4s,那么這個放大時間就可以按需設置了,比如 0.5s。

.bl1{    animation:bubble_big 0.5s linear 1 forwards;  }@keyframes bubble_big_1 {    0% {        transform: scale(.3);    }    100% {        transform: scale(1);    }  }

 

Step 5: 設置偏移

我們先定義幀動畫:bubble_1 來執行偏移。圖片開始放大階段,這里沒有設置偏移,保持中間原點不變。

在運行到 25% * 4 = 1s,即 1s之后,是向左偏移 -8px, 2s 的時候,向右偏移 8px,3s 的時候,向做偏移 15px ,最終向右偏移 15px。

大家可以想到了,這是定義的一個經典的左右擺動軌跡,“向左向右向左向右” 曲線擺動效果。

@keyframes bubble_1 {    0% {    }    25% {        margin-left:-8px;    }    50% {        margin-left:8px    }    75% {        margin-left:-15px    }    100% {        margin-left:15px    }}

效果圖如下:

 

Step 6: 補齊動畫樣式

這里預設了一種運行曲線軌跡,左右擺動的樣式,我們在再預設更多種曲線,達到隨機軌跡的目的。

比如 bubble_1 的左右偏移動畫軌跡,我們可以修改偏移值,來達到不同的曲線軌跡。

Step 7: JS 操作隨機增加節點樣式

提供增加點贊的方法,隨機將點贊的樣式組合,然后渲染到節點上。

let praiseBubble = document.getElementById("praise_bubble");let last = 0;function addPraise() {    const b =Math.floor(Math.random() * 6) + 1;    const bl =Math.floor(Math.random() * 11) + 1; // bl1~bl11    let d = document.createElement("div");    d.className = `bubble b$ bl${bl}`;    d.dataset.t = String(Date.now());    praiseBubble.appendChild(d);}setInterval(() => {    addPraise();},300)

在使用 CSS 來實現點贊的時候,通常還需要注意設置 bubble 的隨機延時,比如:

.bl2{    animation:bubble_2 $bubble_time linear .4s 1 forwards,bubble_big_2 $bubble_scale linear .4s 1 forwards,bubble_y $bubble_time linear .4s 1 forwards;   }

這里如果是隨機到 bl2,那么延時 0.4s 再運行,bl3 延時 0.6s ……

如果是批量更新到節點上,不設置延時的話,那就會扎堆出現。隨機“ bl ”樣式,就隨機了延時,然后批量出現,都會自動錯峰顯示。當然,我們還需要增加當前用戶手動點贊的動畫,這個不需要延時。

另外,有可能同時別人下發了點贊 40 個,業務需求通常是希望這 40 個點贊氣泡都能依次出現,制造持續的點贊氛圍,否則下發量大又會扎堆顯示了。

那么我們還需要分批打散點贊數量,比如一次點贊的時間($bubble_time)是 4s, 那么 4s 內,希望同時出現多少個點贊呢?比如是 10個,那么 40 個點贊,需要分批 4 次渲染。

window.requestAnimationFrame(() => {     // 繼續循環處理批次     render(); });

另外還需要手動清除節點。以防節點過多帶來的性能問題。如下是完整的效果圖。

 

Canvas 繪圖實現

這個很容易理解,直接在 canvas 上繪制動畫就行,如果不了解 canvas 的,可以后續學習下。

Step 1:初始化

頁面元素上新建 canvas 標簽,初始化 canvas。

canvas 上可以設置 width 和 height 屬性,也可以在 style 屬性里面設置 width 和 height。

  • canvas 上 style 的 width 和 height 是 canvas 在瀏覽器中被渲染的高度和寬度,即在頁面中的實際寬高。
  • canvas 標簽的 width 和 height 是畫布實際寬度和高度。
<canvas id="thumsCanvas" width="200" height="400" style="width:100px;height:200px"></canvas>

頁面上一個寬 200,高 400 的 canvas 畫布,然后整個 canvas 顯示在 頁面 寬 100,高 200 的區域內。canvas 畫布的內容被等比縮小一倍顯示在頁面。

定義一個點贊類,ThumbsUpAni,構造函數就是讀取 canvas,保存寬高值。

class ThumbsUpAni{    constructor(){        const canvas = document.getElementById('thumsCanvas');        this.context = canvas.getContext('2d')!;        this.width = canvas.width;        this.height = canvas.height;    }}

Step 2:提前加載圖片資源

將需要隨機渲染的點贊圖片,先預加載,獲得圖片的寬高,如果有下載失敗的,則不顯示該隨機圖片即可。沒啥說的,簡單易懂。

loadImages(){    const images = [        'jfs/t1/93992/8/9049/4680/5e0aea04Ec9dd2be8/608efd890fd61486.png',        'jfs/t1/108305/14/2849/4908/5e0aea04Efb54912c/bfa59f27e654e29c.png',        'jfs/t1/98805/29/8975/5106/5e0aea05Ed970e2b4/98803f8ad07147b9.png',        'jfs/t1/94291/26/9105/4344/5e0aea05Ed64b9187/5165fdf5621d5bbf.png',        'jfs/t1/102753/34/8504/5522/5e0aea05E0b9ef0b4/74a73178e31bd021.png',        'jfs/t1/102954/26/9241/5069/5e0aea05E7dde8bda/720fcec8bc5be9d4.png'    ];    const promiseAll = [] as Array<Promise<any>>;    images.forEach((src) => {        const p = new Promise(function (resolve) {            const img = new Image;            img.onerror = img.onload = resolve.bind(null, img);            img.src = 'https://img12.360buyimg.com/img/' + src;        });        promiseAll.push(p);    });    Promise.all(promiseAll).then((imgsList) => {        this.imgsList = imgsList.filter((d) => {            if (d && d.width > 0) return true;            return false;        });        if (this.imgsList.length == 0) {            logger.error('imgsList load all error');            return;        }    })}

Step 2:創建渲染對象

實時渲染圖片,使其變成一個連貫的動畫,很重要的是:生成曲線軌跡。這個曲線軌跡需要是平滑的均勻曲線。 假如生成的曲線軌跡不平滑的話,那看到的效果就會太突兀,比如上一個是 10 px,下一個就是 -10px,那顯然,動畫就是忽左忽右左右閃爍了。

理想的軌跡是上一個位置是 10px,接下來是 9px,然后一直平滑到 -10px,這樣的坐標點就是連貫的,看起來動畫就是平滑運行。

隨機平滑 X 軸偏移

如果要做到平滑曲線,其實可以使用我們再熟悉不過的正弦( Math.sin )函數來實現均勻曲線。

看下圖的正弦曲線:

這是 Math.sin(0) 到 Math.sin(9) 的曲線圖走勢圖,它是一個平滑的從正數到負數,然后再從負數到正數的曲線圖,完全符合我們的需求,于是我們再需要生成一個隨機比率值,讓擺動幅度隨機起來。

const angle = getRandom(2, 10);let ratio = getRandom(10,30)*((getRandom(0, 1) ? 1 : -1));const getTranslateX = (diffTime) => {    if (diffTime < this.scaleTime) {// 放大期間,不進行搖擺偏移        return basicX;    } else {        return basicX + ratio*Math.sin(angle*(diffTime - this.scaleTime));    }};

scaleTime 是從開始放大到最終大小,用多長時間,這里我們設置 0.1,即總共運行時間前面的 10% 的時間,點贊圖片逐步放大。

diffTime,是只從開始動畫運行到當前時間過了多長時間了,為百分比。實際值是從 0 --》 1 逐步增大。 diffTime - scaleTime = 0 ~ 0.9, diffTime 為 0.4 的時候,說明是已經運行了 40% 的時間。

因為 Math.sin(0) 到 Math.sin(0.9) 曲線幾乎是一個直線,所以不太符合擺動效果,從 Math.sin(0) 到 Math.sin(1.8) 開始有細微的變化,所以我們這里設置的 angle 最小值為 2。

這里設置角度系數 angle 最大為 10 ,從底部到頂部運行兩個波峰。

當然如果運行距離再長一些,我們可以增大 angle 值,比如變成 3 個波峰(如果時間短,出現三個波峰,就會運行過快,有閃爍現象)。如下圖:

 

Y 軸偏移

這個容易理解,開始 diffTime 為 0 ,所以運行偏移從 this.height --> image.height / 2。即從最底部,運行到頂部留下,實際上我們在頂部會淡化隱藏。

const getTranslateY = (diffTime) => {    return image.height / 2 + (this.height - image.height / 2) * (1-diffTime);};

放大縮小

當運行時間 diffTime 小于設置的 scaleTime 的時候,按比例隨著時間增大,scale 變大。超過設置的時間閾值,則返回最終大小。

const basicScale = [0.6, 0.9, 1.2][getRandom(0, 2)];const getScale = (diffTime) => {    if (diffTime < this.scaleTime) {        return +((diffTime/ this.scaleTime).toFixed(2)) * basicScale;    } else {        return basicScale;    }};

淡出

同放大邏輯一致,只不過淡出是在運行快到最后的位置開始生效。

const fadeOutStage = getRandom(14, 18) / 100;const getAlpha = (diffTime) => {    let left = 1 - +diffTime;    if (left > fadeOutStage) {        return 1;    } else {        return 1 - +((fadeOutStage - left) / fadeOutStage).toFixed(2);    }};

實時繪制

創建完繪制對象之后,就可以實時繪制了,根據上述獲取到的“偏移值”,“放大”和“淡出”值,然后實時繪制點贊圖片的位置即可。

每個執行周期,都需要重新繪制 canvas 上的所有的動畫圖片位置,最終形成所有的點贊圖片都在運動的效果。

createRender(){    return (diffTime) => {        // 差值滿了,即結束了 0 ---》 1        if(diffTime>=1) return true;        context.save();        const scale = getScale(diffTime);        const translateX = getTranslateX(diffTime);        const translateY = getTranslateY(diffTime);        context.translate(translateX, translateY);        context.scale(scale, scale);        context.globalAlpha = getAlpha(diffTime);        // const rotate = getRotate();        // context.rotate(rotate * Math.PI / 180);        context.drawImage(            image,            -image.width / 2,            -image.height / 2,            image.width,            image.height        );        context.restore();    };}

這里繪制的圖片是原圖的 width 和 height。前面我們設置了 basiceScale,如果圖片更大,我們可以把 scale 再變小即可。

const basicScale = [0.6, 0.9, 1.2][getRandom(0, 2)];

實時繪制掃描器

開啟實時繪制掃描器,將創建的渲染對象放入 renderList 數組,數組不為空,說明 canvas 上還有動畫,就需要不停的去執行 scan,直到 canvas 上沒有動畫結束為止。

scan() {    this.context.clearRect(0, 0, this.width, this.height);    this.context.fillStyle = "#f4f4f4";    this.context.fillRect(0,0,200,400);    let index = 0;    let length = this.renderList.length;    if (length > 0) {        requestAnimationFrame(this.scan.bind(this));    }    while (index < length) {        const render = this.renderList[index];        if (!render || !render.render || render.render.call(null, (Date.now() - render.timestamp) / render.duration)) {            // 結束了,刪除該動畫            this.renderList.splice(index, 1);            length--;        } else {            // 當前動畫未執行完成,continue            index++;        }    }}

這里就是根據執行的時間來對比,判斷動畫執行到的位置了:

diffTime = (Date.now() - render.timestamp) / render.duration

如果開始的時間戳是 10000,當前是100100,則說明已經運行了 100 毫秒了,如果動畫本來需要執行 1000 毫秒,那么 diffTime = 0.1,代表動畫已經運行了 10%。

增加動畫

每點贊一次或者每接收到別人點贊一次,則調用一次 start 方法來生成渲染實例,放進渲染實例數組。如果當前掃描器未開啟,則需要啟動掃描器,這里使用了 scanning 變量,防止開啟多個掃描器。

start() {    const render = this.createRender();    const duration = getRandom(1500, 3000);    this.renderList.push({        render,        duration,        timestamp: Date.now(),    });    if (!this.scanning) {        this.scanning = true;        requestFrame(this.scan.bind(this));    }    return this;}

保持不扎堆

當接收到大量的點贊數據,且連續多次點贊(直播間人氣很旺的時候)。那么點贊數據的渲染就需要特別注意了,否則頁面就是一坨一坨的點贊動畫。且銜接不緊密。

thumbsUp(num: number) {      if (num <= this.praiseLast) return;      this.thumbsStart = this.praiseLast;      this.praiseLast = num;      if (this.thumbsStart + 500 < num)        this.thumbsStart = num - 500;      const diff = this.praiseLast - this.thumbsStart;      let time = 100;      let isFirst = true;      if (this.thumbsInter != 0) {        return;      }      this.thumbsInter = setInterval(() => {        if (this.thumbsStart >= this.praiseLast) {          clearInterval(this.thumbsInter);          this.thumbsInter = 0;          return;        }        this.thumbsStart++;        this.thumbsUpAni.start();        if (isFirst) {          isFirst = false;          time = Math.round(5000 / diff);        }      }, time);    },

這里開啟定時器,記錄定時器里面處理的 thumbsStart 的值,如果有新增點贊,且定時器還在運行,直接更新最后的 praiseLast 值,定時器會依次將點贊請求全部處理完。

定時器的延時時間 time 根據開啟定時器的時候,需要渲染多少點贊動畫來決定的,比如需要渲染 100 個點贊動畫,我們將 100 個點贊動畫分布在 5s 內渲染完。

  • 對于熱門直播,會同時渲染的動畫很多,不會扎堆顯示,且動畫完全能銜接上,不停的冒泡點贊動畫。
  • 對于冷門直播,有多余一個的點贊請求,我們能打散到 5s 內顯示,也不會扎堆顯示。

End

兩種方式渲染點贊動畫都已經完成,完整源碼,源碼戳這里 。

源碼運行效果圖:

這里還可以體驗線上點贊動畫, 戳這里

再比較

這兩種實現方式,都可以滿足要求,那么到底哪種更優呢?

我們來看下兩者的數據對比。以下為未開啟硬件加速的對比,采用不間斷瘋狂渲染點贊動畫的數據對比:

整體來說,差異如下:

  • SS3 實現簡單
  • Canvas 更靈活,操作更細膩
  • CSS3 內存消耗比 Canvas 大,如果開啟硬件加速,內存消耗更大一些。

總結

到此這篇關于HTML5 直播瘋狂點贊動畫實現代碼 附源碼的文章就介紹到這了,更多相關html5 直播點贊內容請搜索武林網以前的文章或繼續瀏覽下面的相關文章,希望大家以后多多支持武林網!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲精品午夜精品| 国产成人精品在线观看| 欧美激情视频给我| 欧美一级高清免费播放| 亚洲人成五月天| 亚洲欧洲一区二区三区在线观看| 国产ts人妖一区二区三区| 久久久久久久国产精品| 国产婷婷97碰碰久久人人蜜臀| 韩日欧美一区二区| 一区二区三区视频免费| 欧美激情视频网址| 亚洲精品视频网上网址在线观看| 欧美在线视频在线播放完整版免费观看| 高清欧美电影在线| 亚洲国产高清自拍| 中文字幕无线精品亚洲乱码一区| 97超级碰碰人国产在线观看| 国产精品99久久久久久人| 久久久天堂国产精品女人| 欧美精品激情在线观看| 国产亚洲综合久久| 国产一区二区三区在线视频| 国产精品99久久久久久www| 久久久精品国产| 97超视频免费观看| 在线色欧美三级视频| 国产精品啪视频| 欧美激情区在线播放| 成人免费午夜电影| 永久免费毛片在线播放不卡| www.国产精品一二区| 日韩在线观看免费| 久久综合国产精品台湾中文娱乐网| 久久精品国产69国产精品亚洲| 97av在线视频| 亚洲区在线播放| 91麻豆国产精品| 黄色一区二区在线观看| 亚洲成人999| 亚洲综合在线小说| 亚洲人午夜色婷婷| 亚洲第一精品自拍| 亚洲国产高清高潮精品美女| 欧美丰满片xxx777| 日韩经典一区二区三区| 日韩精品中文在线观看| 亚洲欧美日韩一区二区三区在线| 欧美丰满少妇xxxxx| 欧美精品一本久久男人的天堂| 久久久91精品| 欧美成人小视频| 日韩免费观看网站| 国产99在线|中文| 日韩成人黄色av| 亚洲欧美日韩中文在线| 国产精品青草久久久久福利99| 一区二区欧美日韩视频| 国产精品成久久久久三级| 亚洲天堂av在线免费观看| 欧美一级视频免费在线观看| 日本精品视频网站| 国产婷婷色综合av蜜臀av| 日本乱人伦a精品| 欧日韩不卡在线视频| 欧美成人午夜影院| 日韩美女激情视频| 亚洲精品456在线播放狼人| 91久久精品美女| 狠狠爱在线视频一区| 亚洲夜晚福利在线观看| 在线精品国产成人综合| 欧美视频在线免费看| 视频一区视频二区国产精品| 韩剧1988在线观看免费完整版| 国产日韩精品一区二区| 国产精品永久免费| 国产亚洲一区二区在线| 亚洲香蕉成人av网站在线观看| 精品欧美国产一区二区三区| 91美女片黄在线观| 精品国产区一区二区三区在线观看| 精品日本高清在线播放| 国产精品激情av在线播放| 亚洲少妇激情视频| 亚洲国产另类 国产精品国产免费| 日韩av在线导航| 中文字幕综合一区| 自拍偷拍亚洲精品| 亚洲日本中文字幕| 日本国产高清不卡| 欧美久久精品午夜青青大伊人| 国产美女高潮久久白浆| 欧美第一黄网免费网站| 亚洲视频在线免费看| 国产精品中文字幕久久久| 欧美激情网友自拍| 国产97色在线|日韩| 2018日韩中文字幕| 国产日韩在线视频| 色综合伊人色综合网站| 久久婷婷国产麻豆91天堂| 97人人模人人爽人人喊中文字| 欧美激情久久久久| 九九综合九九综合| 亚洲xxxx18| 亚洲视频在线看| 成人免费在线网址| 欧美大胆在线视频| 日韩av在线一区二区| 欧美亚洲一区在线| 亚洲美女免费精品视频在线观看| 亚洲aⅴ男人的天堂在线观看| 久久亚洲电影天堂| 精品少妇一区二区30p| 国产亚洲欧美日韩美女| 亚洲va电影大全| 日韩有码在线播放| 国产精品精品久久久久久| 日韩av成人在线| 亚洲国产91色在线| 久久久国产精品一区| 久久精品久久久久久国产 免费| 538国产精品视频一区二区| 97国产精品人人爽人人做| 欧美精品久久久久久久免费观看| 欧美激情精品久久久久久黑人| 成人高清视频观看www| 精品视频久久久久久| 4438全国亚洲精品在线观看视频| 欧美视频裸体精品| 中文字幕亚洲精品| 日韩在线观看免费网站| 91在线观看免费高清完整版在线观看| 3344国产精品免费看| 亚洲欧美日韩精品久久亚洲区| 国产成人啪精品视频免费网| 国产精品免费视频xxxx| 久久综合伊人77777尤物| 日本成人激情视频| 精品视频—区二区三区免费| 精品一区二区三区三区| 欧美午夜性色大片在线观看| 欧美性猛交xxxx| 欧美中文字幕在线观看| 国产精品视频xxx| 亚洲图片欧洲图片av| 日韩一中文字幕| 中文字幕国产精品久久| 国产精品啪视频| 亚洲精品中文字幕女同| 欧美日韩一区二区在线播放| 欧美人成在线视频| 日韩成人黄色av| 日韩精品中文字| 国产成人精品综合久久久| 国产日韩精品电影| 97涩涩爰在线观看亚洲| 欧美一区三区三区高中清蜜桃| 三级精品视频久久久久| 欧美日韩中文在线| 国产精品第七十二页| 国产精品7m视频| 欧美日韩亚洲天堂|