国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

目錄
Jump.js
快速了解屏幕背后
一些自定義
測(cè)試頁(yè)面
主腳本
事件委托
單個(gè)處理程序
可訪問(wèn)性注意事項(xiàng)
使用CSS支持原生平滑滾動(dòng)
結(jié)論
關(guān)于使用原生JavaScript進(jìn)行平滑滾動(dòng)的常見(jiàn)問(wèn)題解答 (FAQs)
如何在不使用任何庫(kù)的情況下使用原生JavaScript實(shí)現(xiàn)平滑滾動(dòng)?
為什么我的平滑滾動(dòng)在Safari中不起作用?
如何平滑地滾動(dòng)到特定元素?
我可以控制平滑滾動(dòng)的速度嗎?
如何實(shí)現(xiàn)水平平滑滾動(dòng)?
如何停止平滑滾動(dòng)動(dòng)畫(huà)?
如何實(shí)現(xiàn)具有固定頁(yè)眉的平滑滾動(dòng)?
如何為錨鏈接實(shí)現(xiàn)平滑滾動(dòng)?
如何使用鍵盤(pán)導(dǎo)航實(shí)現(xiàn)平滑滾動(dòng)?
如何測(cè)試我的平滑滾動(dòng)實(shí)現(xiàn)的兼容性?
首頁(yè) web前端 js教程 如何在Vanilla JavaScript中實(shí)現(xiàn)光滑的滾動(dòng)

如何在Vanilla JavaScript中實(shí)現(xiàn)光滑的滾動(dòng)

Feb 18, 2025 am 10:49 AM

How to Implement Smooth Scrolling in Vanilla JavaScript

核心要點(diǎn)

  • 使用Jump.js庫(kù)實(shí)現(xiàn)原生JavaScript平滑滾動(dòng),簡(jiǎn)化滾動(dòng)動(dòng)畫(huà),無(wú)需外部依賴(lài)。
  • 修改Jump.js原始代碼,將其從ES6轉(zhuǎn)換為ES5,以確保與不同瀏覽器的更廣泛兼容性。
  • 使用requestAnimationFrame方法進(jìn)行平滑動(dòng)畫(huà)更新,優(yōu)化性能并提供更流暢的用戶(hù)體驗(yàn)。
  • 實(shí)現(xiàn)自定義JavaScript來(lái)攔截默認(rèn)的頁(yè)面內(nèi)鏈接行為,用平滑滾動(dòng)動(dòng)畫(huà)替換突然跳轉(zhuǎn)。
  • 集成CSS scroll-behavior屬性,以支持識(shí)別此功能的瀏覽器中的原生平滑滾動(dòng),如果瀏覽器不支持,則提供JavaScript后備機(jī)制。
  • 通過(guò)在滾動(dòng)后將焦點(diǎn)設(shè)置到目標(biāo)元素來(lái)確保可訪問(wèn)性,解決鍵盤(pán)導(dǎo)航的潛在問(wèn)題,并增強(qiáng)所有用戶(hù)的可用性。

本文由Adrian Sandu、Chris Perry、Jérémy Heleine和Mallory van Achterberg同行評(píng)審。感謝所有SitePoint的同行評(píng)審者,使SitePoint的內(nèi)容達(dá)到最佳狀態(tài)!

平滑滾動(dòng)是一種用戶(hù)界面模式,它逐步增強(qiáng)了默認(rèn)的頁(yè)面內(nèi)導(dǎo)航體驗(yàn),在滾動(dòng)框(視口或可滾動(dòng)元素)內(nèi)動(dòng)畫(huà)地改變位置,從激活鏈接的位置到鏈接URL的哈希片段中指示的目標(biāo)元素的位置。

這并非什么新鮮事物,多年來(lái)一直是一種已知的模式,例如,請(qǐng)查看這篇可追溯到2003年的SitePoint文章!順便說(shuō)一句,這篇文章具有歷史價(jià)值,因?yàn)樗故玖丝蛻?hù)端JavaScript編程,特別是DOM,多年來(lái)的變化和發(fā)展,允許開(kāi)發(fā)更簡(jiǎn)便的原生JavaScript解決方案。

在jQuery生態(tài)系統(tǒng)中,這種模式有很多實(shí)現(xiàn),可以直接使用jQuery或使用插件實(shí)現(xiàn),但在本文中,我們感興趣的是純JavaScript解決方案。具體來(lái)說(shuō),我們將探索和利用Jump.js庫(kù)。

在介紹該庫(kù)及其功能和特性的概述之后,我們將對(duì)原始代碼進(jìn)行一些更改以適應(yīng)我們的需求。在此過(guò)程中,我們將復(fù)習(xí)一些核心的JavaScript語(yǔ)言技能,例如函數(shù)和閉包。然后,我們將創(chuàng)建一個(gè)HTML頁(yè)面來(lái)測(cè)試平滑滾動(dòng)行為,然后將其實(shí)現(xiàn)為自定義腳本。然后將添加對(duì)CSS原生平滑滾動(dòng)的支持(如果可用),最后我們將對(duì)瀏覽器導(dǎo)航歷史記錄進(jìn)行一些觀察。

這是我們將創(chuàng)建的最終演示:

查看CodePen上的SitePoint (@SitePoint)的Smooth Scrolling筆。

完整的源代碼可在GitHub上找到。

Jump.js

Jump.js是用原生ES6 JavaScript編寫(xiě)的,沒(méi)有任何外部依賴(lài)項(xiàng)。它是一個(gè)小型實(shí)用程序,只有大約42 SLOC,但提供的最小化包的大小約為2.67 KB,因?yàn)樗仨氝M(jìn)行轉(zhuǎn)譯。GitHub項(xiàng)目頁(yè)面上提供了一個(gè)演示。

顧名思義,它只提供跳轉(zhuǎn):滾動(dòng)條位置從其當(dāng)前值到目標(biāo)位置的動(dòng)畫(huà)變化,通過(guò)提供DOM元素、CSS選擇器或正數(shù)或負(fù)數(shù)值形式的距離來(lái)指定。這意味著在平滑滾動(dòng)模式的實(shí)現(xiàn)中,我們必須自己執(zhí)行鏈接劫持。更多內(nèi)容請(qǐng)參見(jiàn)以下部分。

請(qǐng)注意,目前僅支持視口的垂直滾動(dòng)。

