:hover
does not match, because the position of the tooltip changes depending on the mouse cursor. Event delegation is also not suitable - it is too expensive to listen to mouseover
and mouseleave
for all elements on the page. This is where live extensions come into play. DOM.extend("[title]", { constructor: function() { var tooltip = DOM.create("span.custom-title"); // textContent // title tooltip.set("textContent", this.get("title")).hide(); this // tooltip .set("title", null) // .data("tooltip", tooltip) // .on("mouseenter", this.onMouseEnter, ["clientX", "clientY"]) .on("mouseleave", this.onMouseLeave) // DOM .append(tooltip); }, onMouseEnter: function(x, y) { this.data("tooltip").style({left: x, top: y}).show(); }, onMouseLeave: function() { this.data("tooltip").hide(); } });
.custom-title
selector in CSS: .custom-title { position: fixed; border: 1px solid #faebcc; background: #faf8f0; }
title
attribute are added to the page. They will be picked up by the extension without calling any initializing function .Decorators, unlike other sections of Web Components, do not yet have a specification.
setInterval
and setTimeout
. It was a cool thing, but now ... something like a bad practice. Native animations will always be smoother: they are usually faster, require less energy and simply do not appear in browsers that do not support them.animate
method in better-dom: only show
, hide
and toggle
. To capture the state of a hidden item in the CSS library uses the standardized attribute aria-hidden
. .custom-title { position: fixed; border: 1px solid #faebcc; background: #faf8f0; /* */ opacity: 1; -webkit-transition: opacity 0.5s; transition: opacity 0.5s; } .custom-title[aria-hidden=true] { opacity: 0; }
show
and hide
attribute, aria-hidden
changes its value to false
or true
. This is enough to show the animation means CSS. body.append("<ul><li class='list-item'></li><li class='list-item'></li><li class='list-item'></li></ul>");
body.append("ul>li.list-item*3");
:lang
and :before
. Take a look at the code below: [data-i18n="hello"]:before { content: "Hello Maksim!"; } [data-i18n="hello"]:lang(ru):before { content: " !"; }
content
property changes according to the current language, which is determined by the value of the lang
attribute for the html
element. Using the data-i18n
attribute, we can use a more general entry: [data-i18n]:before { content: attr(data-i18n); } [data-i18n="Hello Maksim!"]:lang(ru):before { content: " !"; }
i18n
and DOM.importStrings
. The first is used to update the data-i18n
attribute with the corresponding value, and the second locates strings for a particular language. label.i18n("Hello Maksim!"); // label "Hello Maksim!" DOM.importStrings("ru", "Hello Maksim!", " !"); // "ru", label " !" label.set("lang", "ru"); // label " !"
${param}
variables to the key string: label.i18n("Hello ${user}!", {user: "Maksim"}); // label "Hello Maksim!"
<a href="/chemerisuk/better-dom" id="foo" data-test="test">better-dom</a>
var link = document.getElementById("foo"); link.href; // => "https://github.com/chemerisuk/better-dom" link.getAttribute("href"); // => "/chemerisuk/better-dom" link["data-test"]; // => undefined link.getAttribute("data-test"); // => "test" link.href = "abc"; link.href; // => "https://github.com/abc" link.getAttribute("href"); // => "abc"
var link = DOM.find("#foo"); link.get("href"); // => "https://github.com/chemerisuk/better-dom" link.set("href", "abc"); link.get("href"); // => "https://github.com/abc" link.get("data-attr"); // => "test"
checked
, selected
, etc.) you can simply use true
or false
. Changing these properties on the element updates the corresponding attribute (native behavior). var button = document.getElementById("foo"); button.addEventListener("click", function(e) { handleButtonClick(e.button); }, false);
var button = DOM.find("#foo"); button.on("click", handleButtonClick, ["button"]);
["target", "defaultPrevented"]
, so there is no need to add the last argument to read these properties: button.on("click", function(target, canceled) { // });
on
and off
methods. button._handleButtonClick = function() { alert("click!"); }; button.on("click", "_handleButtonClick"); button.fire("click"); // "clicked" button._handleButtonClick = null; button.fire("click"); //
click()
, focus()
, submit()
etc., which are present in the standard and have different behavior in browsers. The only way to call them is to use the fire
method, which executes the default behavior when none of the handlers returned false
: link.fire("click"); // link.on("click", function() { return false; }); link.fire("click"); //
map
, filter
, some
, etc. They allow you to conduct operations on collections in a standardized form. As a result, there are today projects like Underscore or Lo-Dash , which allow you to use these methods in older browsers.each
(differs from forEach
in that it returns this
instead of undefined
)some
every
map
filter
reduce[Right]
var urls, activeLi, linkText; urls = menu.findAll("a").map(function(el) { return el.get("href"); }); activeLi = menu.children().filter(function(el) { return el.hasClass("active"); }); linkText = menu.children().reduce(function(memo, el) { return memo || el.hasClass("active") && el.find("a").get() }, false);
$
return false
find
and findAll
$
(dollar) is “magic”. The name consisting of only one character is not very clear; the function looks like an operator built into the language. That is why inexperienced developers simply call it wherever it is needed.$
is a rather complicated function . Its frequent execution, especially inside events such as mousemove
or scroll
, can be the cause of poor UI responsiveness.$
. This is because the library syntax contributes to this coding style. $("a"); // => , “a” $("<a>"); // => <a> jQuery
find[All]
and DOM.create
. The find[All]
methods are used to search for elements by a CSS selector. DOM.create
creates new elements in memory. Function names clearly state what these functions do. var links = $("a"); links[0].on("click", function() { ... }); // ! $(links[0]).on("click", function() { ... }); //
$()
within an iteration function. Therefore, the developer must always remember with what object he works: native or a wrapper, despite the fact that the library is used to work with the DOM.legacy
method. var foo = DOM.find("#foo"); foo.legacy(function(node) { // Hammer swipe Hammer(node).on("swipe", function(e) { // swipe }); });
return false
in event listeners. In accordance with W3C standards, this value should, in most cases, override the default behavior. In jQuery, return false
additionally stops event delegation !stopPropagation()
call itself can create compatibility problems, since he breaks the possibility of other listeners to do their work in the occurrence of such an eventreturn false
inside an event handler only causes preventDefault()
, as expected.querySelector
and querySelectorAll
. The difference between them is that the first one stops the search after the first match.find
method that uses querySelectorAll
in general. To date, there is no method here that would use querySelector
to find only the first matching element.find
and findAll
. They allow you to use querySelector
optimization above. To estimate the potential gain, I made a sample by the number of entries in the source code of the last commercial project:find
- 103 matches in 11 filesfindAll
- 14 matches in 4 filesfind
method is much more popular. This means that querySelector
optimization takes place in most cases, so it can give a tangible gain in code performance on the client.Source: https://habr.com/ru/post/209140/
All Articles