Javascript 瀏覽器事件簡(jiǎn)介

2023-02-17 10:54 更新

事件 是某事發(fā)生的信號(hào)。所有的 DOM 節(jié)點(diǎn)都生成這樣的信號(hào)(但事件不僅限于 DOM)。

這是最有用的 DOM 事件的列表,你可以瀏覽一下:

鼠標(biāo)事件:

  • ?click? —— 當(dāng)鼠標(biāo)點(diǎn)擊一個(gè)元素時(shí)(觸摸屏設(shè)備會(huì)在點(diǎn)擊時(shí)生成)。
  • ?contextmenu? —— 當(dāng)鼠標(biāo)右鍵點(diǎn)擊一個(gè)元素時(shí)。
  • ?mouseover? / ?mouseout? —— 當(dāng)鼠標(biāo)指針移入/離開一個(gè)元素時(shí)。
  • ?mousedown? / ?mouseup? —— 當(dāng)在元素上按下/釋放鼠標(biāo)按鈕時(shí)。
  • ?mousemove? —— 當(dāng)鼠標(biāo)移動(dòng)時(shí)。

鍵盤事件

  • ?keydown? 和 ?keyup? —— 當(dāng)按下和松開一個(gè)按鍵時(shí)。

表單(form)元素事件

  • ?submit? —— 當(dāng)訪問者提交了一個(gè) ?<form>? 時(shí)。
  • ?focus? —— 當(dāng)訪問者聚焦于一個(gè)元素時(shí),例如聚焦于一個(gè) ?<input>?。

Document 事件

  • ?DOMContentLoaded? —— 當(dāng) HTML 的加載和處理均完成,DOM 被完全構(gòu)建完成時(shí)。

CSS 事件

  • ?transitionend? —— 當(dāng)一個(gè) CSS 動(dòng)畫完成時(shí)。

還有很多其他事件。我們將在下一章中詳細(xì)介紹具體事件。

事件處理程序

為了對(duì)事件作出響應(yīng),我們可以分配一個(gè) 處理程序(handler)—— 一個(gè)在事件發(fā)生時(shí)運(yùn)行的函數(shù)。

處理程序是在發(fā)生用戶行為(action)時(shí)運(yùn)行 JavaScript 代碼的一種方式。

有幾種分配處理程序的方法。讓我們來看看,從最簡(jiǎn)單的開始。

HTML 特性

處理程序可以設(shè)置在 HTML 中名為 on<event> 的特性(attribute)中。

例如,要為一個(gè) input 分配一個(gè) click 處理程序,我們可以使用 onclick,像這樣;

<input value="Click me" onclick="alert('Click!')" type="button">

在鼠標(biāo)點(diǎn)擊時(shí),onclick 中的代碼就會(huì)運(yùn)行。

請(qǐng)注意,在 onclick 中,我們使用單引號(hào),因?yàn)樘匦员旧硎褂玫氖请p引號(hào)。如果我們忘記了代碼是在特性中的,而使用了雙引號(hào),像這樣:onclick="alert("Click!")",那么它就無法正確運(yùn)行。

HTML 特性不是編寫大量代碼的好位置,因此我們最好創(chuàng)建一個(gè) JavaScript 函數(shù),然后在 HTML 特性中調(diào)用這個(gè)函數(shù)。

我們知道,HTML 特性名是大小寫不敏感的,所以 ONCLICK 和 onClick 以及 onCLICK 都一樣可以運(yùn)行。但是特性通常是小寫的:onclick。

DOM 屬性

我們可以使用 DOM 屬性(property)on<event> 來分配處理程序。

例如 elem.onclick

<input id="elem" type="button" value="Click me">
<script>
  elem.onclick = function() {
    alert('Thank you');
  };
</script>

如果一個(gè)處理程序是通過 HTML 特性(attribute)分配的,那么隨后瀏覽器讀取它,并從特性的內(nèi)容創(chuàng)建一個(gè)新函數(shù),并將這個(gè)函數(shù)寫入 DOM 屬性(property)。

因此,這種方法實(shí)際上與前一種方法相同。

這兩段代碼工作相同:

  1. 只有 HTML:
  2. <input type="button" onclick="alert('Click!')" value="Button">
    
  3. HTML + JS:
  4. <input type="button" id="button" value="Button">
    <script>
      button.onclick = function() {
        alert('Click!');
      };
    </script>

在第一個(gè)例子中,button.onclick 是通過 HTML 特性(attribute)初始化的,而在第二個(gè)例子中是通過腳本初始化的。這是它們唯一的不同之處。

因?yàn)檫@里只有一個(gè) onclick 屬性,所以我們無法分配更多事件處理程序。

在下面這個(gè)示例中,我們使用 JavaScript 添加了一個(gè)處理程序,覆蓋了現(xiàn)有的處理程序:

<input type="button" id="elem" onclick="alert('Before')" value="Click me">
<script>
  elem.onclick = function() { // 覆蓋了現(xiàn)有的處理程序
    alert('After'); // 只會(huì)顯示此內(nèi)容
  };
</script>

要移除一個(gè)處理程序 —— 賦值 elem.onclick = null。

訪問元素:this

處理程序中的 this 的值是對(duì)應(yīng)的元素。就是處理程序所在的那個(gè)元素。

下面這行代碼中的 button 使用 this.innerHTML 來顯示它的內(nèi)容:

<button onclick="alert(this.innerHTML)">Click me</button>

可能出現(xiàn)的錯(cuò)誤

如果你剛開始寫事件 —— 請(qǐng)注意一些細(xì)微之處。

我們可以將一個(gè)現(xiàn)存的函數(shù)用作處理程序:

function sayThanks() {
  alert('Thanks!');
}

elem.onclick = sayThanks;

但要注意:函數(shù)應(yīng)該是以 sayThanks 的形式進(jìn)行賦值,而不是 sayThanks()。

// 正確
button.onclick = sayThanks;

// 錯(cuò)誤
button.onclick = sayThanks();

如果我們添加了括號(hào),那么 sayThanks() 就變成了一個(gè)函數(shù)調(diào)用。所以,最后一行代碼實(shí)際上獲得的是函數(shù)執(zhí)行的 結(jié)果,即 undefined(因?yàn)檫@個(gè)函數(shù)沒有返回值)。此代碼不會(huì)工作。

……但在標(biāo)記(markup)中,我們確實(shí)需要括號(hào):

<input type="button" id="button" onclick="sayThanks()">

這個(gè)區(qū)別很容易解釋。當(dāng)瀏覽器讀取 HTML 特性(attribute)時(shí),瀏覽器將會(huì)使用 特性中的內(nèi)容 創(chuàng)建一個(gè)處理程序。

所以,標(biāo)記(markup)會(huì)生成下面這個(gè)屬性:

button.onclick = function() {
  sayThanks(); // <-- 特性(attribute)中的內(nèi)容變到了這里
};

不要對(duì)處理程序使用 setAttribute。

這樣的調(diào)用會(huì)失效:

// 點(diǎn)擊 <body> 將產(chǎn)生 error,
// 因?yàn)樘匦钥偸亲址?,函?shù)變成了一個(gè)字符串
document.body.setAttribute('onclick', function() { alert(1) });

DOM 屬性是大小寫敏感的。

將處理程序分配給 elem.onclick,而不是 elem.ONCLICK,因?yàn)?DOM 屬性是大小寫敏感的。

addEventListener

上述分配處理程序的方式的根本問題是 —— 我們不能為一個(gè)事件分配多個(gè)處理程序。

假設(shè),在我們點(diǎn)擊了一個(gè)按鈕時(shí),我們代碼中的一部分想要高亮顯示這個(gè)按鈕,另一部分則想要顯示一條消息。

