事件介绍

Events are actions or occurrences that happen in the system you are programming, which the system tells you about so your code can react to them.

For example, if the user clicks a button on a webpage, you might want to react to that action by displaying an information box. In this article, we discuss some important concepts surrounding events, and look at how they work in browsers. This won't be an exhaustive study; just what you need to know at this stage.

Prerequisites: Basic computer literacy, a basic understanding of HTML and CSS, JavaScript 第一步 .
Objective: To understand the fundamental theory of events, how they work in browsers, and how events may differ in different programming environments.

A series of fortunate events

As mentioned above, events are actions or occurrences that happen in the system you are programming — the system produces (or "fires") a signal of some kind when an event occurs, and provides a mechanism by which an action can be automatically taken (that is, some code running) when the event occurs. For example, in an airport, when the runway is clear for take off, a signal is communicated to the pilot. As a result, the plane can safely take off.

Image displaying signal for plane to take-off

In the case of the Web, events are fired inside the browser window, and tend to be attached to a specific item that resides in it. This might be a single element, a set of elements, the HTML document loaded in the current tab, or the entire browser window. There are many different types of events that can occur.

例如:

  • The user selects a certain element or hovers the cursor over a certain element.
  • The user chooses a key on the keyboard.
  • The user resizes or closes the browser window.
  • A web page finishes loading.
  • A form is submitted.
  • A video is played, paused, or finishes.
  • An error occurs.

You can gather from this (and from glancing at the MDN event reference ) that there are a lot of events that can be fired.

To react to an event, you attach an event handler to it. This is a block of code (usually a JavaScript function that you as a programmer create) that runs when the event fires. When such a block of code is defined to run in response to an event, we say we are registering an event handler . Note: Event handlers are sometimes called event listeners — they are pretty much interchangeable for our purposes, although strictly speaking, they work together. The listener listens out for the event happening, and the handler is the code that is run in response to it happening.

注意: Web events are not part of the core JavaScript language — they are defined as part of the APIs built into the browser.

简单范例

Let's look at a simple example of what we mean here. In the following example, we have a single <button> , which when pressed, makes the background change to a random color:

<button>Change color</button>

						

The JavaScript looks like so:

const btn = document.querySelector('button');
function random(number) {
  return Math.floor(Math.random() * (number+1));
}
btn.addEventListener('click', () => {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
});

						

In this code, we store a reference to the <button> element inside a constant called btn ,使用 Document.querySelector() 函数。

We also define a function that returns a random number.

The third part of the code is where we define and register the event handler. The <button> element has an event called 'click' that fires when the user clicks the button. Objects that can fire events have an addEventListener() method, that takes at least two arguments: the name of the event and a function to handle the event. So we call the button's addEventListener() method, passing in:

  • the string 'click' , to indicate that we want to listen to the click event
  • a function to call when the event happens. In our case the function generates a random RGB color and sets the page <body> background-color equal to that color.

The example output is as follows. Try clicking the button:

It's not just web pages

Events are not unique to JavaScript — most programming languages have some kind of event model, and the way the model works often differs from JavaScript's way. In fact, the event model in JavaScript for web pages differs from the event model for JavaScript as it is used in other environments.

例如, Node.js is a very popular JavaScript runtime that enables developers to use JavaScript to build network and server-side applications. Node.js event model relies on listeners to listen for events and emitters to emit events periodically — it doesn't sound that different, but the code is quite different, making use of functions like on() to register an event listener, and once() to register an event listener that unregisters after it has run once. HTTP connect event docs provide a good example.

You can also use JavaScript to build cross-browser add-ons — browser functionality enhancements — using a technology called WebExtensions . The event model is similar to the web events model, but a bit different — event listeners properties are camel-cased (such as onMessage 而不是 onmessage ), and need to be combined with the addListener 函数。 见 runtime.onMessage page for an example.

You don't need to understand anything about other such environments at this stage in your learning; we just wanted to make it clear that events can differ in different programming environments.

Using addEventListener()

The recommended mechanism for adding event handlers in web pages is the addEventListener() 方法:

const btn = document.querySelector('button');
function random(number) {
  return Math.floor(Math.random() * (number+1));
}
btn.addEventListener('click', () => {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
});

						

注意: You can find the full source code for this example on GitHub (also see it running live ).

Inside the addEventListener() function, we specify two parameters: the name of the event we want to register this handler for, and the code that comprises the handler function we want to run in response to it.

It is fine to make the handler function a separate named function, like this:

const btn = document.querySelector('button');
function random(number) {
  return Math.floor(Math.random() * (number+1));
}
function changeBackground() {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
}
btn.addEventListener('click', changeBackground);

						

Listening for other events

There are many different events that can be fired by a button element. Let's experiment.

First, make a local copy of random-color-addeventlistener.html , and open it in your browser. It's just a copy of the simple random color example we've played with already. Now try changing click to the following different values in turn, and observing the results in the example:

  • focus and blur — The color changes when the button is focused and unfocused; try pressing the tab to focus on the button and press the tab again to focus away from the button. These are often used to display information about filling in form fields when they are focused, or displaying an error message if a form field is filled with an incorrect value.
  • dblclick — The color changes only when the button is double-clicked.
  • mouseover and mouseout — The color changes when the mouse pointer hovers over the button, or when the pointer moves off the button, respectively.

某些事件,譬如 click , are available on nearly any element. Others are more specific and only useful in certain situations: for example, the play event is only available on some elements, such as <video> .

Removing listeners

If you've added an event handler using addEventListener() , you can remove it again using the removeEventListener() method. For example, this would remove the changeBackground() event handler:

btn.removeEventListener('click', changeBackground);

						

Event handlers can also be removed by passing an AbortSignal to addEventListener() and then later calling abort() on the controller owning the AbortSignal . For example, to add an event handler that we can remove with an AbortSignal :

const controller = new AbortController();
btn.addEventListener('click', () => {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
}, { signal: controller.signal }); // pass an AbortSignal to this handler

						

Then the event handler created by the code above can be removed like this:

controller.abort(); // removes any/all event handlers associated with this controller

						

For simple, small programs, cleaning up old, unused event handlers isn’t necessary, but for larger, more complex programs, it can improve efficiency. Also, the ability to remove event handlers allows you to have the same button performing different actions in different circumstances: all you have to do is add or remove handlers.

Adding multiple listeners for a single event

By making more than one call to addEventListener() , providing different handlers, you can have multiple handlers for a single event:

myElement.addEventListener('click', functionA);
myElement.addEventListener('click', functionB);

						

Both functions would now run when the element is clicked.

了解更多

There are other powerful features and options available with addEventListener() .

These are a little out of scope for this article, but if you want to read them, visit the addEventListener() and removeEventListener() reference pages.

Other event listener mechanisms

推荐使用 addEventListener() to register event handlers. It's the most powerful method and scales best with more complex programs. However, there are two other ways of registering event handlers that you might see: event handler properties and inline event handlers .

Event handler properties

Objects (such as buttons) that can fire events also usually have properties whose name is on followed by the name of the event. For example, elements have a property onclick . This is called an event handler property . To listen for the event, you can assign the handler function to the property.

For example, we could rewrite the random-color example like this:

const btn = document.querySelector('button');
function random(number) {
  return Math.floor(Math.random() * (number+1));
}
btn.onclick = () => {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
}

						

You can also set the handler property to a named function:

const btn = document.querySelector('button');
function random(number) {
  return Math.floor(Math.random() * (number+1));
}
function bgChange() {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
}
btn.onclick = bgChange;

						

With event handler properties, you can't add more than one handler for a single event. For example, you can call addEventListener('click', handler) on an element multiple times, with different functions specified in the second argument:

element.addEventListener('click', function1);
element.addEventListener('click', function2);

						

This is impossible with event handler properties because any subsequent attempts to set the property will overwrite earlier ones:

element.onclick = function1;
element.onclick = function2;

						

Inline event handlers — don't use these

You might also see a pattern like this in your code:

<button onclick="bgChange()">Press me</button>

						
function bgChange() {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
}

						

The earliest method of registering event handlers found on the Web involved event handler HTML attributes (或 inline event handlers ) like the one shown above — the attribute value is literally the JavaScript code you want to run when the event occurs. The above example invokes a function defined inside a <script> element on the same page, but you could also insert JavaScript directly inside the attribute, for example:

<button onclick="alert('Hello, this is my old-fashioned event handler!');">Press me</button>

						

You can find HTML attribute equivalents for many of the event handler properties; however, you shouldn't use these — they are considered bad practice. It might seem easy to use an event handler attribute if you are doing something really quick, but they quickly become unmanageable and inefficient.

For a start, it is not a good idea to mix up your HTML and your JavaScript, as it becomes hard to read. Keeping your JavaScript separate is a good practice, and if it is in a separate file you can apply it to multiple HTML documents.

Even in a single file, inline event handlers are not a good idea. One button is OK, but what if you had 100 buttons? You'd have to add 100 attributes to the file; it would quickly turn into a maintenance nightmare. With JavaScript, you could easily add an event handler function to all the buttons on the page no matter how many there were, using something like this:

const buttons = document.querySelectorAll('button');
for (const button of buttons) {
  button.addEventListener('click', bgChange);
}

						

Finally, many common server configurations will disallow inline JavaScript, as a security measure.

You should never use the HTML event handler attributes — those are outdated, and using them is bad practice.

Event objects

Sometimes, inside an event handler function, you'll see a parameter specified with a name such as event , evt ,或 e . This is called the event object , and it is automatically passed to event handlers to provide extra features and information. For example, let's rewrite our random color example again slightly:

const btn = document.querySelector('button');
function random(number) {
  return Math.floor(Math.random() * (number+1));
}
function bgChange(e) {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  e.target.style.backgroundColor = rndCol;
  console.log(e);
}
btn.addEventListener('click', bgChange);

						

注意: You can find the full source code for this example on GitHub (also see it running live ).

Here you can see we are including an event object, e , in the function, and in the function setting a background color style on e.target — which is the button itself. target property of the event object is always a reference to the element the event occurred upon. So, in this example, we are setting a random background color on the button, not the page.

注意: 事件委托 section below for an example where we use event.target .

注意: You can use any name you like for the event object — you just need to choose a name that you can then use to reference it inside the event handler function.

e / evt / event are most commonly used by developers because they are short and easy to remember. It's always good to be consistent — with yourself, and with others if possible.

Extra properties of event objects

Most event objects have a standard set of properties and methods available on the event object; see the 事件 object reference for a full list.

Some event objects add extra properties that are relevant to that particular type of event. For example, the keydown event fires when the user presses a key. Its event object is a KeyboardEvent , which is a specialized 事件 object with a key property that tells you which key was pressed:

<input id="textBox" type="text"></input>
<div id="output"></div>

						
const textBox = document.querySelector("#textBox");
const output = document.querySelector("#output");
textBox.addEventListener('keydown', event => output.textContent = `You pressed "${event.key}".`);

						

Try typing into the text box and see the output:

Preventing default behavior

Sometimes, you'll come across a situation where you want to prevent an event from doing what it does by default. The most common example is that of a web form, for example, a custom registration form. When you fill in the details and select the submit button, the natural behavior is for the data to be submitted to a specified page on the server for processing, and the browser to be redirected to a "success message" page of some kind (or the same page, if another is not specified.)

The trouble comes when the user has not submitted the data correctly — as a developer, you want to prevent the submission to the server and give an error message saying what's wrong and what needs to be done to put things right. Some browsers support automatic form data validation features, but since many don't, you are advised to not rely on those and implement your own validation checks. Let's look at a simple example.

First, a simple HTML form that requires you to enter your first and last name:

<form>
  <div>
    <label for="fname">First name: </label>
    <input id="fname" type="text">
  </div>
  <div>
    <label for="lname">Last name: </label>
    <input id="lname" type="text">
  </div>
  <div>
     <input id="submit" type="submit">
  </div>
</form>
<p></p>

						