我們可以使用一些選項(xiàng)配置跳轉(zhuǎn),例如持續(xù)時(shí)間(此參數(shù)是必需的)、緩動(dòng)函數(shù)和在動(dòng)畫(huà)結(jié)束時(shí)觸發(fā)的回調(diào)。我們稍后將在演示中看到它們的實(shí)際應(yīng)用。有關(guān)完整詳細(xì)信息,請(qǐng)參見(jiàn)文檔。

Jump.js在“現(xiàn)代”瀏覽器上運(yùn)行沒(méi)有問(wèn)題,包括Internet Explorer 10版或更高版本。同樣,請(qǐng)參考文檔以了解支持的瀏覽器完整列表。使用合適的requestAnimationFrame polyfill,它甚至可以在舊版瀏覽器上運(yùn)行。

快速了解屏幕背后

在內(nèi)部,Jump.js源代碼使用window對(duì)象的requestAnimationFrame方法來(lái)安排在滾動(dòng)動(dòng)畫(huà)的每一幀中更新視口垂直位置的位置。此更新是通過(guò)將使用緩動(dòng)函數(shù)計(jì)算的下一個(gè)位置值傳遞給window.scrollTo方法來(lái)實(shí)現(xiàn)的。有關(guān)完整詳細(xì)信息,請(qǐng)參見(jiàn)源代碼。

一些自定義

在深入研究演示以展示Jump.js的使用之前,我們將對(duì)原始代碼進(jìn)行一些細(xì)微的更改,但這不會(huì)修改其內(nèi)部工作方式。

源代碼是用ES6編寫(xiě)的,需要與JavaScript構(gòu)建工具一起使用才能進(jìn)行轉(zhuǎn)譯和捆綁模塊。對(duì)于某些項(xiàng)目來(lái)說(shuō),這可能有點(diǎn)過(guò)分,因此我們將應(yīng)用一些重構(gòu)來(lái)將代碼轉(zhuǎn)換為ES5,以便在任何地方使用。

首先,讓我們刪除ES6語(yǔ)法和功能。腳本定義了一個(gè)ES6類(lèi):

<code>import easeInOutQuad from './easing'

export default class Jump {
  jump(target, options = {}) {
    this.start = window.pageYOffset

    this.options = {
      duration: options.duration,
      offset: options.offset || 0,
      callback: options.callback,
      easing: options.easing || easeInOutQuad
    }

    this.distance = typeof target === 'string'
      ? this.options.offset + document.querySelector(target).getBoundingClientRect().top
      : target

    this.duration = typeof this.options.duration === 'function'
      ? this.options.duration(this.distance)
      : this.options.duration

    requestAnimationFrame(time => this._loop(time))
  }

  _loop(time) {
    if(!this.timeStart) {
      this.timeStart = time
    }

    this.timeElapsed = time - this.timeStart
    this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration)

    window.scrollTo(0, this.next)

    this.timeElapsed       ? requestAnimationFrame(time => this._loop(time))
      : this._end()
  }

  _end() {
    window.scrollTo(0, this.start + this.distance)

    typeof this.options.callback === 'function' && this.options.callback()
    this.timeStart = false
  }
}
</code>

我們可以使用構(gòu)造函數(shù)和一堆原型方法將其轉(zhuǎn)換為ES5“類(lèi)”,但請(qǐng)注意,我們永遠(yuǎn)不需要此類(lèi)的多個(gè)實(shí)例,因此使用普通對(duì)象字面量實(shí)現(xiàn)的單例就可以了:

<code>var jump = (function() {

    var o = {

        jump: function(target, options) {
            this.start = window.pageYOffset

            this.options = {
              duration: options.duration,
              offset: options.offset || 0,
              callback: options.callback,
              easing: options.easing || easeInOutQuad
            }

            this.distance = typeof target === 'string'
              ? this.options.offset + document.querySelector(target).getBoundingClientRect().top
              : target

            this.duration = typeof this.options.duration === 'function'
              ? this.options.duration(this.distance)
              : this.options.duration

            requestAnimationFrame(_loop)
        },

        _loop: function(time) {
            if(!this.timeStart) {
              this.timeStart = time
            }

            this.timeElapsed = time - this.timeStart
            this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration)

            window.scrollTo(0, this.next)

            this.timeElapsed               ? requestAnimationFrame(_loop)
              : this._end()
        },

        _end: function() {
            window.scrollTo(0, this.start + this.distance)

            typeof this.options.callback === 'function' && this.options.callback()
            this.timeStart = false
        }

    };

    var _loop = o._loop.bind(o);

    // Robert Penner's easeInOutQuad - http://robertpenner.com/easing/
    function easeInOutQuad(t, b, c, d)  {
        t /= d / 2
        if(t         t--
        return -c / 2 * (t * (t - 2) - 1) + b
    }

    return o;

})();
</code>

除了刪除類(lèi)之外,我們還需要進(jìn)行其他一些更改。requestAnimationFrame的回調(diào)用于在每一幀中更新滾動(dòng)條位置,在原始代碼中,它是通過(guò)ES6箭頭函數(shù)調(diào)用的,在初始化時(shí)預(yù)綁定到j(luò)ump單例。然后,我們將默認(rèn)緩動(dòng)函數(shù)捆綁在同一個(gè)源文件中。最后,我們使用IIFE(立即調(diào)用函數(shù)表達(dá)式)包裝了代碼,以避免命名空間污染。

現(xiàn)在我們可以應(yīng)用另一個(gè)重構(gòu)步驟,注意借助嵌套函數(shù)和閉包,我們可以只使用函數(shù)而不是對(duì)象:

<code>function jump(target, options) {
    var start = window.pageYOffset;

    var opt = {
      duration: options.duration,
      offset: options.offset || 0,
      callback: options.callback,
      easing: options.easing || easeInOutQuad
    };

    var distance = typeof target === 'string' ? 
        opt.offset + document.querySelector(target).getBoundingClientRect().top : 
        target
    ;

    var duration = typeof opt.duration === 'function'
          ? opt.duration(distance)
          : opt.duration
    ;

    var 
        timeStart = null,
        timeElapsed
    ;

    requestAnimationFrame(loop);

    function loop(time) {
        if (timeStart === null)
            timeStart = time;

        timeElapsed = time - timeStart;

        window.scrollTo(0, opt.easing(timeElapsed, start, distance, duration));

        if (timeElapsed         requestAnimationFrame(loop)
        else
            end();
    }

    function end() {
        window.scrollTo(0, start + distance);

        typeof opt.callback === 'function' && opt.callback();
        timeStart = null;
    }

    // ...

}
</code>

單例現(xiàn)在變成了將被調(diào)用以動(dòng)畫(huà)滾動(dòng)的jump函數(shù),loop和end回調(diào)變成了嵌套函數(shù),而對(duì)象的屬性現(xiàn)在變成了局部變量(閉包)。我們不再需要IIFE,因?yàn)楝F(xiàn)在所有代碼都安全地包裝在一個(gè)函數(shù)中。