我們想為此事件分配兩個(gè)處理程序。但是,新的 DOM 屬性將覆蓋現(xiàn)有的 DOM 屬性:

input.onclick = function() { alert(1); }
// ...
input.onclick = function() { alert(2); } // 替換了前一個(gè)處理程序

Web 標(biāo)準(zhǔn)的開發(fā)者很早就了解到了這一點(diǎn),并提出了一種使用特殊方法 addEventListener 和 removeEventListener 來管理處理程序的替代方法。它們沒有這樣的問題。

添加處理程序的語法:

element.addEventListener(event, handler[, options]);

?event ?

事件名,例如:?"click"?。

?handler ?

處理程序。

?options ?

具有以下屬性的附加可選對(duì)象:

  • ?once?:如果為 ?true?,那么會(huì)在被觸發(fā)后自動(dòng)刪除監(jiān)聽器。
  • ?capture?:事件處理的階段,我們稍后將在 冒泡和捕獲 一章中介紹。由于歷史原因,?options? 也可以是 ?false/true?,它與 ?{capture: false/true}? 相同。
  • ?passive?:如果為 ?true?,那么處理程序?qū)⒉粫?huì)調(diào)用 ?preventDefault()?,我們稍后將在 瀏覽器默認(rèn)行為 一章中介紹。

要移除處理程序,可以使用 removeEventListener

element.removeEventListener(event, handler[, options]);

移除需要相同的函數(shù)

要移除處理程序,我們需要傳入與分配的函數(shù)完全相同的函數(shù)。

這不起作用:

elem.addEventListener( "click" , () => alert('Thanks!'));
// ....
elem.removeEventListener( "click", () => alert('Thanks!'));

處理程序不會(huì)被移除,因?yàn)?nbsp;removeEventListener 獲取了另一個(gè)函數(shù) —— 使用相同的代碼,但這并不起作用,因?yàn)樗且粋€(gè)不同的函數(shù)對(duì)象。

下面是正確方法:

function handler() {
  alert( 'Thanks!' );
}

input.addEventListener("click", handler);
// ....
input.removeEventListener("click", handler);

請(qǐng)注意 —— 如果我們不將函數(shù)存儲(chǔ)在一個(gè)變量中,那么我們就無法移除它。由 addEventListener 分配的處理程序?qū)o法被“讀回”。

多次調(diào)用 addEventListener 允許添加多個(gè)處理程序,如下所示:

<input id="elem" type="button" value="Click me"/>

<script>
  function handler1() {
    alert('Thanks!');
  };

  function handler2() {
    alert('Thanks again!');
  }

  elem.onclick = () => alert("Hello");
  elem.addEventListener("click", handler1); // Thanks!
  elem.addEventListener("click", handler2); // Thanks again!
</script>

正如我們?cè)谏厦孢@個(gè)例子中所看到的,我們可以 同時(shí) 使用 DOM 屬性和 addEventListener 來設(shè)置處理程序。但通常我們只使用其中一種方式。

對(duì)于某些事件,只能通過 ?addEventListener? 設(shè)置處理程序

有些事件無法通過 DOM 屬性進(jìn)行分配。只能使用 addEventListener。

例如,DOMContentLoaded 事件,該事件在文檔加載完成并且 DOM 構(gòu)建完成時(shí)觸發(fā)。

// 永遠(yuǎn)不會(huì)運(yùn)行
document.onDOMContentLoaded = function() {
  alert("DOM built");
};
// 這種方式可以運(yùn)行
document.addEventListener("DOMContentLoaded", function() {
  alert("DOM built");
});

所以 addEventListener 更通用。雖然這樣的事件是特例而不是規(guī)則。

事件對(duì)象

為了正確處理事件,我們需要更深入地了解發(fā)生了什么。不僅僅是 “click” 或 “keydown”,還包括鼠標(biāo)指針的坐標(biāo)是什么?按下了哪個(gè)鍵?等等。