Now some JavaScript — here we implement a very simple check inside a handler for the submit event (the submit event is fired on a form when it is submitted) that tests whether the text fields are empty. If they are, we call the preventDefault() function on the event object — which stops the form submission — and then display an error message in the paragraph below our form to tell the user what's wrong:

const form = document.querySelector('form');
const fname = document.getElementById('fname');
const lname = document.getElementById('lname');
const para = document.querySelector('p');
form.addEventListener('submit', e => {
  if (fname.value === '' || lname.value === '') {
    e.preventDefault();
    para.textContent = 'You need to fill in both names!';
  }
});

						

Obviously, this is pretty weak form validation — it wouldn't stop the user validating the form with spaces or numbers entered into the fields, for example — but it is OK for example purposes. The output is as follows:

注意: for the full source code, see preventdefault-validation.html (also see it running live here.)

事件冒泡和捕获

Event bubbling and capture are terms that describe phases in how the browser handles events targeted at nested elements.

Setting a listener on a parent element

Consider a web page like this:

<div id="container">
  <button>Click me!</button>
</div>
<pre id="output"></pre>

						

Here the button is inside another element, a <div> element. We say that the <div> element here is the parent of the element it contains. What happens if we add a click event handler to the parent, then click the button?

const output = document.querySelector('#output');
function handleClick(e) {
  output.textContent += `You clicked on a ${e.currentTarget.tagName} element\n`;
}
const container = document.querySelector('#container');
container.addEventListener('click', handleClick);

						

You'll see that the parent fires a click event when the user clicks the button:

You clicked on a DIV element
						

This makes sense: the button is inside the <div> , so when you click the button you're also implicitly clicking the element it is inside.

Bubbling example

What happens if we add event listeners to the button and the parent?

<body>
  <div id="container">
    <button>Click me!</button>
  </div>
  <pre id="output"></pre>
</body>

						

Let's try adding click event handlers to the button, its parent (the <div> ), and the <body> element that contains both of them:

const output = document.querySelector('#output');
function handleClick(e) {
  output.textContent += `You clicked on a ${e.currentTarget.tagName} element\n`;
}
const container = document.querySelector('#container');
const button = document.querySelector('button');
document.body.addEventListener('click', handleClick);
container.addEventListener('click', handleClick);
button.addEventListener('click', handleClick);

						

You'll see that all three elements fire a click event when the user clicks the button:

You clicked on a BUTTON element
You clicked on a DIV element
You clicked on a BODY element
						

In this case:

  • the click on the button fires first
  • followed by the click on its parent (the <div> element)
  • followed by the <div> element's parent (the <body> element).

We describe this by saying that the event bubbles up from the innermost element that was clicked.

This behavior can be useful and can also cause unexpected problems. In the next section we'll see a problem that it causes, and find the solution.

Video player example

Open up the show-video-box.html example in a new tab (and the 源代码 in another tab.) It is also available live below:

This example shows and hides a <div> 采用 <video> element inside it:

<button>Display video</button>
<div class="hidden">
  <video>
    <source src="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/events/rabbit320.mp4" type="video/mp4">
    <source src="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/events/rabbit320.webm" type="video/webm">
    <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p>
  </video>
</div>

						