作為最后的重構(gòu)步驟,為了避免在每次調(diào)用loop回調(diào)時(shí)重復(fù)timeStart重置檢查,第一次調(diào)用requestAnimationFrame()時(shí),我們將向其傳遞一個(gè)匿名函數(shù),該函數(shù)在調(diào)用loop函數(shù)之前重置timerStart變量:

<code>import easeInOutQuad from './easing'

export default class Jump {
  jump(target, options = {}) {
    this.start = window.pageYOffset

    this.options = {
      duration: options.duration,
      offset: options.offset || 0,
      callback: options.callback,
      easing: options.easing || easeInOutQuad
    }

    this.distance = typeof target === 'string'
      ? this.options.offset + document.querySelector(target).getBoundingClientRect().top
      : target

    this.duration = typeof this.options.duration === 'function'
      ? this.options.duration(this.distance)
      : this.options.duration

    requestAnimationFrame(time => this._loop(time))
  }

  _loop(time) {
    if(!this.timeStart) {
      this.timeStart = time
    }

    this.timeElapsed = time - this.timeStart
    this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration)

    window.scrollTo(0, this.next)

    this.timeElapsed       ? requestAnimationFrame(time => this._loop(time))
      : this._end()
  }

  _end() {
    window.scrollTo(0, this.start + this.distance)

    typeof this.options.callback === 'function' && this.options.callback()
    this.timeStart = false
  }
}
</code>

再次注意,在重構(gòu)過(guò)程中,核心滾動(dòng)動(dòng)畫(huà)代碼沒(méi)有改變。

測(cè)試頁(yè)面

現(xiàn)在我們已經(jīng)自定義了腳本以適應(yīng)我們的需求,我們準(zhǔn)備組裝一個(gè)測(cè)試演示。在本節(jié)中,我們將編寫(xiě)一個(gè)使用下一節(jié)中介紹的腳本增強(qiáng)平滑滾動(dòng)的頁(yè)面。

該頁(yè)面包含一個(gè)包含指向文檔中后續(xù)部分的頁(yè)面內(nèi)鏈接的內(nèi)容表(TOC),以及指向TOC的其他鏈接。我們還將混合一些指向其他頁(yè)面的外部鏈接。這是此頁(yè)面的基本結(jié)構(gòu):

<code>var jump = (function() {

    var o = {

        jump: function(target, options) {
            this.start = window.pageYOffset

            this.options = {
              duration: options.duration,
              offset: options.offset || 0,
              callback: options.callback,
              easing: options.easing || easeInOutQuad
            }

            this.distance = typeof target === 'string'
              ? this.options.offset + document.querySelector(target).getBoundingClientRect().top
              : target

            this.duration = typeof this.options.duration === 'function'
              ? this.options.duration(this.distance)
              : this.options.duration

            requestAnimationFrame(_loop)
        },

        _loop: function(time) {
            if(!this.timeStart) {
              this.timeStart = time
            }

            this.timeElapsed = time - this.timeStart
            this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration)

            window.scrollTo(0, this.next)

            this.timeElapsed               ? requestAnimationFrame(_loop)
              : this._end()
        },

        _end: function() {
            window.scrollTo(0, this.start + this.distance)

            typeof this.options.callback === 'function' && this.options.callback()
            this.timeStart = false
        }

    };

    var _loop = o._loop.bind(o);

    // Robert Penner's easeInOutQuad - http://robertpenner.com/easing/
    function easeInOutQuad(t, b, c, d)  {
        t /= d / 2
        if(t         t--
        return -c / 2 * (t * (t - 2) - 1) + b
    }

    return o;

})();
</code>

在頭部,我們將包含一些CSS規(guī)則來(lái)設(shè)置基本的最簡(jiǎn)布局,而在body標(biāo)簽的末尾,我們將包含兩個(gè)JavaScript文件:前者是我們重構(gòu)后的Jump.js版本,后者是我們現(xiàn)在將討論的腳本。

主腳本

這是將使用我們自定義的Jump.js庫(kù)版本的動(dòng)畫(huà)跳轉(zhuǎn)來(lái)增強(qiáng)測(cè)試頁(yè)面滾動(dòng)體驗(yàn)的腳本。當(dāng)然,此代碼也將用ES5 JavaScript編寫(xiě)。

讓我們簡(jiǎn)要概述一下它應(yīng)該完成的任務(wù):它必須劫持頁(yè)面內(nèi)鏈接上的點(diǎn)擊,禁用瀏覽器的默認(rèn)行為(突然跳轉(zhuǎn)到點(diǎn)擊鏈接的href屬性的哈希片段中指示的目標(biāo)元素),并將其替換為對(duì)我們的jump()函數(shù)的調(diào)用。

因此,首先要監(jiān)控頁(yè)面內(nèi)鏈接上的點(diǎn)擊。我們可以通過(guò)兩種方式做到這一點(diǎn),使用事件委托或?qū)⑻幚沓绦蚋郊拥矫總€(gè)相關(guān)的鏈接。

事件委托

在第一種方法中,我們將點(diǎn)擊偵聽(tīng)器添加到一個(gè)元素document.body。這樣,頁(yè)面上任何元素的每個(gè)點(diǎn)擊事件都將沿著其祖先的分支冒泡到DOM樹(shù),直到到達(dá)document.body:

<code>function jump(target, options) {
    var start = window.pageYOffset;

    var opt = {
      duration: options.duration,
      offset: options.offset || 0,
      callback: options.callback,
      easing: options.easing || easeInOutQuad
    };

    var distance = typeof target === 'string' ? 
        opt.offset + document.querySelector(target).getBoundingClientRect().top : 
        target
    ;

    var duration = typeof opt.duration === 'function'
          ? opt.duration(distance)
          : opt.duration
    ;

    var 
        timeStart = null,
        timeElapsed
    ;

    requestAnimationFrame(loop);

    function loop(time) {
        if (timeStart === null)
            timeStart = time;

        timeElapsed = time - timeStart;

        window.scrollTo(0, opt.easing(timeElapsed, start, distance, duration));

        if (timeElapsed         requestAnimationFrame(loop)
        else
            end();
    }

    function end() {
        window.scrollTo(0, start + distance);

        typeof opt.callback === 'function' && opt.callback();
        timeStart = null;
    }

    // ...

}
</code>

當(dāng)然,現(xiàn)在在注冊(cè)的事件偵聽(tīng)器(onClick)中,我們必須檢查傳入的click事件對(duì)象的target,以檢查它是否與頁(yè)面內(nèi)鏈接元素相關(guān)。這可以通過(guò)多種方式完成,因此我們將將其抽象為輔助函數(shù)isInPageLink()。我們稍后將看看此函數(shù)的機(jī)制。

如果傳入的點(diǎn)擊是在頁(yè)面內(nèi)鏈接上,我們將停止事件冒泡并阻止關(guān)聯(lián)的默認(rèn)操作。最后,我們調(diào)用jump函數(shù),為其提供目標(biāo)元素的哈希選擇器和配置所需動(dòng)畫(huà)的參數(shù)。

這是事件處理程序:

<code>requestAnimationFrame(function(time) { timeStart = time; loop(time); });

function loop(time) {
    timeElapsed = time - timeStart;

    window.scrollTo(0, opt.easing(timeElapsed, start, distance, duration));

    if (timeElapsed         requestAnimationFrame(loop)
    else
        end();
}
</code>

單個(gè)處理程序

使用第二種方法來(lái)監(jiān)控鏈接點(diǎn)擊,將上面介紹的事件處理程序的稍微修改后的版本附加到每個(gè)頁(yè)面內(nèi)鏈接元素,因此沒(méi)有事件冒泡:

<code>import easeInOutQuad from './easing'

export default class Jump {
  jump(target, options = {}) {
    this.start = window.pageYOffset

    this.options = {
      duration: options.duration,
      offset: options.offset || 0,
      callback: options.callback,
      easing: options.easing || easeInOutQuad
    }

    this.distance = typeof target === 'string'
      ? this.options.offset + document.querySelector(target).getBoundingClientRect().top
      : target

    this.duration = typeof this.options.duration === 'function'
      ? this.options.duration(this.distance)
      : this.options.duration

    requestAnimationFrame(time => this._loop(time))
  }

  _loop(time) {
    if(!this.timeStart) {
      this.timeStart = time
    }

    this.timeElapsed = time - this.timeStart
    this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration)

    window.scrollTo(0, this.next)

    this.timeElapsed       ? requestAnimationFrame(time => this._loop(time))
      : this._end()
  }

  _end() {
    window.scrollTo(0, this.start + this.distance)

    typeof this.options.callback === 'function' && this.options.callback()
    this.timeStart = false
  }
}
</code>

我們查詢(xún)所有元素,并使用[].slice()技巧將返回的DOM NodeList轉(zhuǎn)換為JavaScript數(shù)組(如果目標(biāo)瀏覽器支持,更好的替代方法是使用ES6 Array.from()方法)。然后,我們可以使用數(shù)組方法過(guò)濾頁(yè)面內(nèi)鏈接,重新使用上面定義的相同輔助函數(shù),最后將偵聽(tīng)器附加到剩余的鏈接元素。

事件處理程序與之前幾乎相同,但當(dāng)然我們不需要檢查點(diǎn)擊目標(biāo):

<code>var jump = (function() {

    var o = {

        jump: function(target, options) {
            this.start = window.pageYOffset

            this.options = {
              duration: options.duration,
              offset: options.offset || 0,
              callback: options.callback,
              easing: options.easing || easeInOutQuad
            }

            this.distance = typeof target === 'string'
              ? this.options.offset + document.querySelector(target).getBoundingClientRect().top
              : target

            this.duration = typeof this.options.duration === 'function'
              ? this.options.duration(this.distance)
              : this.options.duration

            requestAnimationFrame(_loop)
        },

        _loop: function(time) {
            if(!this.timeStart) {
              this.timeStart = time
            }

            this.timeElapsed = time - this.timeStart
            this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration)

            window.scrollTo(0, this.next)

            this.timeElapsed               ? requestAnimationFrame(_loop)
              : this._end()
        },

        _end: function() {
            window.scrollTo(0, this.start + this.distance)

            typeof this.options.callback === 'function' && this.options.callback()
            this.timeStart = false
        }

    };

    var _loop = o._loop.bind(o);

    // Robert Penner's easeInOutQuad - http://robertpenner.com/easing/
    function easeInOutQuad(t, b, c, d)  {
        t /= d / 2
        if(t         t--
        return -c / 2 * (t * (t - 2) - 1) + b
    }

    return o;

})();
</code>

哪種方法最好取決于使用上下文。例如,如果在初始頁(yè)面加載后可能動(dòng)態(tài)添加新的鏈接元素,那么我們必須使用事件委托。

現(xiàn)在我們轉(zhuǎn)向isInPageLink()的實(shí)現(xiàn),我們?cè)谥暗氖录幚沓绦蛑惺褂么溯o助函數(shù)來(lái)抽象頁(yè)面內(nèi)鏈接的測(cè)試。正如我們所看到的,此函數(shù)接受DOM節(jié)點(diǎn)作為參數(shù),并返回一個(gè)布爾值以指示該節(jié)點(diǎn)是否表示頁(yè)面內(nèi)鏈接元素。僅檢查傳遞的節(jié)點(diǎn)是A標(biāo)簽并且設(shè)置了哈希片段是不夠的,因?yàn)殒溄涌赡苁侵赶蛄硪粋€(gè)頁(yè)面,在這種情況下,必須不禁用默認(rèn)瀏覽器操作。因此,我們檢查屬性href中存儲(chǔ)的值“減去”哈希片段是否等于頁(yè)面URL:

<code>function jump(target, options) {
    var start = window.pageYOffset;

    var opt = {
      duration: options.duration,
      offset: options.offset || 0,
      callback: options.callback,
      easing: options.easing || easeInOutQuad
    };

    var distance = typeof target === 'string' ? 
        opt.offset + document.querySelector(target).getBoundingClientRect().top : 
        target
    ;

    var duration = typeof opt.duration === 'function'
          ? opt.duration(distance)
          : opt.duration
    ;

    var 
        timeStart = null,
        timeElapsed
    ;

    requestAnimationFrame(loop);

    function loop(time) {
        if (timeStart === null)
            timeStart = time;

        timeElapsed = time - timeStart;

        window.scrollTo(0, opt.easing(timeElapsed, start, distance, duration));

        if (timeElapsed         requestAnimationFrame(loop)
        else
            end();
    }

    function end() {
        window.scrollTo(0, start + distance);

        typeof opt.callback === 'function' && opt.callback();
        timeStart = null;
    }

    // ...

}
</code>

stripHash()是另一個(gè)輔助函數(shù),我們也用它在腳本初始化時(shí)設(shè)置變量pageUrl的值:

<code>requestAnimationFrame(function(time) { timeStart = time; loop(time); });

function loop(time) {
    timeElapsed = time - timeStart;

    window.scrollTo(0, opt.easing(timeElapsed, start, distance, duration));

    if (timeElapsed         requestAnimationFrame(loop)
    else
        end();
}
</code>

此基于字符串的解決方案以及哈希片段的修剪即使在帶有查詢(xún)字符串的URL上也能正常工作,因?yàn)楣2糠衷赨RL的一般結(jié)構(gòu)中位于它們之后。

正如我之前所說(shuō),這只是實(shí)現(xiàn)此測(cè)試的一種可能方法。例如,本教程開(kāi)頭引用的文章使用了不同的解決方案,對(duì)鏈接href與location對(duì)象進(jìn)行了組件級(jí)比較。

應(yīng)該注意的是,我們?cè)趦煞N事件訂閱方法中都使用了此函數(shù),但在第二種方法中,我們將其用作我們已經(jīng)知道是標(biāo)簽的元素的過(guò)濾器,因此對(duì)tagName屬性的第一次檢查是多余的。這留給讀者作為練習(xí)。

可訪問(wèn)性注意事項(xiàng)

就目前而言,我們的代碼容易受到已知錯(cuò)誤(實(shí)際上是一對(duì)無(wú)關(guān)的錯(cuò)誤,影響B(tài)link/WebKit/KHTML和一個(gè)影響IE的錯(cuò)誤)的影響,這些錯(cuò)誤會(huì)影響鍵盤(pán)用戶(hù)。當(dāng)通過(guò)制表鍵瀏覽TOC鏈接時(shí),激活一個(gè)鏈接將平滑地向下滾動(dòng)到選定的部分,但焦點(diǎn)將保留在鏈接上。這意味著在下一個(gè)制表鍵按下時(shí),用戶(hù)將被送回TOC,而不是送往他們選擇的節(jié)中的第一個(gè)鏈接。

為了解決這個(gè)問(wèn)題,我們將向主腳本添加另一個(gè)函數(shù):

<code>>
    <h1>></h1>Title>
    <nav> id="toc"></nav>
        <ul>></ul>
            <li>></li>
<a> href="http://www.miracleart.cn/link/db8229562f80fbcc7d780f571e5974ec"></a>Section 1>>
            <li>></li>
<a> href="http://www.miracleart.cn/link/ba2cf4148007ed8a8b041f8abd9bbf96"></a>Section 2>>
            ...
        >
    >
     id="sect-1">
        <h2>></h2>Section 1>
        <p>></p>Pellentesque habitant morbi tristique senectus et netus et <a> href="http://www.miracleart.cn/link/e1b97c787a5677efa5eba575c41e8688"></a>a link to another page> ac turpis egestas. <a> href="http://www.miracleart.cn/link/e1b97c787a5677efa5eba575c41e8688index.html#foo"></a>A link to another page, with an anchor> quam, feugiat vitae, ...>
        <a> href="http://www.miracleart.cn/link/7421d74f57142680e679057ddc98edf5"></a>Back to TOC>
    >
     id="sect-2">
        <h2>></h2>Section 2>
        ...
    >
    ...
     src="jump.js">>
     src="script.js">>
>
</code>

它將在我們將傳遞給jump函數(shù)的回調(diào)中運(yùn)行,并將我們要滾動(dòng)到的元素的哈希值傳遞過(guò)去:

<code>import easeInOutQuad from './easing'

export default class Jump {
  jump(target, options = {}) {
    this.start = window.pageYOffset

    this.options = {
      duration: options.duration,
      offset: options.offset || 0,
      callback: options.callback,
      easing: options.easing || easeInOutQuad
    }

    this.distance = typeof target === 'string'
      ? this.options.offset + document.querySelector(target).getBoundingClientRect().top
      : target

    this.duration = typeof this.options.duration === 'function'
      ? this.options.duration(this.distance)
      : this.options.duration

    requestAnimationFrame(time => this._loop(time))
  }

  _loop(time) {
    if(!this.timeStart) {
      this.timeStart = time
    }

    this.timeElapsed = time - this.timeStart
    this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration)

    window.scrollTo(0, this.next)

    this.timeElapsed       ? requestAnimationFrame(time => this._loop(time))
      : this._end()
  }

  _end() {
    window.scrollTo(0, this.start + this.distance)

    typeof this.options.callback === 'function' && this.options.callback()
    this.timeStart = false
  }
}
</code>

此函數(shù)的作用是獲取哈希值對(duì)應(yīng)的DOM元素,并測(cè)試它是否已經(jīng)是可以接收焦點(diǎn)的元素(例如錨點(diǎn)或按鈕元素)。如果元素不能默認(rèn)接收焦點(diǎn)(例如我們的容器),則它會(huì)將其tabIndex屬性設(shè)置為-1(允許通過(guò)編程方式接收焦點(diǎn),但不能通過(guò)鍵盤(pán)接收)。然后焦點(diǎn)將設(shè)置為該元素,這意味著用戶(hù)的下一個(gè)tab按鍵將焦點(diǎn)移動(dòng)到下一個(gè)可用鏈接。

您可以在此處查看主腳本的完整源代碼,其中包含所有先前討論的更改。

使用CSS支持原生平滑滾動(dòng)

CSS對(duì)象模型視圖模塊規(guī)范引入了一個(gè)新的屬性來(lái)原生實(shí)現(xiàn)平滑滾動(dòng):scroll-behavior。

它可以取兩個(gè)值,auto表示默認(rèn)的瞬時(shí)滾動(dòng),smooth表示動(dòng)畫(huà)滾動(dòng)。該規(guī)范沒(méi)有提供任何配置滾動(dòng)動(dòng)畫(huà)的方法,例如其持續(xù)時(shí)間和時(shí)間函數(shù)(緩動(dòng))。

我可以使用css-scroll-behavior嗎?來(lái)自caniuse.com的數(shù)據(jù)顯示主要瀏覽器對(duì)css-scroll-behavior功能的支持情況。

不幸的是,在撰寫(xiě)本文時(shí),支持非常有限。在Chrome中,此功能正在開(kāi)發(fā)中,可以通過(guò)在chrome://flags屏幕中啟用它來(lái)使用部分實(shí)現(xiàn)。CSS屬性尚未實(shí)現(xiàn),因此鏈接點(diǎn)擊上的平滑滾動(dòng)不起作用。

無(wú)論如何,通過(guò)對(duì)主腳本進(jìn)行微小的更改,我們可以檢測(cè)用戶(hù)代理中是否可用此功能并避免運(yùn)行我們的其余代碼。為了在視口中使用平滑滾動(dòng),我們將CSS屬性應(yīng)用于根元素HTML(但在我們的測(cè)試頁(yè)面中,我們甚至可以將其應(yīng)用于body元素):

<code>var jump = (function() {

    var o = {

        jump: function(target, options) {
            this.start = window.pageYOffset

            this.options = {
              duration: options.duration,
              offset: options.offset || 0,
              callback: options.callback,
              easing: options.easing || easeInOutQuad
            }

            this.distance = typeof target === 'string'
              ? this.options.offset + document.querySelector(target).getBoundingClientRect().top
              : target

            this.duration = typeof this.options.duration === 'function'
              ? this.options.duration(this.distance)
              : this.options.duration

            requestAnimationFrame(_loop)
        },

        _loop: function(time) {
            if(!this.timeStart) {
              this.timeStart = time
            }

            this.timeElapsed = time - this.timeStart
            this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration)

            window.scrollTo(0, this.next)

            this.timeElapsed               ? requestAnimationFrame(_loop)
              : this._end()
        },

        _end: function() {
            window.scrollTo(0, this.start + this.distance)

            typeof this.options.callback === 'function' && this.options.callback()
            this.timeStart = false
        }

    };

    var _loop = o._loop.bind(o);

    // Robert Penner's easeInOutQuad - http://robertpenner.com/easing/
    function easeInOutQuad(t, b, c, d)  {
        t /= d / 2
        if(t         t--
        return -c / 2 * (t * (t - 2) - 1) + b
    }

    return o;

})();
</code>

然后,我們?cè)谀_本開(kāi)頭添加一個(gè)簡(jiǎn)單的功能檢測(cè)測(cè)試:

<code>function jump(target, options) {
    var start = window.pageYOffset;

    var opt = {
      duration: options.duration,
      offset: options.offset || 0,
      callback: options.callback,
      easing: options.easing || easeInOutQuad
    };

    var distance = typeof target === 'string' ? 
        opt.offset + document.querySelector(target).getBoundingClientRect().top : 
        target
    ;

    var duration = typeof opt.duration === 'function'
          ? opt.duration(distance)
          : opt.duration
    ;

    var 
        timeStart = null,
        timeElapsed
    ;

    requestAnimationFrame(loop);

    function loop(time) {
        if (timeStart === null)
            timeStart = time;

        timeElapsed = time - timeStart;

        window.scrollTo(0, opt.easing(timeElapsed, start, distance, duration));

        if (timeElapsed         requestAnimationFrame(loop)
        else
            end();
    }

    function end() {
        window.scrollTo(0, start + distance);

        typeof opt.callback === 'function' && opt.callback();
        timeStart = null;
    }

    // ...

}
</code>

因此,如果瀏覽器支持原生滾動(dòng),則腳本將不執(zhí)行任何操作并退出,否則它將像以前一樣繼續(xù)執(zhí)行,并且瀏覽器將忽略不受支持的CSS屬性。

結(jié)論

除了實(shí)現(xiàn)簡(jiǎn)單和性能之外,剛才討論的CSS解決方案的另一個(gè)優(yōu)勢(shì)是瀏覽器歷史行為與使用瀏覽器默認(rèn)滾動(dòng)時(shí)所體驗(yàn)的行為一致。每個(gè)頁(yè)面內(nèi)跳轉(zhuǎn)都推送到瀏覽器歷史堆棧上,我們可以使用相應(yīng)的按鈕來(lái)回瀏覽這些跳轉(zhuǎn)(但至少在Firefox中沒(méi)有平滑滾動(dòng))。

在我們編寫(xiě)的代碼中(我們現(xiàn)在可以將其視為CSS支持不可用時(shí)的后備方案),我們沒(méi)有考慮腳本相對(duì)于瀏覽器歷史記錄的行為。根據(jù)上下文和用例,這可能是或可能不是感興趣的事情,但如果我們認(rèn)為腳本應(yīng)該增強(qiáng)默認(rèn)滾動(dòng)體驗(yàn),那么我們應(yīng)該期望一致的行為,就像CSS一樣。

關(guān)于使用原生JavaScript進(jìn)行平滑滾動(dòng)的常見(jiàn)問(wèn)題解答 (FAQs)

如何在不使用任何庫(kù)的情況下使用原生JavaScript實(shí)現(xiàn)平滑滾動(dòng)?

在不使用任何庫(kù)的情況下使用原生JavaScript實(shí)現(xiàn)平滑滾動(dòng)非常簡(jiǎn)單。您可以使用window.scrollTo方法,并將behavior選項(xiàng)設(shè)置為smooth。此方法通過(guò)給定數(shù)量滾動(dòng)窗口中的文檔。這是一個(gè)簡(jiǎn)單的示例:

<code>import easeInOutQuad from './easing'

export default class Jump {
  jump(target, options = {}) {
    this.start = window.pageYOffset

    this.options = {
      duration: options.duration,
      offset: options.offset || 0,
      callback: options.callback,
      easing: options.easing || easeInOutQuad
    }

    this.distance = typeof target === 'string'
      ? this.options.offset + document.querySelector(target).getBoundingClientRect().top
      : target

    this.duration = typeof this.options.duration === 'function'
      ? this.options.duration(this.distance)
      : this.options.duration

    requestAnimationFrame(time => this._loop(time))
  }

  _loop(time) {
    if(!this.timeStart) {
      this.timeStart = time
    }

    this.timeElapsed = time - this.timeStart
    this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration)

    window.scrollTo(0, this.next)

    this.timeElapsed       ? requestAnimationFrame(time => this._loop(time))
      : this._end()
  }

  _end() {
    window.scrollTo(0, this.start + this.distance)

    typeof this.options.callback === 'function' && this.options.callback()
    this.timeStart = false
  }
}
</code>