當(dāng)事件發(fā)生時(shí),瀏覽器會(huì)創(chuàng)建一個(gè) event 對(duì)象,將詳細(xì)信息放入其中,并將其作為參數(shù)傳遞給處理程序。

下面是一個(gè)從 event 對(duì)象獲取鼠標(biāo)指針的坐標(biāo)的示例:

<input type="button" value="Click me" id="elem">

<script>
  elem.onclick = function(event) {
    // 顯示事件類型、元素和點(diǎn)擊的坐標(biāo)
    alert(event.type + " at " + event.currentTarget);
    alert("Coordinates: " + event.clientX + ":" + event.clientY);
  };
</script>

event 對(duì)象的一些屬性:

?event.type ?

事件類型,這里是 ?"click"?。

?event.currentTarget ?

處理事件的元素。這與 ?this? 相同,除非處理程序是一個(gè)箭頭函數(shù),或者它的 ?this? 被綁定到了其他東西上,之后我們就可以從 ?event.currentTarget? 獲取元素了。

?event.clientX? / ?event.clientY ?

指針事件(pointer event)的指針的窗口相對(duì)坐標(biāo)。

還有很多屬性。其中很多都取決于事件類型:鍵盤事件具有一組屬性,指針事件具有另一組屬性,稍后我們將詳細(xì)討論不同事件,那時(shí)我們?cè)賹?duì)其進(jìn)行詳細(xì)研究。

?event? 對(duì)象在 HTML 處理程序中也可用

如果我們?cè)?HTML 中分配了一個(gè)處理程序,那么我們也可以使用 event 對(duì)象,像這樣:

<input type="button" onclick="alert(event.type)" value="Event type">

這是可能的,因?yàn)楫?dāng)瀏覽器讀取特性(attribute)時(shí),它會(huì)創(chuàng)建像這樣的處理程序:function(event) { alert(event.type) }。也就是說:它的第一個(gè)參數(shù)是 "event",而主體取自于該特性(attribute)。

對(duì)象處理程序:handleEvent

我們不僅可以分配函數(shù),還可以使用 addEventListener 將一個(gè)對(duì)象分配為事件處理程序。當(dāng)事件發(fā)生時(shí),就會(huì)調(diào)用該對(duì)象的 handleEvent 方法。

例如:

<button id="elem">Click me</button>

<script>
  let obj = {
    handleEvent(event) {
      alert(event.type + " at " + event.currentTarget);
    }
  };

  elem.addEventListener('click', obj);
</script>

正如我們所看到的,當(dāng) addEventListener 接收一個(gè)對(duì)象作為處理程序時(shí),在事件發(fā)生時(shí),它就會(huì)調(diào)用 obj.handleEvent(event) 來處理事件。

我們也可以對(duì)此使用一個(gè)類:

<button id="elem">Click me</button>

<script>
  class Menu {
    handleEvent(event) {
      switch(event.type) {
        case 'mousedown':
          elem.innerHTML = "Mouse button pressed";
          break;
        case 'mouseup':
          elem.innerHTML += "...and released.";
          break;
      }
    }
  }

  let menu = new Menu();
  elem.addEventListener('mousedown', menu);
  elem.addEventListener('mouseup', menu);
</script>

這里,同一個(gè)對(duì)象處理兩個(gè)事件。請(qǐng)注意,我們需要使用 addEventListener 來顯式設(shè)置事件,以指明要監(jiān)聽的事件。這里的 menu 對(duì)象只監(jiān)聽 mousedown 和 mouseup,而沒有任何其他類型的事件。

handleEvent 方法不必通過自身完成所有的工作。它可以調(diào)用其他特定于事件的方法,例如:

<button id="elem">Click me</button>

<script>
  class Menu {
    handleEvent(event) {
      // mousedown -> onMousedown
      let method = 'on' + event.type[0].toUpperCase() + event.type.slice(1);
      this[method](event);
    }

    onMousedown() {
      elem.innerHTML = "Mouse button pressed";
    }

    onMouseup() {
      elem.innerHTML += "...and released.";
    }
  }

  let menu = new Menu();
  elem.addEventListener('mousedown', menu);
  elem.addEventListener('mouseup', menu);
</script>

現(xiàn)在事件處理程序已經(jīng)明確地分離了出來,這樣更容易進(jìn)行代碼編寫和后續(xù)維護(hù)。

總結(jié)

這里有 3 種分配事件處理程序的方式:

  1. HTML 特性(attribute):?onclick="..."?。
  2. DOM 屬性(property):?elem.onclick = function?。
  3. 方法(method):?elem.addEventListener(event, handler[, phase])? 用于添加,?removeEventListener? 用于移除。

HTML 特性很少使用,因?yàn)?HTML 標(biāo)簽中的 JavaScript 看起來有些奇怪且陌生。而且也不能在里面寫太多代碼。

DOM 屬性用起來還可以,但我們無法為特定事件分配多個(gè)處理程序。在許多場(chǎng)景中,這種限制并不嚴(yán)重。

最后一種方式是最靈活的,但也是寫起來最長(zhǎng)的。有少數(shù)事件只能使用這種方式。例如 transtionend 和 DOMContentLoaded(上文中講到了)。addEventListener 也支持對(duì)象作為事件處理程序。在這種情況下,如果發(fā)生事件,則會(huì)調(diào)用 handleEvent 方法。

無論你如何分類處理程序 —— 它都會(huì)將獲得一個(gè)事件對(duì)象作為第一個(gè)參數(shù)。該對(duì)象包含有關(guān)所發(fā)生事件的詳細(xì)信息。

在下一章中,我們將學(xué)習(xí)更多關(guān)于一般事件和不同類型事件的內(nèi)容。

任務(wù)


點(diǎn)擊隱藏

重要程度: 5

為 button 添加 JavaScript 代碼,使得 <div id="text"> 在我們點(diǎn)擊該按鈕時(shí)消失。

打開一個(gè)任務(wù)沙箱。


解決方案

使用沙箱打開解決方案。


隱藏自己

重要程度: 5

創(chuàng)建一個(gè)按鈕,在被點(diǎn)擊時(shí),隱藏自己。


解決方案

可以在處理程序中使用 this 來引用“元素自身”:

<input type="button" onclick="this.hidden=true" value="Click to hide">

哪個(gè)處理程序會(huì)運(yùn)行?

重要程度: 5

在變量中有一個(gè)按鈕。它上面沒有處理程序。

執(zhí)行以下代碼之后,哪些處理程序會(huì)在按鈕被點(diǎn)擊時(shí)運(yùn)行?會(huì)顯示哪些 alert?

button.addEventListener("click", () => alert("1"));

button.removeEventListener("click", () => alert("1"));

button.onclick = () => alert(2);

解決方案

答案:1 和 2。

第一個(gè)處理程序會(huì)觸發(fā),因?yàn)樗鼪]有被 removeEventListener 移除。要移除處理程序,我們需要傳遞正確的所分配的函數(shù)。在代碼中,傳遞了一個(gè)新的函數(shù),該函數(shù)看起來相同,但仍然是另一個(gè)函數(shù)。

要移除一個(gè)函數(shù)對(duì)象,我們需要存儲(chǔ)對(duì)它的引用,像這樣:

function handler() {
  alert(1);
}

button.addEventListener("click", handler);
button.removeEventListener("click", handler);

無論 addEventListener 怎樣,button.onclick 處理程序都會(huì)觸發(fā)。


讓球在球場(chǎng)中移動(dòng)

重要程度: 5

點(diǎn)擊球場(chǎng)中任意一點(diǎn),讓球在球場(chǎng)中移動(dòng)。

要求:

  • 球的中心應(yīng)該恰好在點(diǎn)擊時(shí)鼠標(biāo)指針位置的下方(如果在球不越過球場(chǎng)邊緣的情況下,能實(shí)現(xiàn)的話)。
  • 最好添加一些 CSS 動(dòng)畫。
  • 球不能越過場(chǎng)地邊界。
  • 頁面滾動(dòng)時(shí),布局不能被破壞。

注意:

  • 代碼還應(yīng)該適用于不同大小的球和球場(chǎng),而不應(yīng)該綁定到任何固定值。
  • 使用 ?event.clientX/event.clientY? 屬性來獲取點(diǎn)擊坐標(biāo)。

打開一個(gè)任務(wù)沙箱。


解決方案

首先,我們需要選擇一種定位球的方法。

我們不能使用 position:fixed,因?yàn)闈L動(dòng)頁面會(huì)造成球被移出球場(chǎng)。

所以我們應(yīng)該使用 position:absolute,并且要使定位真正可靠,應(yīng)該使 field 自身具有 position:absolute

然后,球?qū)⑾鄬?duì)于球場(chǎng)定位:

#field {
  width: 200px;
  height: 150px;
  position: relative;
}

#ball {
  position: absolute;
  left: 0; /* 相對(duì)于最接近的祖先(field) */
  top: 0;
  transition: 1s all; /* left/top 的 CSS 動(dòng)畫,使球飛起來 */
}

接下來我們需要指定正確的 ball.style.left/top。它們現(xiàn)在包含相對(duì)于球場(chǎng)的坐標(biāo)。

這是示意圖:


我們有 event.clientX/clientY —— 點(diǎn)擊位置的窗口相對(duì)坐標(biāo)。

要獲取點(diǎn)擊位置的球場(chǎng)相對(duì)坐標(biāo) left,我們可以減去球場(chǎng)左邊緣和邊框的寬度:

let left = event.clientX - fieldCoords.left - field.clientLeft;

通常情況下,ball.style.left 表示“元素的左邊緣”(球)。因此,如果我們將其指定為 left,那么球的邊緣而非球的中心將位于鼠標(biāo)光標(biāo)下方。

我們需要將球向左移動(dòng)球?qū)挾鹊囊话?,向上移?dòng)球高度的一半,以使其居中。    

所以,最后的 left 將是:

let left = event.clientX - fieldCoords.left - field.clientLeft - ball.offsetWidth/2;

使用相同的邏輯來計(jì)算垂直坐標(biāo)。

請(qǐng)注意,球的寬度/高度必須在我們?cè)L問 ball.offsetWidth 時(shí)就已知。應(yīng)該在 HTML 或 CSS 中指定。

使用沙箱打開解決方案。


創(chuàng)建滑動(dòng)菜單

重要程度: 5

創(chuàng)建一個(gè)在點(diǎn)擊時(shí)打開/折疊的菜單:

P.S. 源文檔的 HTML/CSS 將被修改。

打開一個(gè)任務(wù)沙箱。


解決方案

  • HTML/CSS
  • 首先,讓我們創(chuàng)建 HTML/CSS。

    菜單是頁面上的一個(gè)獨(dú)立圖形組件,所以最好把它放入一個(gè)單獨(dú)的 DOM 元素中。

    菜單項(xiàng)的列表可以被作為列表 ul/li 列出。

    下面是示例結(jié)構(gòu):

    <div class="menu">
      <span class="title">Sweeties (click me)!</span>
      <ul>
        <li>Cake</li>
        <li>Donut</li>
        <li>Honey</li>
      </ul>
    </div>

    我們對(duì)標(biāo)題使用 <span>,因?yàn)?nbsp;<div> 有一個(gè)隱式的 display:block,它會(huì)占據(jù) 100% 的水平寬度。

    就像這樣:

    <div style="border: solid red 1px" onclick="alert(1)">Sweeties (click me)!</div>
    

    因此,如果我們?cè)谒厦嬖O(shè)置 onclick,那么它也會(huì)捕獲文本右側(cè)的點(diǎn)擊。

    ……由于 <span> 有一個(gè)隱式的 display: inline,它恰好占據(jù)了足以容納所有文本的位置:

    <span style="border: solid red 1px" onclick="alert(1)">Sweeties (click me)!</span>
    
  • 切換菜單
  • 切換菜單應(yīng)更改箭頭并顯示/隱藏菜單列表。

    所有這些更改都可以通過 CSS 完美處理。在 JavaScript 中,我們應(yīng)該通過添加/移除 .open 類來標(biāo)記菜單的當(dāng)前狀態(tài)。

    沒有它,菜單就會(huì)被關(guān)閉:

    .menu ul {
      margin: 0;
      list-style: none;
      padding-left: 20px;
      display: none;
    }
    
    .menu .title::before {
      content: '? ';
      font-size: 80%;
      color: green;
    }

    ……有 .open 后,箭頭會(huì)改變,列表會(huì)出現(xiàn):

    .menu.open .title::before {
      content: '▼ ';
    }
    
    .menu.open ul {
      display: block;
    }

    使用沙箱打開解決方案。


添加關(guān)閉按鈕

重要程度: 5

有一個(gè)消息列表。

使用 JavaScript 在每條消息的右上角添加一個(gè)關(guān)閉按鈕。

結(jié)果應(yīng)該如下所示:


打開一個(gè)任務(wù)沙箱。


解決方案

我們可以使用 position:absolute(并使窗格 position:relative)或者 float:right 來添加按鈕。float:right 的好處是按鈕永遠(yuǎn)都不會(huì)與文本重疊,但是 position:absolute 則提供了更大的自由度。選擇權(quán)在你自己手上。

然后,對(duì)于每個(gè)窗格(pane),代碼可以像這樣:

pane.insertAdjacentHTML("afterbegin", '<button class="remove-button">[x]</button>');

然后 <button> 變成了 pane.firstChild,因此我們可以像這樣為它添加處理程序:

pane.firstChild.onclick = () => pane.remove();

使用沙箱打開解決方案。


輪播圖

重要程度: 4

創(chuàng)建一個(gè)“輪播圖(carousel)” —— 一條可以通過點(diǎn)擊箭頭來滾動(dòng)圖像的圖像帶。


之后,我們可以為其添加更多功能:無限滾動(dòng),動(dòng)態(tài)加載等。

P.S. 對(duì)于這個(gè)任務(wù),HTML/CSS 結(jié)構(gòu)實(shí)際上占解決方案的 90%。

打開一個(gè)任務(wù)沙箱。


解決方案

圖像帶可以表示為圖像 <img> 的 ul/li 列表。

通常,這樣的圖像帶是很寬的,但我們?cè)谄渲車胖昧艘粋€(gè)固定大小的 <div> 來“剪切”它,因此,只有圖像帶的一部分是可見的:


為了使列表水平顯示,我們需要為 <li> 應(yīng)用正確的 CSS 屬性,例如 display: inline-block。

對(duì)于 <img> 來說,我們應(yīng)該調(diào)整 display,因?yàn)槟J(rèn)情況下它是 inline。在 inline 元素下方為 “l(fā)etter tails” 保留了額外的空間,因此,我們可以使用 display:block 來將其刪除。

我們可以移動(dòng) <ul> 來進(jìn)行滾動(dòng)。有很多方法可以實(shí)現(xiàn)這一點(diǎn),例如,通過修改 margin-left 或者使用 transform: translateX()(性能更好):


外部的 <div> 具有固定的寬度,因此,會(huì)裁剪掉“多余”的圖像。

整個(gè)輪播圖是頁面上的一個(gè)獨(dú)立的“圖形組件”,因此我們最好將其包裝到一個(gè)單獨(dú)的 <div class="carousel"> 中,并在其中對(duì)其進(jìn)行樣式設(shè)置。

使用沙箱打開解決方案。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)