<button> is clicked, the video is displayed, by changing the class attribute on the <div> from hidden to showing (the example's CSS contains these two classes, which position the box off the screen and on the screen, respectively):

const btn = document.querySelector('button');
const videoBox = document.querySelector('div');
function displayVideo() {
  if (videoBox.getAttribute('class') === 'hidden') {
    videoBox.setAttribute('class','showing');
  }
}
btn.addEventListener('click', displayVideo);

						

We then add a couple more click event handlers — the first one to the <div> and the second one to the <video> :

videoBox.addEventListener('click', () => videoBox.setAttribute('class', 'hidden'));
const video = document.querySelector('video');
video.addEventListener('click', () => video.play());

						

Now, when the area of the <div> outside the video is selected, the box should be hidden again and when the video itself is selected, the video should start to play.

But there's a problem — currently, when you select the video it starts to play, but it causes the <div> to be hidden at the same time. This is because the video is inside the <div> — it is part of it — so selecting the video actually runs both the above event handlers.

Bubbling and capturing explained

When an event is fired on an element that has parent elements (in this case, the <video> 拥有 <div> as a parent), modern browsers run three different phases — the capturing phase, the target phase, and the bubbling phase.

capturing phase:

  • The browser checks to see if the element's outer-most ancestor ( <html> ) has a click event handler registered on it for the capturing phase, and runs it if so.
  • Then it moves on to the next element inside <html> and does the same thing, then the next one, and so on until it reaches the direct parent of the element that was actually selected.

target phase:

  • The browser checks to see if the target property has an event handler for the click event registered on it, and runs it if so.
  • Then, if bubbles is true , it propagates the event to the direct parent of the selected element, then the next one, and so on until it reaches the <html> 元素。 否则,若 bubbles is false , it doesn’t propagate the event to any ancestors of the target.

bubbling phase, the exact opposite of the capturing phase occurs:

  • The browser checks to see if the direct parent of the element selected has a click event handler registered on it for the bubbling phase, and runs it if so.
  • Then it moves on to the next immediate ancestor element and does the same thing, then the next one, and so on until it reaches the <html> 元素。

In modern browsers, by default, all event handlers are registered for the bubbling phase. So in our current example, when you select the video, the event bubbles from the <video> element outwards to the <html> 元素。 Along the way:

  • It finds the click handler on the 视频 element and runs it, so the video first starts playing.
  • It then finds the click handler on the videoBox element and runs that, so the video is hidden as well.

注意: All JavaScript events go through the capturing and target phases. Whether an event enters the bubbling phase can be checked by the read-only bubbles 特性。

注意: Event listeners registered for the <html> element aren’t at the top of hierarchy. For example, event listeners registered for the window and document objects are higher in the hierarchy.

The following example demonstrates the behavior described above. Hover over the numbers and click on them to trigger events, and then observe the output that gets logged.

Example code: event phases

<div>1
    <div>2
        <div>3
            <div>4
                <div>5</div>
            </div>
        </div>
    </div>
</div>
<button id="clear">clear output</button>
<section id="log"></section>

						
p {
    line-height: 0;
}
div {
    display: inline-block;
    padding: 5px;
    background: #fff;
    border: 1px solid #aaa;
    cursor: pointer;
}
div:hover {
    border: 1px solid #faa;
    background: #fdd;
}

						
/*
 * source 1: https://dom.spec.whatwg.org/#dom-event-eventphase
 * source 2: https://stackoverflow.com/a/4616720/15266715
*/
const evtPhasestr = ["NONE: ", "CAPTURING_PHASE: ", "AT_TARGET: ", "BUBBLING_PHASE: "];
const logElement = document.getElementById('log');
function log(msg) {
    logElement.innerHTML += (`<p>${msg}</p>`);
}
function phase(evt) {
    log(evtPhasestr[evt.eventPhase] + this.firstChild.nodeValue.trim());
}
function gphase(evt) {
    log(evtPhasestr[evt.eventPhase] + evt.currentTarget.toString().slice(8,-1));
}
function clearOutput(evt) {
    evt.stopPropagation();
    logElement.innerHTML = '';
}
const divs = document.getElementsByTagName('div');
for (const div of divs) {
  div.addEventListener('click', phase, true);
  div.addEventListener('click', phase, false);
}
document.addEventListener('click', gphase, true);
document.addEventListener('click', gphase, false);
window.addEventListener('click', gphase, true);
window.addEventListener('click', gphase, false);
const clearButton = document.getElementById('clear');
clearButton.addEventListener('click', clearOutput);

						

Fixing the problem with stopPropagation()

As we saw in the video example, this can be a very annoying behavior, but there is a way to prevent it! 标准 事件 object has a function available on it called stopPropagation() which, when invoked on a handler's event object, makes it so that first handler is run but the event doesn't bubble any further up the chain, so no more handlers will be run.

So we can fix our current problem by changing the second handler function in the previous code block to this:

video.addEventListener('click', e => {
  e.stopPropagation();
  video.play();
});

						

You can try making a local copy of the show-video-box.html source code and fixing it yourself, or looking at the fixed result in show-video-box-fixed.html (also see the 源代码 here).

注意: Why bother with both capturing and bubbling? Well, in the bad old days when browsers were much less cross-compatible than they are now, Netscape only used event capturing, and Internet Explorer used only event bubbling. When the W3C decided to try to standardize the behavior and reach a consensus, they ended up with this system that included both, which is the one modern browsers implemented.

注意: As mentioned above, by default all event handlers are registered in the bubbling phase, and this makes more sense most of the time. If you really want to register an event in the capturing phase instead, you can do so by registering your handler using addEventListener() , and setting the optional third property to true .

事件委托

Event bubbling isn't just annoying though: it can be very useful. In particular it enables a practice called event delegation . In this practice, when we want some code to run when the user interacts with any one of a large number of child elements, we set the event listener on their parent and have events that happen on them bubble up to their parent rather than having to set the event listener on every child individually.

Let's go back to our first example, where we set the background color of the whole page when the user clicked a button. Suppose that instead, the page is divided into 16 tiles, and we want to set each tile to a random color when the user clicks that tile.

Here's the HTML:

<div id="container">
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
</div>

						

We have a little CSS, to set the size and position of the tiles:

.tile {
  height: 100px;
  width: 25%;
  float: left;
}

						

Now in the JavaScript, we could add a click event handler for every tile. But a much simpler and more efficient option is to set the click event handler on the parent, and rely on event bubbling to ensure that the handler is executed when the user clicks on a tile:

function random(number) {
  return Math.floor(Math.random()*number);
}
function bgChange() {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  return rndCol;
}
const container = document.querySelector('#container');
container.addEventListener('click', event => event.target.style.backgroundColor = bgChange());

						

The output is as follows (try clicking around on it):

注意: In this example we're using event.target to get the element that was the target of the event (that is, the innermost element). If we wanted to access the element that fired this event (in this case the container) we could use event.currentTarget .

注意: useful-eventtarget.html for the full source code; also see it running live 这里。

Test your skills!

You've reached the end of this article, but can you remember the most important information? To verify you've retained this information before you move on — see Test your skills: Events .

结论

You should now know all you need to know about web events at this early stage. As mentioned, events are not really part of the core JavaScript — they are defined in browser Web APIs.

Also, it is important to understand that the different contexts in which JavaScript is used have different event models — from Web APIs to other areas such as browser WebExtensions and Node.js (server-side JavaScript). We are not expecting you to understand all of these areas now, but it certainly helps to understand the basics of events as you forge ahead with learning web development.

If there is anything you didn't understand, feel free to read through the article again, or contact us to ask for help.

另请参阅

  • domevents.dev — a very useful interactive playground app that enables learning about the behavior of the DOM Event system through exploration.
  • 事件参考
  • Event order (discussion of capturing and bubbling) — an excellently detailed piece by Peter-Paul Koch.
  • Event accessing (discussion of the event object) — another excellently detailed piece by Peter-Paul Koch.

In this module

发现此页面有问题吗?

最后修改: , 由 MDN 贡献者

  1. Complete beginners start here!
  2. Web 快速入门
    1. Getting started with the Web overview
    2. 安装基本软件
    3. What will your website look like?
    4. 处理文件
    5. HTML 基础
    6. CSS 基础
    7. JavaScript 基础
    8. 发布您的网站
    9. How the Web works
  3. HTML — Structuring the Web
  4. HTML 介绍
    1. Introduction to HTML overview
    2. Getting started with HTML
    3. What's in the head? Metadata in HTML
    4. HTML text fundamentals
    5. Creating hyperlinks
    6. Advanced text formatting
    7. Document and website structure
    8. Debugging HTML
    9. Assessment: Marking up a letter
    10. Assessment: Structuring a page of content
  5. 多媒体和嵌入
    1. Multimedia and embedding overview
    2. Images in HTML
    3. Video and audio content
    4. From object to iframe — other embedding technologies
    5. Adding vector graphics to the Web
    6. Responsive images
    7. Assessment: Mozilla splash page
  6. HTML 表格
    1. HTML tables overview
    2. HTML table basics
    3. HTML Table advanced features and accessibility
    4. Assessment: Structuring planet data
  7. CSS — Styling the Web
  8. CSS 第一步
    1. CSS first steps overview
    2. What is CSS?
    3. Getting started with CSS
    4. How CSS is structured
    5. How CSS works
    6. Using your new knowledge
  9. CSS 构建块
    1. CSS building blocks overview
    2. Cascade and inheritance
    3. CSS 选择器
    4. The box model
    5. Backgrounds and borders
    6. Handling different text directions
    7. Overflowing content
    8. Values and units
    9. Sizing items in CSS
    10. Images, media, and form elements
    11. Styling tables
    12. Debugging CSS
    13. Organizing your CSS
  10. 样式化文本
    1. Styling text overview
    2. Fundamental text and font styling
    3. Styling lists
    4. Styling links
    5. Web fonts
    6. Assessment: Typesetting a community school homepage
  11. CSS 布局
    1. CSS layout overview
    2. Introduction to CSS layout
    3. Normal Flow
    4. Flexbox
    5. Grids
    6. Floats
    7. 位置
    8. Multiple-column Layout
    9. Responsive design
    10. Beginner's guide to media queries
    11. Legacy Layout Methods
    12. Supporting Older Browsers
    13. Fundamental Layout Comprehension
  12. JavaScript — Dynamic client-side scripting
  13. JavaScript 第一步
    1. JavaScript first steps overview
    2. What is JavaScript?
    3. A first splash into JavaScript
    4. What went wrong? Troubleshooting JavaScript
    5. Storing the information you need — Variables
    6. Basic math in JavaScript — Numbers and operators
    7. Handling text — Strings in JavaScript
    8. Useful string methods
    9. 数组
    10. Assessment: Silly story generator
  14. JavaScript 构建块
    1. JavaScript building blocks overview
    2. Making decisions in your code — Conditionals
    3. Looping code
    4. Functions — Reusable blocks of code
    5. Build your own function
    6. Function return values
    7. 事件介绍
    8. Assessment: Image gallery
  15. 引入 JavaScript 对象
    1. Introducing JavaScript objects overview
    2. Object basics
    3. 对象原型
    4. Object-oriented programming concepts
    5. Classes in JavaScript
    6. Working with JSON data
    7. Object building practice
    8. Assessment: Adding features to our bouncing balls demo
  16. 异步 JavaScript
    1. Asynchronous JavaScript overview
    2. General asynchronous programming concepts
    3. Introducing asynchronous JavaScript
    4. Cooperative asynchronous Java​Script: Timeouts and intervals
    5. Graceful asynchronous programming with Promises
    6. Making asynchronous programming easier with async and await
    7. Choosing the right approach
  17. 客户端侧 Web API
    1. 客户端侧 Web API
    2. Introduction to web APIs
    3. Manipulating documents
    4. Fetching data from the server
    5. Third party APIs
    6. Drawing graphics
    7. Video and audio APIs
    8. Client-side storage
  18. Web forms — Working with user data
  19. Core forms learning pathway
    1. Web forms overview
    2. Your first form
    3. How to structure a web form
    4. Basic native form controls
    5. The HTML5 input types
    6. Other form controls
    7. Styling web forms
    8. Advanced form styling
    9. UI pseudo-classes
    10. Client-side form validation
    11. Sending form data
  20. Advanced forms articles
    1. How to build custom form controls
    2. Sending forms through JavaScript
    3. CSS property compatibility table for form controls
  21. Accessibility — Make the web usable by everyone
  22. Accessibility guides
    1. Accessibility overview
    2. What is accessibility?
    3. HTML: A good basis for accessibility
    4. CSS and JavaScript accessibility best practices
    5. WAI-ARIA basics
    6. Accessible multimedia
    7. Mobile accessibility
  23. Accessibility assessment
    1. Assessment: Accessibility troubleshooting
  24. Tools and testing
  25. Client-side web development tools
    1. Client-side web development tools index
    2. Client-side tooling overview
    3. Command line crash course
    4. Package management basics
    5. Introducing a complete toolchain
    6. Deploying our app
  26. Introduction to client-side frameworks
    1. Client-side frameworks overview
    2. Framework main features
  27. React
    1. Getting started with React
    2. Beginning our React todo list
    3. Componentizing our React app
    4. React interactivity: Events and state
    5. React interactivity: Editing, filtering, conditional rendering
    6. Accessibility in React
    7. React resources
  28. Ember
    1. Getting started with Ember
    2. Ember app structure and componentization
    3. Ember interactivity: Events, classes and state
    4. Ember Interactivity: Footer functionality, conditional rendering
    5. Routing in Ember
    6. Ember resources and troubleshooting
  29. Vue
    1. Getting started with Vue
    2. Creating our first Vue component
    3. Rendering a list of Vue components
    4. Adding a new todo form: Vue events, methods, and models
    5. Styling Vue components with CSS
    6. Using Vue computed properties
    7. Vue conditional rendering: editing existing todos
    8. Focus management with Vue refs
    9. Vue resources
  30. Svelte
    1. Getting started with Svelte
    2. Starting our Svelte Todo list app
    3. Dynamic behavior in Svelte: working with variables and props
    4. Componentizing our Svelte app
    5. Advanced Svelte: Reactivity, lifecycle, accessibility
    6. Working with Svelte stores
    7. TypeScript support in Svelte
    8. Deployment and next steps
  31. Angular
    1. Getting started with Angular
    2. Beginning our Angular todo list app
    3. Styling our Angular app
    4. Creating an item component
    5. Filtering our to-do items
    6. Building Angular applications and further resources
  32. Git and GitHub
    1. Git and GitHub overview
    2. Hello World
    3. Git Handbook
    4. Forking Projects
    5. About pull requests
    6. Mastering Issues
  33. Cross browser testing
    1. Cross browser testing overview
    2. Introduction to cross browser testing
    3. Strategies for carrying out testing
    4. Handling common HTML and CSS problems
    5. Handling common JavaScript problems
    6. Handling common accessibility problems
    7. Implementing feature detection
    8. Introduction to automated testing
    9. Setting up your own test automation environment
  34. Server-side website programming
  35. 第一步
    1. First steps overview
    2. Introduction to the server-side
    3. Client-Server overview
    4. Server-side web frameworks
    5. Website security
  36. Django Web 框架 (Python)
    1. Django web framework (Python) overview
    2. 介绍
    3. 设置开发环境
    4. Tutorial: The Local Library website
    5. Tutorial Part 2: Creating a skeleton website
    6. Tutorial Part 3: Using models
    7. Tutorial Part 4: Django admin site
    8. Tutorial Part 5: Creating our home page
    9. Tutorial Part 6: Generic list and detail views
    10. Tutorial Part 7: Sessions framework
    11. Tutorial Part 8: User authentication and permissions
    12. Tutorial Part 9: Working with forms
    13. Tutorial Part 10: Testing a Django web application
    14. Tutorial Part 11: Deploying Django to production
    15. Web application security
    16. Assessment: DIY mini blog
  37. Express Web Framework (node.js/JavaScript)
    1. Express Web Framework (Node.js/JavaScript) overview
    2. Express/Node introduction
    3. Setting up a Node (Express) development environment
    4. Express tutorial: The Local Library website
    5. Express Tutorial Part 2: Creating a skeleton website
    6. Express Tutorial Part 3: Using a database (with Mongoose)
    7. Express Tutorial Part 4: Routes and controllers
    8. Express Tutorial Part 5: Displaying library data
    9. Express Tutorial Part 6: Working with forms
    10. Express Tutorial Part 7: Deploying to production
  38. Further resources
  39. Common questions
    1. HTML questions
    2. CSS questions
    3. JavaScript questions
    4. Web mechanics
    5. Tools and setup
    6. Design and accessibility