minor
This commit is contained in:
parent
405032ef32
commit
ba2b7b0c4a
1 changed files with 39 additions and 40 deletions
|
@ -11,13 +11,13 @@ Here's a list of the most useful DOM events, just to take a look at:
|
||||||
- `mousedown` / `mouseup` -- when the mouse button is pressed / released over an element.
|
- `mousedown` / `mouseup` -- when the mouse button is pressed / released over an element.
|
||||||
- `mousemove` -- when the mouse is moved.
|
- `mousemove` -- when the mouse is moved.
|
||||||
|
|
||||||
|
**Keyboard events:**
|
||||||
|
- `keydown` and `keyup` -- when a keyboard key is pressed and released.
|
||||||
|
|
||||||
**Form element events:**
|
**Form element events:**
|
||||||
- `submit` -- when the visitor submits a `<form>`.
|
- `submit` -- when the visitor submits a `<form>`.
|
||||||
- `focus` -- when the visitor focuses on an element, e.g. on an `<input>`.
|
- `focus` -- when the visitor focuses on an element, e.g. on an `<input>`.
|
||||||
|
|
||||||
**Keyboard events:**
|
|
||||||
- `keydown` and `keyup` -- when the visitor presses and then releases the button.
|
|
||||||
|
|
||||||
**Document events:**
|
**Document events:**
|
||||||
- `DOMContentLoaded` -- when the HTML is loaded and processed, DOM is fully built.
|
- `DOMContentLoaded` -- when the HTML is loaded and processed, DOM is fully built.
|
||||||
|
|
||||||
|
@ -87,8 +87,6 @@ If the handler is assigned using an HTML-attribute then the browser reads it, cr
|
||||||
|
|
||||||
So this way is actually the same as the previous one.
|
So this way is actually the same as the previous one.
|
||||||
|
|
||||||
**The handler is always in the DOM property: the HTML-attribute is just one of the ways to initialize it.**
|
|
||||||
|
|
||||||
These two code pieces work the same:
|
These two code pieces work the same:
|
||||||
|
|
||||||
1. Only HTML:
|
1. Only HTML:
|
||||||
|
@ -109,6 +107,8 @@ These two code pieces work the same:
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
In the first example, the HTML attribute is used to initialize the `button.onclick`, while in the second example -- the script, that's all the difference.
|
||||||
|
|
||||||
**As there's only one `onclick` property, we can't assign more than one event handler.**
|
**As there's only one `onclick` property, we can't assign more than one event handler.**
|
||||||
|
|
||||||
In the example below adding a handler with JavaScript overwrites the existing handler:
|
In the example below adding a handler with JavaScript overwrites the existing handler:
|
||||||
|
@ -124,16 +124,6 @@ In the example below adding a handler with JavaScript overwrites the existing ha
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
By the way, we can assign an existing function as a handler directly:
|
|
||||||
|
|
||||||
```js
|
|
||||||
function sayThanks() {
|
|
||||||
alert('Thanks!');
|
|
||||||
}
|
|
||||||
|
|
||||||
elem.onclick = sayThanks;
|
|
||||||
```
|
|
||||||
|
|
||||||
To remove a handler -- assign `elem.onclick = null`.
|
To remove a handler -- assign `elem.onclick = null`.
|
||||||
|
|
||||||
## Accessing the element: this
|
## Accessing the element: this
|
||||||
|
@ -150,7 +140,17 @@ In the code below `button` shows its contents using `this.innerHTML`:
|
||||||
|
|
||||||
If you're starting to work with events -- please note some subtleties.
|
If you're starting to work with events -- please note some subtleties.
|
||||||
|
|
||||||
**The function should be assigned as `sayThanks`, not `sayThanks()`.**
|
We can set an existing function as a handler:
|
||||||
|
|
||||||
|
```js
|
||||||
|
function sayThanks() {
|
||||||
|
alert('Thanks!');
|
||||||
|
}
|
||||||
|
|
||||||
|
elem.onclick = sayThanks;
|
||||||
|
```
|
||||||
|
|
||||||
|
But be careful: the function should be assigned as `sayThanks`, not `sayThanks()`.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// right
|
// right
|
||||||
|
@ -160,7 +160,7 @@ button.onclick = sayThanks;
|
||||||
button.onclick = sayThanks();
|
button.onclick = sayThanks();
|
||||||
```
|
```
|
||||||
|
|
||||||
If we add parentheses, `sayThanks()` -- is a function call. So the last line actually takes the *result* of the function execution, that is `undefined` (as the function returns nothing), and assigns it to `onclick`. That doesn't work.
|
If we add parentheses, then `sayThanks()` becomes is a function call. So the last line actually takes the *result* of the function execution, that is `undefined` (as the function returns nothing), and assigns it to `onclick`. That doesn't work.
|
||||||
|
|
||||||
...On the other hand, in the markup we do need the parentheses:
|
...On the other hand, in the markup we do need the parentheses:
|
||||||
|
|
||||||
|
@ -168,21 +168,17 @@ If we add parentheses, `sayThanks()` -- is a function call. So the last line ac
|
||||||
<input type="button" id="button" onclick="sayThanks()">
|
<input type="button" id="button" onclick="sayThanks()">
|
||||||
```
|
```
|
||||||
|
|
||||||
The difference is easy to explain. When the browser reads the attribute, it creates a handler function with *body from its content*: `sayThanks()`.
|
The difference is easy to explain. When the browser reads the attribute, it creates a handler function with body from the attribute content.
|
||||||
|
|
||||||
So the markup generates this property:
|
So the markup generates this property:
|
||||||
```js
|
```js
|
||||||
button.onclick = function() {
|
button.onclick = function() {
|
||||||
*!*
|
*!*
|
||||||
sayThanks(); // the attribute content
|
sayThanks(); // <-- the attribute content goes here
|
||||||
*/!*
|
*/!*
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
**Use functions, not strings.**
|
|
||||||
|
|
||||||
The assignment `elem.onclick = "alert(1)"` would work too. It works for compatibility reasons, but is strongly not recommended.
|
|
||||||
|
|
||||||
**Don't use `setAttribute` for handlers.**
|
**Don't use `setAttribute` for handlers.**
|
||||||
|
|
||||||
Such a call won't work:
|
Such a call won't work:
|
||||||
|
@ -201,7 +197,7 @@ Assign a handler to `elem.onclick`, not `elem.ONCLICK`, because DOM properties a
|
||||||
|
|
||||||
The fundamental problem of the aforementioned ways to assign handlers -- we can't assign multiple handlers to one event.
|
The fundamental problem of the aforementioned ways to assign handlers -- we can't assign multiple handlers to one event.
|
||||||
|
|
||||||
For instance, one part of our code wants to highlight a button on click, and another one wants to show a message.
|
Let's say, one part of our code wants to highlight a button on click, and another one wants to show a message on the same click.
|
||||||
|
|
||||||
We'd like to assign two event handlers for that. But a new DOM property will overwrite the existing one:
|
We'd like to assign two event handlers for that. But a new DOM property will overwrite the existing one:
|
||||||
|
|
||||||
|
@ -211,7 +207,7 @@ input.onclick = function() { alert(1); }
|
||||||
input.onclick = function() { alert(2); } // replaces the previous handler
|
input.onclick = function() { alert(2); } // replaces the previous handler
|
||||||
```
|
```
|
||||||
|
|
||||||
Web-standard developers understood that long ago and suggested an alternative way of managing handlers using special methods `addEventListener` and `removeEventListener`. They are free of such a problem.
|
Developers of web standards understood that long ago and suggested an alternative way of managing handlers using special methods `addEventListener` and `removeEventListener`. They are free of such a problem.
|
||||||
|
|
||||||
The syntax to add a handler:
|
The syntax to add a handler:
|
||||||
|
|
||||||
|
@ -229,8 +225,7 @@ element.addEventListener(event, handler, [options]);
|
||||||
: An additional optional object with properties:
|
: An additional optional object with properties:
|
||||||
- `once`: if `true`, then the listener is automatically removed after it triggers.
|
- `once`: if `true`, then the listener is automatically removed after it triggers.
|
||||||
- `capture`: the phase where to handle the event, to be covered later in the chapter <info:bubbling-and-capturing>. For historical reasons, `options` can also be `false/true`, that's the same as `{capture: false/true}`.
|
- `capture`: the phase where to handle the event, to be covered later in the chapter <info:bubbling-and-capturing>. For historical reasons, `options` can also be `false/true`, that's the same as `{capture: false/true}`.
|
||||||
- `passive`: if `true`, then the handler will not `preventDefault()`, we'll cover that later in <info:default-browser-action>.
|
- `passive`: if `true`, then the handler will not call `preventDefault()`, we'll explain that later in <info:default-browser-action>.
|
||||||
|
|
||||||
|
|
||||||
To remove the handler, use `removeEventListener`:
|
To remove the handler, use `removeEventListener`:
|
||||||
|
|
||||||
|
@ -249,7 +244,7 @@ elem.addEventListener( "click" , () => alert('Thanks!'));
|
||||||
elem.removeEventListener( "click", () => alert('Thanks!'));
|
elem.removeEventListener( "click", () => alert('Thanks!'));
|
||||||
```
|
```
|
||||||
|
|
||||||
The handler won't be removed, because `removeEventListener` gets another function -- with the same code, but that doesn't matter.
|
The handler won't be removed, because `removeEventListener` gets another function -- with the same code, but that doesn't matter, as it's a different function object.
|
||||||
|
|
||||||
Here's the right way:
|
Here's the right way:
|
||||||
|
|
||||||
|
@ -291,19 +286,21 @@ Multiple calls to `addEventListener` allow to add multiple handlers, like this:
|
||||||
As we can see in the example above, we can set handlers *both* using a DOM-property and `addEventListener`. But generally we use only one of these ways.
|
As we can see in the example above, we can set handlers *both* using a DOM-property and `addEventListener`. But generally we use only one of these ways.
|
||||||
|
|
||||||
````warn header="For some events, handlers only work with `addEventListener`"
|
````warn header="For some events, handlers only work with `addEventListener`"
|
||||||
There exist events that can't be assigned via a DOM-property. Must use `addEventListener`.
|
There exist events that can't be assigned via a DOM-property. Only with `addEventListener`.
|
||||||
|
|
||||||
For instance, the event `DOMContentLoaded`, that triggers when the document is loaded and DOM is built.
|
For instance, the `DOMContentLoaded` event, that triggers when the document is loaded and DOM is built.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
// will never run
|
||||||
document.onDOMContentLoaded = function() {
|
document.onDOMContentLoaded = function() {
|
||||||
alert("DOM built"); // will never run
|
alert("DOM built");
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
// this way it works
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
alert("DOM built"); // this way it works
|
alert("DOM built");
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
So `addEventListener` is more universal. Although, such events are an exception rather than the rule.
|
So `addEventListener` is more universal. Although, such events are an exception rather than the rule.
|
||||||
|
@ -311,11 +308,11 @@ So `addEventListener` is more universal. Although, such events are an exception
|
||||||
|
|
||||||
## Event object
|
## Event object
|
||||||
|
|
||||||
To properly handle an event we'd want to know more about what's happened. Not just a "click" or a "keypress", but what were the pointer coordinates? Which key was pressed? And so on.
|
To properly handle an event we'd want to know more about what's happened. Not just a "click" or a "keydown", but what were the pointer coordinates? Which key was pressed? And so on.
|
||||||
|
|
||||||
When an event happens, the browser creates an *event object*, puts details into it and passes it as an argument to the handler.
|
When an event happens, the browser creates an *event object*, puts details into it and passes it as an argument to the handler.
|
||||||
|
|
||||||
Here's an example of getting mouse coordinates from the event object:
|
Here's an example of getting pointer coordinates from the event object:
|
||||||
|
|
||||||
```html run
|
```html run
|
||||||
<input type="button" value="Click me" id="elem">
|
<input type="button" value="Click me" id="elem">
|
||||||
|
@ -338,11 +335,11 @@ Some properties of `event` object:
|
||||||
: Element that handled the event. That's exactly the same as `this`, unless the handler is an arrow function, or its `this` is bound to something else, then we can get the element from `event.currentTarget`.
|
: Element that handled the event. That's exactly the same as `this`, unless the handler is an arrow function, or its `this` is bound to something else, then we can get the element from `event.currentTarget`.
|
||||||
|
|
||||||
`event.clientX / event.clientY`
|
`event.clientX / event.clientY`
|
||||||
: Window-relative coordinates of the cursor, for mouse events.
|
: Window-relative coordinates of the cursor, for pointer events.
|
||||||
|
|
||||||
There are more properties. They depend on the event type, so we'll study them later when we come to different events in details.
|
There are more properties. Many of them depend on the event type: keyboard events have one set of properties, pointer events - another one, we'll study them later when we come to different events in details.
|
||||||
|
|
||||||
````smart header="The event object is also accessible from HTML"
|
````smart header="The event object is also available in HTML handlers"
|
||||||
If we assign a handler in HTML, we can also use the `event` object, like this:
|
If we assign a handler in HTML, we can also use the `event` object, like this:
|
||||||
|
|
||||||
```html autorun height=60
|
```html autorun height=60
|
||||||
|
@ -364,15 +361,17 @@ For instance:
|
||||||
<button id="elem">Click me</button>
|
<button id="elem">Click me</button>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
elem.addEventListener('click', {
|
let obj = {
|
||||||
handleEvent(event) {
|
handleEvent(event) {
|
||||||
alert(event.type + " at " + event.currentTarget);
|
alert(event.type + " at " + event.currentTarget);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
elem.addEventListener('click', obj);
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
As we can see, when `addEventListener` receives an object as the handler, it calls `object.handleEvent(event)` in case of an event.
|
As we can see, when `addEventListener` receives an object as the handler, it calls `obj.handleEvent(event)` in case of an event.
|
||||||
|
|
||||||
We could also use a class for that:
|
We could also use a class for that:
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue