狠狠色丁香婷婷综合尤物/久久精品综合一区二区三区/中国有色金属学报/国产日韩欧美在线观看 - 国产一区二区三区四区五区tv

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

requestAnimationFrame和使用場景舉例

freeflydom
2024年8月15日 9:26 本文熱度 1405

一項新技術新的技術方案的提出,一定是為了解決某個問題的,或者是對某種方案的優化,比如window.requestAnimationFrame這個api...

requestAnimationFrame官方介紹

requestAnimationFrame用處概述

window.requestAnimationFrame() 告訴瀏覽器——你希望執行一個動畫,并且要求瀏覽器在下次重繪之前調用指定的回調函數更新動畫。該方法需要傳入一個回調函數作為參數,該回調函數會在瀏覽器下一次重繪之前執行...

官方文檔對應截圖

官方文檔:developer.mozilla.org/zh-CN/docs/…

大致看了以后,我們可以知道:

requestAnimationFrame這個api主要是用來做動畫的。

requestAnimationFrame這個api主要是用來做動畫的。

requestAnimationFrame這個api主要是用來做動畫的。

其實顧名思義,我們翻譯這個英文單詞,也能大致明白。request(請求)Animation(動畫)Frame(幀)

關于前端動畫的兩個問題:

1.前端動畫方案有哪些?

2.為何偏偏要使用這個新的api來做動畫(或者說這個api較之前做動畫的方式優點有哪些)?

1.前端動畫方案有哪些?

主要分類為css動畫js動畫,如下細分:

  • css動畫

    • transition過渡動畫

    • animation直接動畫(搭配@keyframes

  • js動畫

    • setIntervalsetTimeout定時器(比如不停地更改dom元素的位置,使其運動起來)

    • canvas動畫,搭配js中的定時器去運動起來(canvas只是一個畫筆,然后我們通過定時器會使用這個畫筆去畫畫-動畫)

    • requestAnimationFrame動畫(js動畫中的較好方案)

另有svg動畫標簽,不過工作中這種方式是比較少的,這里不贅述

2.為何偏偏要使用這個新的api來做動畫(或者說這個api較之前做動畫的方式優點有哪些)?

在工作中,做動畫最優的方案無疑是css動畫,但是某些特定場景下,css動畫無法實現我們所需要的需求,此時,我們就要考慮使用js去做動畫了

canvas動畫本質也是定時器動畫

使用定時器動畫干活,實際上是可以的,但是存在一個最大的問題,就是動畫會抖動動畫會抖動動畫會抖動,體驗效果不是非常好。

而,使用requestAnimationFrame去做動畫,就不會抖動就不會抖動就不會抖動

這里筆者寫一個demo動畫(分別是上述兩種方式實現dom元素向右平移)給大家看一下,就知道具體的區別。我們先看一下效果圖:(紅色dom是定時器實現、綠色domrequestAnimationFrame實現)

因為筆者的gif錄制軟件的問題,看著都有點卡,實際上,大家把下方代碼復制一份跑起來看的話,會發現定時器動畫在微微顫抖,而requestAnimationFrame動畫卻穩如老狗

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>requestAnimationFrame_yyds</title>

<style>

body {

box-sizing: border-box;

background-color: #ccc;

}


.box1,

.box2 {

position: absolute;

width: 160px;

height: 160px;

line-height: 160px;

text-align: center;

color: #fff;

font-size: 13px;

}

.box1 {

top: 40px;

background: red;

}

.box2 {

top: 210px;

background: green;

}

</style>

</style>

</head>

<body>

<button>let's go!</button>

<div>定時器動畫</div>

<div>請求動畫幀</div>

<script>

// 動畫思路:不斷修改dom元素的left值,使其運動起來(動畫)

let box1 = document.querySelector('.box1')

let box2 = document.querySelector('.box2')


// setInterval定時器方式

function setIntervalFn() {

let timer = null

box1.style.left = '0px'

timer = setInterval(() => {

let leftVal = parseInt(box1.style.left)

if (leftVal >= 720) {

clearInterval(timer)

} else {

box1.style.left = leftVal + 1 + 'px'

}

}, 17)

}


// requestAnimationFrame請求動畫幀方式

function requestAnimationFrameFn() {

let timer = null // 可注掉

box2.style.left = '0px'

function callbackFn() {

let leftVal = parseInt(box2.style.left)

if (leftVal >= 720) {

// 不再繼續遞歸調用即可,就不會繼續執行了,下面這個加不加都無所謂,因為影響不到

// cancelAnimationFrame取消請求動畫幀,用的極少,看下,下文中的回到頂部組件

// 大家會發現并沒有使用到這個api(這樣寫只是和clearInterval做一個對比)

// 畢竟,正常情況下,requestAnimationFrame會自動停下來

cancelAnimationFrame(timer) // 可注掉(很少用到)

} else {

box2.style.left = leftVal + 1 + 'px'

window.requestAnimationFrame(callbackFn)

}

}

window.requestAnimationFrame(callbackFn)

}


// 動畫綁定

let btn = document.querySelector('.btn')

btn.addEventListener('click', () => {

setIntervalFn()

requestAnimationFrameFn()

})

</script>

</body>

</html>


Chrome瀏覽器查看當前幀數命令:1. F12打開控制臺2. command + shift + p調出輸入面板3. 在Run輸入框中輸入:Show frames per second(FPS) meter回車即可

通過上述的例子,我們可以回答這個問題了:

  • 面試官問:requestAnimationFrame比定時器好在哪里?

  • 候選人答:好在比較穩定,動畫不卡頓

  • 面試官說:你回去等通知吧...

所以在這里,我們還要順帶延伸一下,為什么定時器會卡,而requestAnimationFrame不會卡。在說這個問題之前,這里再提一下,requestAnimationFrame的語法規則

requestAnimationFrame的語法規則

一言以蔽之:requestAnimationFramejs中的setTimeout定時器函數基本一致,不過setTimeout可以自由設置間隔時間,而requestAnimationFrame的間隔時間是由瀏覽器自身決定的,大約是17毫秒左右

1.requestAnimationFrame我們可以在控制臺輸入window,然后展開查看其身上的屬性,就能找到了,如下圖:

2.由上圖我們可以看到,requestAnimationFrame本質上是一個全局window對象上的一個屬性函數,函數是要被執行的,要被調用的。所以我們使時,直接:window.requestAnimationFrame(callBack)即可。

3.和定時器一樣其接收的參數callback也是一個函數,即下一次重繪之前更新動畫幀所調用的函數,即在這個函數體中,我們可以寫對應的邏輯代碼(和定時器類似)

4.requestAnimationFrame也有返回值,返回值是一個整數,主要是定時器的身份證標識,可以使用 window.cancelAnimationFrame()來取消回調函數執行,相當于定時器中的clearTimeout()

5.二者也都是只執行一次,想要繼續執行,做到類似setInterval的效果,需要寫成遞歸的形式(上述案例中也提到了)

為什么定時器會卡,而requestAnimationFrame不會卡

為什么定時器會卡

  • 我們在手機或者電腦顯示屏上看東西時,顯示屏會默默的不停地干活(刷新畫面)

  • 這個刷新值得是每秒鐘刷新次數,普通顯示器的刷新率約為60Hz(每秒刷新60次),高檔的有75Hz、90Hz、120Hz、144Hz等等

  • 刷新率次數越高,顯示器顯示的圖像越清晰、越流暢、越絲滑

  • 不刷新就是靜態的畫面,刷新比較低就是卡了PPT的感覺

  • 動畫想要絲滑流暢,需要卡住時間點進行代碼操作(代碼語句賦值、瀏覽器重繪)

  • 所以只需要每隔1000毫秒的60分之一(60HZ)即約為17毫秒,進行一次動畫操作即可

  • 只要卡住這個17毫秒,每隔17毫秒進行操作,就能確保動畫絲滑

  • 但是定時器的回調函數,會受到js的事件隊列宏任務、微任務影響,可能設定的是17毫秒執行一次,但是實際上這次是17毫秒、下次21毫秒、再下次13毫秒執行,所以并不是嚴格的卡住了這個60HZ的時間

  • 沒有在合適的時間點操作,就會出現:類似這樣的情況:不變不變不變...

  • 于是就出現了,繪制不及時的情況,就會有抖動的出現(以上述案例,位置和時間沒有線性對應更新變化導致看起來抖動)

js執行代碼是很快的,可能不到一毫秒,大家可以使用相應console的api去測試,如下:

console.time()

let box1 = document.querySelector('.box1')

box1.style.left = '100px'

console.timeEnd()


// js執行耗時結果:default: 0.044189453125 ms


為何requestAnimationFrame不會卡

requestAnimationFrame能夠做到,精準嚴格的卡住顯示器刷新的時間,比如普通顯示器60HZ它會自動對應17ms執行一次,比如高級顯示器120HZ,它會自動對應9ms執行一次。

當然requestAnimationFrame只會執行一次,想要使其多次執行,要寫成遞歸的形式。上述案例也給出了遞歸寫法

至于為何requestAnimationFrame能夠卡住時間,其底層原理又是啥?本文暫且按下不表。

所以,這就是requestAnimationFrame的好處。

所以,上述內容驗證了:一項新技術新的技術方案的提出,一定是為了解決相關的問題的。

所以,window.requestAnimationFrame這個api就是解決了定時器不精準的問題的。

這就是其產生的原因。

requestAnimationFrame應用場景舉例-回到頂部組件

比如:回到頂部組件,就是使用requestAnimationFrame實現的。

下面是筆者封裝的回到頂部組件效果圖和代碼

效果圖:

也可以去筆者的網站上去看效果哦:ashuai.work:8888/#/myBack

代碼:

<template>

  <transition name="fade-transform">

    <div

      v-show="visible"

     

      :style="{

        bottom: bottom + 'px',

        right: right + 'px',

      }"

      @click="goToTop"

    >

      <slot></slot>

    </div>

  </transition>

</template>


<script>

export default {

  name: "myBack",

  props: {

    bottom: {

      type: Number,

      default: 72,

    },

    right: {

      type: Number,

      default: 72,

    },

    // 回到頂部出現的滾動高度位置

    showHeight: {

      type: Number,

      default: 240,

    },

    // 擁有滾動條的那個dom元素的id或者class,用于下方選中操作更改滾動條滾動距離

    scrollBarDom: String,

  },

  data() {

    return {

      visible: false,

      scrollDom: null,

    };

  },

  mounted() {

    if (document.querySelector(this.scrollBarDom)) {

      this.scrollDom = document.querySelector(this.scrollBarDom);

      // 不用給window綁定監聽滾動事件,給對應滾動條元素綁定即可

      this.scrollDom.addEventListener("scroll", this.isShowGoToTop, true);

    }

  },

  beforeDestroy() {

    // 最后要解除監聽滾動事件

    this.scrollDom.removeEventListener("scroll", this.isShowGoToTop, true);

  },

  methods: {

    isShowGoToTop() {

      // 獲取滾動的元素,即有滾動條的那個元素

      if (this.scrollDom.scrollTop > 20) {

        this.visible = true;

      } else {

        this.visible = false;

      }

    },

    goToTop() {

      // 獲取滾動的元素,即有滾動條的那個元素

      let scrollDom = document.querySelector(this.scrollBarDom);

      // 獲取垂直滾動的距離,看看滾動了多少了,然后不斷地修改滾動距離直至為0

      let scrollDistance = scrollDom.scrollTop;


      /**

       * window.requestAnimationFrame兼容性已經可以了,正常都有的

       * */

      if (window.requestAnimationFrame) {

        let fun = () => {

          scrollDom.scrollTop = scrollDistance -= 36;

          if (scrollDistance > 0) {

            window.requestAnimationFrame(fun); // 只執行一次,想多次執行需要再調用

          } else {

            scrollDom.scrollTop = 0;

          }

        };

        window.requestAnimationFrame(fun);

        return;

      }


      /**

       * 沒有requestAnimationFrame的話,就用定時器去更改滾動條距離,使之滾動

       * */

      let timer2 = setInterval(() => {

        scrollDom.scrollTop = scrollDistance -= 36;

        if (scrollDistance <= 0) {

          clearInterval(timer2);

          scrollDom.scrollTop = 0;

        }

      }, 17);

    },

  },

};

</script>


<style scoped>

.backWrap {

  position: fixed;

  cursor: pointer;

  width: 42px;

  height: 42px;

  background: #9cc2e5;

  border-radius: 4px;

  display: flex;

  justify-content: center;

  align-items: center;

  transition: all 0.5s;

}


// 過渡效果

.fade-transform-leave-active,

.fade-transform-enter-active {

  transition: all 0.36s;

}


.fade-transform-enter {

  opacity: 0;

  transform: translateY(-5px);

}

.fade-transform-leave-to {

  opacity: 0;

  transform: translateY(5px);

}

</style>


GitHub倉庫地址:github.com/shuirongshu…

另外,有一個做滾動的插件庫,叫做vue-seamless-scroll其內部實現原理也是基于requestAnimationFrame實現的。感興趣的道友可以去看看

類比學習reduce循環解決了forEach循環可能需要一個初始變量的問題

我們類比一下學習,比如既然有了forEach循環,為啥還又新推出一個reduce循環呢?

原因:某些場景下,reduce循環解決了forEach循環還需要再定義一個變量的問題。

似曾相識的感覺...

比如我們有一個需求,給一個數組求和。

forEach寫法

let arr = [1, 3, 5, 7, 9]

function forEachFn(params) {

    let total = 0

    params.forEach((num) => {

        total = total + num

    })

    return total

}

let res1 = forEachFn(arr)

console.log(res1);


reduce寫法

let arr = [1, 3, 5, 7, 9]

function reduceFn(params) {

    return params.reduce((temp, num) => {

        temp = temp + num

        return temp

    }, 0)

}

let res2 = reduceFn(arr)

console.log(res2);


通過上述兩段代碼,我們可以看到,reduce函數比forEach少寫了一個total變量,千萬不要小看這少寫的東西,某些情況下,會節省很多的工作量呢!


作者:水冗水孚
鏈接:https://juejin.cn/post/7190728064458817591
來源:稀土掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。



該文章在 2024/8/16 10:26:10 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved