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

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

requestAnimationFrame和使用場(chǎng)景舉例

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

一項(xiàng)新技術(shù)新的技術(shù)方案的提出,一定是為了解決某個(gè)問題的,或者是對(duì)某種方案的優(yōu)化,比如window.requestAnimationFrame這個(gè)api...

requestAnimationFrame官方介紹

requestAnimationFrame用處概述

window.requestAnimationFrame() 告訴瀏覽器——你希望執(zhí)行一個(gè)動(dòng)畫,并且要求瀏覽器在下次重繪之前調(diào)用指定的回調(diào)函數(shù)更新動(dòng)畫。該方法需要傳入一個(gè)回調(diào)函數(shù)作為參數(shù),該回調(diào)函數(shù)會(huì)在瀏覽器下一次重繪之前執(zhí)行...

官方文檔對(duì)應(yīng)截圖

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

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

requestAnimationFrame這個(gè)api主要是用來做動(dòng)畫的。

requestAnimationFrame這個(gè)api主要是用來做動(dòng)畫的。

requestAnimationFrame這個(gè)api主要是用來做動(dòng)畫的。

其實(shí)顧名思義,我們翻譯這個(gè)英文單詞,也能大致明白。request(請(qǐng)求)Animation(動(dòng)畫)Frame(幀)

關(guān)于前端動(dòng)畫的兩個(gè)問題:

1.前端動(dòng)畫方案有哪些?

2.為何偏偏要使用這個(gè)新的api來做動(dòng)畫(或者說這個(gè)api較之前做動(dòng)畫的方式優(yōu)點(diǎn)有哪些)?

1.前端動(dòng)畫方案有哪些?

主要分類為css動(dòng)畫js動(dòng)畫,如下細(xì)分:

  • css動(dòng)畫

    • transition過渡動(dòng)畫

    • animation直接動(dòng)畫(搭配@keyframes

  • js動(dòng)畫

    • setIntervalsetTimeout定時(shí)器(比如不停地更改dom元素的位置,使其運(yùn)動(dòng)起來)

    • canvas動(dòng)畫,搭配js中的定時(shí)器去運(yùn)動(dòng)起來(canvas只是一個(gè)畫筆,然后我們通過定時(shí)器會(huì)使用這個(gè)畫筆去畫畫-動(dòng)畫)

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

另有svg動(dòng)畫標(biāo)簽,不過工作中這種方式是比較少的,這里不贅述

2.為何偏偏要使用這個(gè)新的api來做動(dòng)畫(或者說這個(gè)api較之前做動(dòng)畫的方式優(yōu)點(diǎn)有哪些)?

在工作中,做動(dòng)畫最優(yōu)的方案無疑是css動(dòng)畫,但是某些特定場(chǎng)景下,css動(dòng)畫無法實(shí)現(xiàn)我們所需要的需求,此時(shí),我們就要考慮使用js去做動(dòng)畫了

canvas動(dòng)畫本質(zhì)也是定時(shí)器動(dòng)畫

使用定時(shí)器動(dòng)畫干活,實(shí)際上是可以的,但是存在一個(gè)最大的問題,就是動(dòng)畫會(huì)抖動(dòng)動(dòng)畫會(huì)抖動(dòng)動(dòng)畫會(huì)抖動(dòng),體驗(yàn)效果不是非常好。

而,使用requestAnimationFrame去做動(dòng)畫,就不會(huì)抖動(dòng)就不會(huì)抖動(dòng)就不會(huì)抖動(dòng)

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

因?yàn)楣P者的gif錄制軟件的問題,看著都有點(diǎn)卡,實(shí)際上,大家把下方代碼復(fù)制一份跑起來看的話,會(huì)發(fā)現(xiàn)定時(shí)器動(dòng)畫在微微顫抖,而requestAnimationFrame動(dòng)畫卻穩(wěn)如老狗

<!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>定時(shí)器動(dòng)畫</div>

<div>請(qǐng)求動(dòng)畫幀</div>

<script>

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

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

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


// setInterval定時(shí)器方式

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請(qǐng)求動(dòng)畫幀方式

function requestAnimationFrameFn() {

let timer = null // 可注掉

box2.style.left = '0px'

function callbackFn() {

let leftVal = parseInt(box2.style.left)

if (leftVal >= 720) {

// 不再繼續(xù)遞歸調(diào)用即可,就不會(huì)繼續(xù)執(zhí)行了,下面這個(gè)加不加都無所謂,因?yàn)橛绊懖坏?/span>

// cancelAnimationFrame取消請(qǐng)求動(dòng)畫幀,用的極少,看下,下文中的回到頂部組件

// 大家會(huì)發(fā)現(xiàn)并沒有使用到這個(gè)api(這樣寫只是和clearInterval做一個(gè)對(duì)比)

// 畢竟,正常情況下,requestAnimationFrame會(huì)自動(dòng)停下來

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

} else {

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

window.requestAnimationFrame(callbackFn)

}

}

window.requestAnimationFrame(callbackFn)

}


// 動(dòng)畫綁定

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

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

setIntervalFn()

requestAnimationFrameFn()

})

</script>

</body>

</html>


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

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

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

  • 候選人答:好在比較穩(wěn)定,動(dòng)畫不卡頓

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

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

requestAnimationFrame的語法規(guī)則

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

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

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

3.和定時(shí)器一樣其接收的參數(shù)callback也是一個(gè)函數(shù),即下一次重繪之前更新動(dòng)畫幀所調(diào)用的函數(shù),即在這個(gè)函數(shù)體中,我們可以寫對(duì)應(yīng)的邏輯代碼(和定時(shí)器類似)

4.requestAnimationFrame也有返回值,返回值是一個(gè)整數(shù),主要是定時(shí)器的身份證標(biāo)識(shí),可以使用 window.cancelAnimationFrame()來取消回調(diào)函數(shù)執(zhí)行,相當(dāng)于定時(shí)器中的clearTimeout()

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

為什么定時(shí)器會(huì)卡,而requestAnimationFrame不會(huì)卡

為什么定時(shí)器會(huì)卡

  • 我們?cè)谑謾C(jī)或者電腦顯示屏上看東西時(shí),顯示屏?xí)牟煌5馗苫睿ㄋ⑿庐嬅妫?/p>

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

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

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

  • 動(dòng)畫想要絲滑流暢,需要卡住時(shí)間點(diǎn)進(jìn)行代碼操作(代碼語句賦值、瀏覽器重繪)

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

  • 只要卡住這個(gè)17毫秒,每隔17毫秒進(jìn)行操作,就能確保動(dòng)畫絲滑

  • 但是定時(shí)器的回調(diào)函數(shù),會(huì)受到j(luò)s的事件隊(duì)列宏任務(wù)、微任務(wù)影響,可能設(shè)定的是17毫秒執(zhí)行一次,但是實(shí)際上這次是17毫秒、下次21毫秒、再下次13毫秒執(zhí)行,所以并不是嚴(yán)格的卡住了這個(gè)60HZ的時(shí)間

  • 沒有在合適的時(shí)間點(diǎn)操作,就會(huì)出現(xiàn):類似這樣的情況:不變不變不變...

  • 于是就出現(xiàn)了,繪制不及時(shí)的情況,就會(huì)有抖動(dòng)的出現(xiàn)(以上述案例,位置和時(shí)間沒有線性對(duì)應(yīng)更新變化導(dǎo)致看起來抖動(dòng))

js執(zhí)行代碼是很快的,可能不到一毫秒,大家可以使用相應(yīng)console的api去測(cè)試,如下:

console.time()

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

box1.style.left = '100px'

console.timeEnd()


// js執(zhí)行耗時(shí)結(jié)果:default: 0.044189453125 ms


為何requestAnimationFrame不會(huì)卡