在此示例中,當(dāng)您點(diǎn)擊具有類(lèi)your-element的元素時(shí),頁(yè)面將平滑地滾動(dòng)到頂部。

為什么我的平滑滾動(dòng)在Safari中不起作用?

使用scrollTo方法并將behavior選項(xiàng)設(shè)置為smooth的平滑滾動(dòng)功能在Safari中不受支持。要使其正常工作,您可以使用polyfill,例如smoothscroll-polyfill。這將在原生不支持它的瀏覽器中啟用平滑滾動(dòng)功能。

如何平滑地滾動(dòng)到特定元素?

要平滑地滾動(dòng)到特定元素,您可以使用Element.scrollIntoView方法,并將behavior選項(xiàng)設(shè)置為smooth。這是一個(gè)示例:

<code>var jump = (function() {

    var o = {

        jump: function(target, options) {
            this.start = window.pageYOffset

            this.options = {
              duration: options.duration,
              offset: options.offset || 0,
              callback: options.callback,
              easing: options.easing || easeInOutQuad
            }

            this.distance = typeof target === 'string'
              ? this.options.offset + document.querySelector(target).getBoundingClientRect().top
              : target

            this.duration = typeof this.options.duration === 'function'
              ? this.options.duration(this.distance)
              : this.options.duration

            requestAnimationFrame(_loop)
        },

        _loop: function(time) {
            if(!this.timeStart) {
              this.timeStart = time
            }

            this.timeElapsed = time - this.timeStart
            this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration)

            window.scrollTo(0, this.next)

            this.timeElapsed               ? requestAnimationFrame(_loop)
              : this._end()
        },

        _end: function() {
            window.scrollTo(0, this.start + this.distance)

            typeof this.options.callback === 'function' && this.options.callback()
            this.timeStart = false
        }

    };

    var _loop = o._loop.bind(o);

    // Robert Penner's easeInOutQuad - http://robertpenner.com/easing/
    function easeInOutQuad(t, b, c, d)  {
        t /= d / 2
        if(t         t--
        return -c / 2 * (t * (t - 2) - 1) + b
    }

    return o;

})();
</code>

在此示例中,當(dāng)您點(diǎn)擊具有類(lèi)your-element的元素時(shí),頁(yè)面將平滑地滾動(dòng)到具有類(lèi)target-element的元素。

我可以控制平滑滾動(dòng)的速度嗎?

平滑滾動(dòng)的速度不能直接控制,因?yàn)樗蔀g覽器處理。但是,您可以使用window.requestAnimationFrame創(chuàng)建一個(gè)自定義平滑滾動(dòng)函數(shù),以便更好地控制滾動(dòng)動(dòng)畫(huà),包括其速度。

如何實(shí)現(xiàn)水平平滑滾動(dòng)?

您可以通過(guò)與垂直平滑滾動(dòng)類(lèi)似的方式實(shí)現(xiàn)水平平滑滾動(dòng)。window.scrollToElement.scrollIntoView方法也接受left選項(xiàng)以指定要滾動(dòng)到的水平位置。這是一個(gè)示例:

<code>function jump(target, options) {
    var start = window.pageYOffset;

    var opt = {
      duration: options.duration,
      offset: options.offset || 0,
      callback: options.callback,
      easing: options.easing || easeInOutQuad
    };

    var distance = typeof target === 'string' ? 
        opt.offset + document.querySelector(target).getBoundingClientRect().top : 
        target
    ;

    var duration = typeof opt.duration === 'function'
          ? opt.duration(distance)
          : opt.duration
    ;

    var 
        timeStart = null,
        timeElapsed
    ;

    requestAnimationFrame(loop);

    function loop(time) {
        if (timeStart === null)
            timeStart = time;

        timeElapsed = time - timeStart;

        window.scrollTo(0, opt.easing(timeElapsed, start, distance, duration));

        if (timeElapsed         requestAnimationFrame(loop)
        else
            end();
    }

    function end() {
        window.scrollTo(0, start + distance);

        typeof opt.callback === 'function' && opt.callback();
        timeStart = null;
    }

    // ...

}
</code>

這將使文檔向右平滑滾動(dòng)100像素。

如何停止平滑滾動(dòng)動(dòng)畫(huà)?

不能直接停止平滑滾動(dòng)動(dòng)畫(huà),因?yàn)樗蔀g覽器處理。但是,如果您使用的是自定義平滑滾動(dòng)函數(shù),則可以使用window.cancelAnimationFrame取消動(dòng)畫(huà)幀來(lái)停止動(dòng)畫(huà)。

如何實(shí)現(xiàn)具有固定頁(yè)眉的平滑滾動(dòng)?

要實(shí)現(xiàn)具有固定頁(yè)眉的平滑滾動(dòng),您需要調(diào)整滾動(dòng)位置以考慮頁(yè)眉的高度。您可以通過(guò)從目標(biāo)滾動(dòng)位置減去頁(yè)眉的高度來(lái)實(shí)現(xiàn)此目的。

如何為錨鏈接實(shí)現(xiàn)平滑滾動(dòng)?

要為錨鏈接實(shí)現(xiàn)平滑滾動(dòng),您可以向鏈接的點(diǎn)擊事件添加事件偵聽(tīng)器,并使用Element.scrollIntoView方法平滑地滾動(dòng)到目標(biāo)元素。這是一個(gè)示例:

<code>requestAnimationFrame(function(time) { timeStart = time; loop(time); });

function loop(time) {
    timeElapsed = time - timeStart;

    window.scrollTo(0, opt.easing(timeElapsed, start, distance, duration));

    if (timeElapsed         requestAnimationFrame(loop)
    else
        end();
}
</code>

這將使頁(yè)面上的所有錨鏈接平滑地滾動(dòng)到其目標(biāo)元素。

如何使用鍵盤(pán)導(dǎo)航實(shí)現(xiàn)平滑滾動(dòng)?

使用鍵盤(pán)導(dǎo)航實(shí)現(xiàn)平滑滾動(dòng)比較復(fù)雜,因?yàn)樗枰獢r截鍵盤(pán)事件并手動(dòng)滾動(dòng)文檔。您可以通過(guò)向keydown事件添加事件偵聽(tīng)器并使用window.scrollTo方法平滑地滾動(dòng)文檔來(lái)實(shí)現(xiàn)此目的。

如何測(cè)試我的平滑滾動(dòng)實(shí)現(xiàn)的兼容性?

您可以使用BrowserStack等在線工具測(cè)試平滑滾動(dòng)實(shí)現(xiàn)的兼容性。這些工具允許您在不同的瀏覽器和不同的設(shè)備上測(cè)試您的網(wǎng)站,以確保您的實(shí)現(xiàn)可以在所有環(huán)境中正常工作。

以上是如何在Vanilla JavaScript中實(shí)現(xiàn)光滑的滾動(dòng)的詳細(xì)內(nèi)容。更多信息請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本站聲明
本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請(qǐng)聯(lián)系admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣服圖片

Undresser.AI Undress

Undresser.AI Undress

人工智能驅(qū)動(dòng)的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用于從照片中去除衣服的在線人工智能工具。

Clothoff.io

Clothoff.io

AI脫衣機(jī)

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的代碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

功能強(qiáng)大的PHP集成開(kāi)發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)代碼編輯軟件(SublimeText3)

熱門(mén)話題

Java vs. JavaScript:清除混亂 Java vs. JavaScript:清除混亂 Jun 20, 2025 am 12:27 AM

Java和JavaScript是不同的編程語(yǔ)言,各自適用于不同的應(yīng)用場(chǎng)景。Java用于大型企業(yè)和移動(dòng)應(yīng)用開(kāi)發(fā),而JavaScript主要用于網(wǎng)頁(yè)開(kāi)發(fā)。

JavaScript評(píng)論:簡(jiǎn)短說(shuō)明 JavaScript評(píng)論:簡(jiǎn)短說(shuō)明 Jun 19, 2025 am 12:40 AM

JavascriptconcommentsenceenceEncorenceEnterential gransimenting,reading and guidingCodeeXecution.1)單inecommentsareusedforquickexplanations.2)多l(xiāng)inecommentsexplaincomplexlogicorprovideDocumentation.3)

如何在JS中與日期和時(shí)間合作? 如何在JS中與日期和時(shí)間合作? Jul 01, 2025 am 01:27 AM

JavaScript中的日期和時(shí)間處理需注意以下幾點(diǎn):1.創(chuàng)建Date對(duì)象有多種方式,推薦使用ISO格式字符串以保證兼容性;2.獲取和設(shè)置時(shí)間信息可用get和set方法,注意月份從0開(kāi)始;3.手動(dòng)格式化日期需拼接字符串,也可使用第三方庫(kù);4.處理時(shí)區(qū)問(wèn)題建議使用支持時(shí)區(qū)的庫(kù),如Luxon。掌握這些要點(diǎn)能有效避免常見(jiàn)錯(cuò)誤。

JavaScript與Java:開(kāi)發(fā)人員的全面比較 JavaScript與Java:開(kāi)發(fā)人員的全面比較 Jun 20, 2025 am 12:21 AM

JavaScriptIspreferredforredforwebdevelverment,而Javaisbetterforlarge-ScalebackendsystystemsandSandAndRoidApps.1)JavascriptexcelcelsincreatingInteractiveWebexperienceswebexperienceswithitswithitsdynamicnnamicnnamicnnamicnnamicnemicnemicnemicnemicnemicnemicnemicnemicnddommanipulation.2)

為什么要將標(biāo)簽放在的底部? 為什么要將標(biāo)簽放在的底部? Jul 02, 2025 am 01:22 AM

PlacingtagsatthebottomofablogpostorwebpageservespracticalpurposesforSEO,userexperience,anddesign.1.IthelpswithSEObyallowingsearchenginestoaccesskeyword-relevanttagswithoutclutteringthemaincontent.2.Itimprovesuserexperiencebykeepingthefocusonthearticl

JavaScript:探索用于高效編碼的數(shù)據(jù)類(lèi)型 JavaScript:探索用于高效編碼的數(shù)據(jù)類(lèi)型 Jun 20, 2025 am 12:46 AM

javascripthassevenfundaMentalDatatypes:數(shù)字,弦,布爾值,未定義,null,object和symbol.1)numberSeadUble-eaduble-ecisionFormat,forwidevaluerangesbutbecautious.2)

什么是在DOM中冒泡和捕獲的事件? 什么是在DOM中冒泡和捕獲的事件? Jul 02, 2025 am 01:19 AM

事件捕獲和冒泡是DOM中事件傳播的兩個(gè)階段,捕獲是從頂層向下到目標(biāo)元素,冒泡是從目標(biāo)元素向上傳播到頂層。1.事件捕獲通過(guò)addEventListener的useCapture參數(shù)設(shè)為true實(shí)現(xiàn);2.事件冒泡是默認(rèn)行為,useCapture設(shè)為false或省略;3.可使用event.stopPropagation()阻止事件傳播;4.冒泡支持事件委托,提高動(dòng)態(tài)內(nèi)容處理效率;5.捕獲可用于提前攔截事件,如日志記錄或錯(cuò)誤處理。了解這兩個(gè)階段有助于精確控制JavaScript響應(yīng)用戶(hù)操作的時(shí)機(jī)和方式。

Java和JavaScript有什么區(qū)別? Java和JavaScript有什么區(qū)別? Jun 17, 2025 am 09:17 AM

Java和JavaScript是不同的編程語(yǔ)言。1.Java是靜態(tài)類(lèi)型、編譯型語(yǔ)言,適用于企業(yè)應(yīng)用和大型系統(tǒng)。2.JavaScript是動(dòng)態(tài)類(lèi)型、解釋型語(yǔ)言,主要用于網(wǎng)頁(yè)交互和前端開(kāi)發(fā)。

See all articles