requestAnimationFrame能夠做到,精準(zhǔn)嚴(yán)格的卡住顯示器刷新的時(shí)間,比如普通顯示器60HZ它會(huì)自動(dòng)對(duì)應(yīng)17ms執(zhí)行一次,比如高級(jí)顯示器120HZ,它會(huì)自動(dòng)對(duì)應(yīng)9ms執(zhí)行一次。

當(dāng)然requestAnimationFrame只會(huì)執(zhí)行一次,想要使其多次執(zhí)行,要寫成遞歸的形式。上述案例也給出了遞歸寫法

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

所以,這就是requestAnimationFrame的好處。

所以,上述內(nèi)容驗(yàn)證了:一項(xiàng)新技術(shù)新的技術(shù)方案的提出,一定是為了解決相關(guān)的問題的。

所以,window.requestAnimationFrame這個(gè)api就是解決了定時(shí)器不精準(zhǔn)的問題的。

這就是其產(chǎn)生的原因。

requestAnimationFrame應(yīng)用場(chǎng)景舉例-回到頂部組件

比如:回到頂部組件,就是使用requestAnimationFrame實(shí)現(xiàn)的。

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

效果圖:

也可以去筆者的網(wǎng)站上去看效果哦: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,

    },

    // 回到頂部出現(xiàn)的滾動(dòng)高度位置

    showHeight: {

      type: Number,

      default: 240,

    },

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

    scrollBarDom: String,

  },

  data() {

    return {

      visible: false,

      scrollDom: null,

    };

  },

  mounted() {

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

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

      // 不用給window綁定監(jiān)聽滾動(dòng)事件,給對(duì)應(yīng)滾動(dòng)條元素綁定即可

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

    }

  },

  beforeDestroy() {

    // 最后要解除監(jiān)聽滾動(dòng)事件

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

  },

  methods: {

    isShowGoToTop() {

      // 獲取滾動(dòng)的元素,即有滾動(dòng)條的那個(gè)元素

      if (this.scrollDom.scrollTop > 20) {

        this.visible = true;

      } else {

        this.visible = false;

      }

    },

    goToTop() {

      // 獲取滾動(dòng)的元素,即有滾動(dòng)條的那個(gè)元素

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

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

      let scrollDistance = scrollDom.scrollTop;


      /**

       * window.requestAnimationFrame兼容性已經(jīng)可以了,正常都有的

       * */

      if (window.requestAnimationFrame) {

        let fun = () => {

          scrollDom.scrollTop = scrollDistance -= 36;

          if (scrollDistance > 0) {

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

          } else {

            scrollDom.scrollTop = 0;

          }

        };

        window.requestAnimationFrame(fun);

        return;

      }


      /**

       * 沒有requestAnimationFrame的話,就用定時(shí)器去更改滾動(dòng)條距離,使之滾動(dòng)

       * */

      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倉(cāng)庫(kù)地址:github.com/shuirongshu…

另外,有一個(gè)做滾動(dòng)的插件庫(kù),叫做vue-seamless-scroll其內(nèi)部實(shí)現(xiàn)原理也是基于requestAnimationFrame實(shí)現(xiàn)的。感興趣的道友可以去看看

類比學(xué)習(xí)reduce循環(huán)解決了forEach循環(huán)可能需要一個(gè)初始變量的問題

我們類比一下學(xué)習(xí),比如既然有了forEach循環(huán),為啥還又新推出一個(gè)reduce循環(huán)呢?

原因:某些場(chǎng)景下,reduce循環(huán)解決了forEach循環(huán)還需要再定義一個(gè)變量的問題。

似曾相識(shí)的感覺...

比如我們有一個(gè)需求,給一個(gè)數(shù)組求和。

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函數(shù)比forEach少寫了一個(gè)total變量,千萬不要小看這少寫的東西,某些情況下,會(huì)節(jié)省很多的工作量呢!


作者:水冗水孚
鏈接:https://juejin.cn/post/7190728064458817591
來源:稀土掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。



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