Add elements, rename tags, reorder with drag-and-drop, duplicate and delete. Double-click text to edit inline.
这种直观的DOM操作界面将复杂的HTML结构编辑简化为可视化操作,这可能显著降低前端开发的认知负担。然而,这也引发了关于AI如何理解和处理这些结构变更的深层次问题。
Add elements, rename tags, reorder with drag-and-drop, duplicate and delete. Double-click text to edit inline.
这种直观的DOM操作界面将复杂的HTML结构编辑简化为可视化操作,这可能显著降低前端开发的认知负担。然而,这也引发了关于AI如何理解和处理这些结构变更的深层次问题。
DOM OJ Administrator bira jedan od raspoloživih Brojeva blagajne koju otvara OL koji će taj dan raditi na definisanoj blagajni ukoliko je različit od definisanog OL za odabrani broj blagajne.
Blagajna se ne definise sama za sebe kao entitet vec ukljucuje OL, a opet mozes da izaberes i nekog drugog OL.
Zasto jednostavno nemamo nezavisnu listu blagajni i OL i da uvek mozes da izaberes bilo kog OL iz liste kad otvarash blagajnu, i da imash opciju da stavish jednog OL kao default tako da sutradan se on prvi postavi...
You'll only need the trailing * when there is another <Routes> somewhere in that route's descendant tree. In that case, the descendant <Routes> will match on the portion of the pathname that remains (see the previous example for what this looks like in practice).
Something to do with routes in index.js and routes in app.js
```svelte
<script> let wrapper; </script> <div bind:this="{wrapper}"></div>```
Security considerations When inserting HTML into a page by using insertAdjacentHTML(), be careful not to use user input that hasn't been escaped.
```html <select id="position"> <br /> <option>beforebegin</option>
<option>afterbegin</option> <option>beforeend</option> <option>afterend</option></select>
<button id="insert">Insert HTML</button> <button id="reset">Reset</button>
Some text, with a code-formatted element inside it.
```
```js const insert = document.querySelector("#insert"); insert.addEventListener("click", () => { const subject = document.querySelector("#subject"); const positionSelect = document.querySelector("#position"); subject.insertAdjacentHTML( positionSelect.value, "inserted text" ); });
const reset = document.querySelector("#reset"); reset.addEventListener("click", () => { document.location.reload(); });
```
Use insertAdjacentHTML(). It works with all current browsers, even with IE11.
js
var mylist = document.getElementById('mylist');
mylist.insertAdjacentHTML('beforeend', '<li>third</li>');
```html
```
HTML 5 introduced the <template> element which can be used for this purpose (as now described in the WhatWG spec and MDN docs). A <template> element is used to declare fragments of HTML that can be utilized in scripts. The element is represented in the DOM as a HTMLTemplateElement which has a .content property of DocumentFragment type, to provide access to the template's contents. This means that you can convert an HTML string to DOM elements by setting the innerHTML of a <template> element, then reaching into the template's .content property.
```js /* * @param {String} HTML representing a single element * @return {Element} / function htmlToElement(html) { var template = document.createElement('template'); html = html.trim(); // Never return a text node of whitespace as the result template.innerHTML = html; return template.content.firstChild; }
var td = htmlToElement('<td>foo</td>'), div = htmlToElement('<div><span>nested</span> <span>stuff</span></div>');
/* * @param {String} HTML representing any number of sibling elements * @return {NodeList} / function htmlToElements(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.childNodes; }
var rows = htmlToElements('<tr><td>foo</td></tr><tr><td>bar</td></tr>'); ```
```js function makeDocument() { let frame = document.getElementById("theFrame");
let doc = document.implementation.createHTMLDocument("New Document"); let p = doc.createElement("p"); p.textContent = "This is a new paragraph.";
try { doc.body.appendChild(p); } catch (e) { console.log(e); }
// Copy the new HTML document into the frame
let destDocument = frame.contentDocument; let srcNode = doc.documentElement; let newNode = destDocument.importNode(srcNode, true);
destDocument.replaceChild(newNode, destDocument.documentElement); } ```
document.implementation.createHTMLDocument() which can stream dynamic HTML content directly into the page DOM
CSS-generated content is not included in the DOM. Because of this, it will not be represented in the accessibility tree and certain assistive technology/browser combinations will not announce it. If the content conveys information that is critical to understanding the page's purpose, it is better to include it in the main document.
Warning: Microdata were implemented in some browsers for a long time. Nowadays, they have been abandoned and removed from all browsers and are therefore deprecated. You can't use them anymore and this document is kept as information only.
js
var biography = document.getItems("http://example.org/biography")[0];
alert('Hi there ' + biography.properties['name'][0].textContent + '!');
The microdata becomes even more useful when scripts can use it to expose information to the user, for example offering it in a form that can be used by other applications.The document.getItems(typeNames) method provides access to the top-level microdata items. It returns a NodeList containing the items with the specified types, or all types if no argument is specified.Each item is represented in the DOM by the element on which the relevant itemscope attribute is found. These elements have their element.itemScope IDL attribute set to true.The type of items can be obtained using the element.itemType IDL attribute on the element with the itemscope attribute.
```js // This sample shows how the getItems() method can be used to obtain a list // of all the top-level microdata items of one type given in the document:
var cats = document.getItems("http://example.com/feline"); ```
```js // This sample gets the first item of type "http://example.net/user" // and then pops up an alert using the "name" property from that item.
var user = document.getItems('http://example.net/user')[0]; alert('Hello ' + user.properties['name'][0].content + '!'); ```
```js // The HTMLPropertiesCollection object, when indexed by name in this way, // actually returns a PropertyNodeList object with all the matching properties. // The PropertyNodeList object can be used to obtain all the values at once // using its values attribute, which returns an array of all the values.
var cat = document.getItems('http://example.org/animals#cat')[0]; var colors = cat.properties['http://example.com/color'].values; var result; if (colors.length == 0) { result = 'Color unknown.'; } else if (colors.length == 1) { result = 'Color: ' + colors[0]; } else { result = 'Colors:'; for (var i = 0; i < colors.length; i += 1) result += ' ' + colors[i]; } ```
TL;DR; A custom renderer for ReactJS that uses Web Workers to run the expensive Virtual DOM diffing calculations
Tl;Dr; ReactJS is faster when Virtual DOM reconciliations are done on a Web Worker thread.
如何看待 snabbdom 的作者开发的前端框架 Turbine 抛弃了虚拟 DOM?
not when it is served as text/html
occurs when the page is served as application/xhtml+xml
interpreted as normal white space for rendering
This behavior is incorrect because line breaks in text from HTML source are interpreted as normal white space for rendering.
```html
<html> <head> <br /> <script> function noMondays() { var tw = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false); var textNode = tw.nextNode(); while (textNode) { if (textNode.wholeText.match('Monday') || textNode.parentNode.getAttribute('id') == 'Monday') { textNode.parentNode.removeChild(textNode); } textNode = tw.nextNode(); } } function refresh() { window.location.reload( false ); // Reload our page. } </script>
</head> <body>
Monday, Joe bought a turkey.
Tuesday, Bill bought a pound of nails.
<div>Chuck called in sick Monday.</div>CALL supplier today!
Wednesday's delivery was delayed.
<button onclick="refresh()">Reload</button> <button onclick="noMondays()">Lose Mondays</button> </body></html> ```
DOMPurify - a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG
```js import DOMPurify from 'dompurify'
const App = () => {
const data = lorem <b onmouseover="alert('mouseover');">ipsum</b>
const sanitizedData = () => ({
__html: DOMPurify.sanitize(data)
})
return ( <div dangerouslySetInnerHTML={sanitizedData()} /> ); }
export default App; ```
Differences from innerHTML Element.innerHTML returns HTML, as its name indicates. Sometimes people use innerHTML to retrieve or write text inside an element, but textContent has better performance because its value is not parsed as HTML. Moreover, using textContent can prevent XSS attacks.
Differences from innerText Don't get confused by the differences between Node.textContent and HTMLElement.innerText. Although the names seem similar, there are important differences: textContent gets the content of all elements, including <script> and <style> elements. In contrast, innerText only shows "human-readable" elements. textContent returns every element in the node. In contrast, innerText is aware of styling and won't return the text of "hidden" elements. Moreover, since innerText takes CSS styles into account, reading the value of innerText triggers a reflow to ensure up-to-date computed styles. (Reflows can be computationally expensive, and thus should be avoided when possible.) Both textContent and innerText remove child nodes when altered, but altering innerText in Internet Explorer (version 11 and below) also permanently destroys all descendant text nodes. It is impossible to insert the nodes again into any other element or into the same element after doing so.
```js document.createAnnotation()
document.getAnnotations(nodes)
document.removeAnnotation(annotation) ```
```js Annotation#addTarget(target)
Annotation#addBody(body) ```
The HTMLLabelElement.htmlFor property reflects the value of the for content property.
function getDomPath(el) {
var stack = [];
while ( el.parentNode != null ) {
console.log(el.nodeName);
var sibCount = 0;
var sibIndex = 0;
for ( var i = 0; i < el.parentNode.childNodes.length; i++ ) {
var sib = el.parentNode.childNodes[i];
if ( sib.nodeName == el.nodeName ) {
if ( sib === el ) {
sibIndex = sibCount;
}
sibCount++;
}
}
if ( el.hasAttribute('id') && el.id != '' ) {
stack.unshift(el.nodeName.toLowerCase() + '#' + el.id);
} else if ( sibCount > 1 ) {
stack.unshift(el.nodeName.toLowerCase() + ':eq(' + sibIndex + ')');
} else {
stack.unshift(el.nodeName.toLowerCase());
}
el = el.parentNode;
}
return stack.slice(1); // removes the html element
}
//Usage:
var path = getDomPath(document.getElementById('button'));
console.log(path.join(' > '));
“When I give food to the poor, they call me a saint. When I ask why the poor have no food, they call me a communist.” ― Dom Helder Camara, Dom Helder Camara: Essential Writings
CSS-generated content is not included in the DOM. Because of this, it will not be represented in the accessibility tree and certain assistive technology/browser combinations will not announce it. If the content conveys information that is critical to understanding the page's purpose, it is better to include it in the main document.
The :empty selector refers only to child nodes, not input values. [value=""] does work; but only for the initial state. This is because a node's value attribute (that CSS sees), is not the same as the node's value property (Changed by the user or DOM javascript, and submitted as form data).
[...document.querySelectorAll("*")].filter(e => e.childNodes && [...e.childNodes].find(n => n.nodeValue?.match("❤")))
function contains(selector, text) { var elements = document.querySelectorAll(selector); return [].filter.call(elements, function(element){ return RegExp(text).test(element.textContent); }); }
Array.from(document.querySelectorAll('div')) .find(el => el.textContent === 'SomeText, text continues.');
хорошая библиотека для парсинга и автоматизации тестирования "вёрстки с js"
This is not an issue related to using a virtual DOM. Plenty of non VDOM libraries have solved this. Imba and Solid come to mind.
I'm looking at https://html.spec.whatwg.org/#attributes-3 right now, and it seems that there are a few others that ought to be boolean but are not currently in this list: allowpaymentrequest, formnovalidate, hidden (is on the original list in the master branch), itemscope, nomodule, and playsinline.
I have a feature spec to test the Javascript behavior of the blur event, sadly Capybara's native DSL doesn't seem to support it yet.
hyperscript is a perfectly good alternative and uses the same interface as matt esch's virtual-dom
A JavaScript DOM model supporting element creation, diff computation and patch operations for efficient re-rendering
virtual-dom exposes a set of objects designed for representing DOM nodes. A "Document Object Model Model" might seem like a strange term, but it is exactly that. It's a native JavaScript tree structure that represents a native DOM node tree.
virtual-dom is a collection of modules designed to provide a declarative way of representing the DOM for your app. So instead of updating the DOM when your application state changes, you simply create a virtual tree or VTree, which looks like the DOM state that you want. virtual-dom will then figure out how to make the DOM look like this efficiently without recreating all of the DOM nodes.
Node doesn't have a DOM available. So in order to render HTML we use string concatenation instead. This has the fun benefit of being quite efficient, which in turn means it's great for server rendering!
tagged template string virtual dom builder
The Shadow DOM is a browser technology designed primarily for scoping variables and CSS in web components. The virtual DOM is a concept implemented by libraries in JavaScript on top of browser APIs.
Since “virtual DOM” is more of a pattern than a specific technology, people sometimes say it to mean different things. In React world, the term “virtual DOM” is usually associated with React elements since they are the objects representing the user interface
The virtual DOM (VDOM) is a programming concept where an ideal, or “virtual”, representation of a UI is kept in memory and synced with the “real” DOM by a library such as ReactDOM.
new_event = new old_event.constructor(old_event.type, old_event)
Many DOM elements can be set up to accept (or "listen" for) these events, and execute code in response to process (or "handle") them. Event-handlers are usually connected (or "attached") to various HTML elements (such as <button>, <div>, <span>, etc.)
The Event interface represents an event which takes place in the DOM.
DOM Events are sent to notify code of interesting things that have taken place.
The Web platform provides several ways to be notified of DOM events.
isTrusted is not part of React, it's a native browser event property. You cannot programmatically create an event and have isTrusted be true.
This article demonstrates how to create and dispatch DOM events. Such events are commonly called synthetic events, as opposed to the events fired by the browser itself.
Unlike DOM events, component events don't bubble. If you want to listen to an event on some deeply nested component, the intermediate components must forward
Allow creating custom components with the same abilities as native dom. By all means keep the same level of encapsulation, don't push class on components, but allow a component to mark the class property or another as a CSS Class property, in which case you could pass it through the same transformation that native elements go through
So a "Svelte" way to do document.createElement.
Svelte currently has no opinion as to what you store in an exported class prop of a component. It will not necessarily be used a class attribute.
React creates a virtual DOM. When state changes in a component it firstly runs a “diffing” algorithm, which identifies what has changed in the virtual DOM. The second step is reconciliation, where it updates the DOM with the results of diff.The HTML DOM is always tree-structured — which is allowed by the structure of HTML document. The DOM trees are huge nowadays because of large apps. Since we are more and more pushed towards dynamic web apps (Single Page Applications — SPAs), we need to modify the DOM tree incessantly and a lot. And this is a real performance and development pain.The Virtual DOM is an abstraction of the HTML DOM. It is lightweight and detached from the browser-specific implementation details. It is not invented by React but it uses it and provides it for free. ReactElements lives in the virtual DOM. They make the basic nodes here. Once we defined the elements, ReactElements can be render into the "real" DOM.Whenever a ReactComponent is changing the state, diff algorithm in React runs and identifies what has changed. And then it updates the DOM with the results of diff. The point is - it’s done faster than it would be in the regular DOM.
React creates a virtual DOM and every time the state of a component changes, it runs a diff algorithm on the virtual DOM. If something needs to be changed, it changes only this part in the HTML DOM. This is faster than the default of updating the entire HTML DOM any time something changes.
One of the most important concepts in AMP’s design is its focus on reducing the amount of DOM reflow required to render its web pages. To reduce DOM reflow, AMP includes a layout system to ensure the layout of the page is known as early as possible in the lifecycle of downloading and rendering the page.
Why was the container type inferred? Because we did not specify a height attribute for the amp-img tag. In HTML, reflow can be reduced by always specifying a fixed width and height for elements on a page. In AMP, you need to define the width and height for amp-img elements so that AMP can pre-determine the aspect ratio of the element.
Applications built with just React usually have a single root DOM node
The Document Object Model (DOM) is a programming interface for HTML and XML documents
it's an API
(DOM) is a cross-platform, language-independent convention for representing and interacting with objects in HTML, XHTML and XML documents. Objects in the DOM tree may be addressed and manipulated by using methods on the objects
the umbrella term "JavaScript" as understood in a web browser context contains several very different elements. One of them is the core language (ECMAScript), another is the collection of the Web APIs, including the DOM (Document Object Model)
If you used browser JS DOM APIs (that have nothing to do with React itself), you know they don’t automatically update attributes
Please note: we need to hide the ball before the call (*). Otherwise we’ll usually have a ball on these coordinates, as it’s the top element under the pointer: elemBelow=ball.
but the method is supposed to return the most nested one. why did we need to hide the ball? cause its the most nested one in the DOM structure? didn't get it...
What’s the first idea? Probably to put onmouseover/mouseup handlers on potential droppables and detect when the mouse pointer appears over them. And then we know that we are dragging/dropping on that element. But that doesn’t work. The problem is that, while we’re dragging, the draggable element is always above other elements. And mouse events only happen on the top element, not on those below it.
key point!
Another important aspect – we track mousemove on document, not on ball. From the first sight it may seem that the mouse is always over the ball, and we can put mousemove on it. But as we remember, mousemove triggers often, but not for every pixel. So after swift move the cursor can jump from the ball somewhere in the middle of document (or even outside of the window). So we should listen on document to catch it.
if not, some mouseMove events we think are triggered on the ball will actually be triggered on other elements - hence the need to track those events on document
Children are ignored.
key point! notice the demo...
According to the browser logic, the mouse cursor may be only over a single element at any time – the most nested one (and top by z-index).
key point!
We should keep that possibility in mind when using event.relatedTarget in our code. If we access event.relatedTarget.tagName, then there will be an error.
key point!
A text selection is the default browser action on mousedown event. So the alternative solution would be to handle mousedown and prevent it, like this:
an alternative to preventing the selection of text on double click (see "user-select" CSS usage above)
We should use them instead of new Event if we want to create such events. For instance, new MouseEvent("click"). The right constructor allows to specify standard properties for that type of event.
important, if you wish/need to generate custom events
An alternative solution would be to check in the document handler if the default action was prevented? If it is so, then the event was handled, and we don’t need to react on it.
instead of stopPropagation, we can preventDefault() in the child and check if it was prevented in a parent event listener
So, without scrollbar the content width would be 300px, but if the scrollbar is 16px wide (the width may vary between devices and browsers) then only 300 - 16 = 284px remains, and we should take it into account. That’s why examples from this chapter assume that there’s a scrollbar. If there’s no scrollbar, then things are just a bit simpler.
in other words, "width" contains the border, scrollbar and padding
So nowadays getComputedStyle actually returns the resolved value of the property.
important
elem.classList.toggle("class") – if the class exists, then removes it, otherwise adds it.
cool!
The call to document.write only works while the page is loading.
key point! don't use this method. create elements instead and embed them...
node.append(...nodes or strings) – append nodes or strings at the end of node, node.prepend(...nodes or strings) – insert nodes or strings into the beginning of node, node.before(...nodes or strings) –- insert nodes or strings before the node, node.after(...nodes or strings) –- insert nodes or strings after the node, node.replaceWith(...nodes or strings) –- replaces node with the given nodes or strings.
note: the string inserted is treated as string and is 'escaped'. for methods that allow inserting string as html, see below...
Quite rarely, even if a DOM property type is a string, it may differ from the attribute. For instance, the href DOM property is always a full URL, even if the attribute contains a relative URL or just a #hash.
so not only the type is different between the attribute and the DOM property, but also their content might differ.
There are other examples. The style attribute is a string, but the style property is an object:
interesting!
HTML attributes have the following features: Their name is case-insensitive (id is same as ID). Their values are always strings.
important
So when an element has id or another standard attribute, the corresponding property gets created. But that doesn’t happen if the attribute is non-standard.
key point
In most cases, we expect the text from a user, and want to treat it as text. We don’t want unexpected HTML in our site. An assignment to textContent does exactly that.
key point - sanitation at courtesy of the browser itself
If innerHTML inserts a <script> tag into the document – it doesn’t execute. It becomes a part of HTML, just as a script that has already run.
key point!
The innerHTML property allows to get the HTML inside the element as a string. We can also modify it. So it’s one of most powerful ways to change the page.
key point. compare this with innerText
In the example below, there are two scripts. The first one creates a reference to the collection of <div>. As of now, its length is 1. The second scripts runs after the browser meets one more <div>, so its length is 2
now that's confusing! see line below on contrasting with querySelector()
elem.querySelectorAll(css) returns all elements inside elem matching the given CSS selector.
notice that it returns all elements inside 'elem', meaning it works on a subset of the document, not its entirety. Much more effective, wise and useful to limit your searches like this.
The behavior is described in the specification, but it is supported mainly for compatibility. The browser tries to help us by mixing namespaces of JS and DOM. Good for very simple scripts, but there may be name conflicts. Also, when we look in JS and don’t have HTML in view, it’s not obvious where the variable comes from. If we declare a variable with the same name, it takes precedence:
in other words - don't use JS variables for elements on the page with specific ID
Please note an interesting detail here. If we run the example above, the last element shown is <script>. In fact, the document has more stuff below, but at the moment of the script execution the browser did not read it yet, so the script doesn’t see it.
because the last thing available to the browser when the script run is the script code itself... . This is a key point and a reason why its usually recommended to add all script tags at the end of the body - so the whole DOM will be loaded before the scripts run
elements
that's the key point here...
In the DOM world null means “doesn’t exist” In the DOM, the null value means “doesn’t exist” or “no such node”.
key point!
comments – sometimes we can put the information there, it won’t be shown, but JS can read it from the DOM.
key point - i wonder if Angular uses this capability as I do know that it introduces some comments into the DOM
there’s a rule – if something’s in HTML, then it also must be in the DOM tree
including HTML comments
keydown – pressing a key may lead to adding a character into a field, or other actions.
interesting example on a default action
Menu items are links <a>, not buttons. There are several benefits, for instance: Many people like to use “right click” – “open in a new window”. If we use <button> or <span>, that doesn’t work. Search engines follow <a href="..."> links while indexing.
key point on why use 'a' tag instead of buttons for navigation purposes
If we handle an event in JavaScript, often we don’t want browser actions. Fortunately, it can be prevented.
like for example if a link is used in a SPA. We don't want page reload... so we need to tell the browser not to handle the event.
One more example. A click on an element with the attribute data-toggle-id will show/hide the element with the given id:
now that's a nice useful example. In many cases you have a page in which several items are concealable in this fashion. cool!
When we assign an event handler to the document object, we should always use addEventListener, not document.onclick, because the latter will cause conflicts: new handlers overwrite old ones.
key point (and a logical one...)
Note that while formally there are 3 phases, the 2nd phase (“target phase”: the event reached the element) is not handled separately: handlers on both capturing and bubbling phases trigger at that phase.
the example below is really useful in understanding this
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 event.currentTarget becomes useful.
key point, as using arrow functions is quite common these days, to have lexical binding of this, without confusion
Please note – if we don’t store the function in a variable, then we can’t remove it.
key point
The document object gives access to the page content
note: page content, not other functional areas of the browser. Read on to see other parts of the browser.
An HTML element is an individual component of an HTML document or web page, once this has been parsed into the Document Object Model.
Know the Document Object Model.
React is fast, thanks to the VirtualDOM. Using a diffing algorithm, the browser DOM nodes are manipulated only when there is a state change. This algorithm is computationally expensive. Using webworkers to perform the calculations can make React even faster.
var el; var i = 0; var fragment = document.createDocumentFragment(); while (i < 200) { el = document.createElement('li'); el.innerText = 'This is my list item number ' + i; fragment.appendChild(el); i++; } div.appendChild(fragment);
The fastest (): while (node.lastChild) { node.removeChild(node.lastChild); } Alternatives (slower): while (node.firstChild) { node.removeChild(node.firstChild); } while (node.hasChildNodes()) { node.removeChild(node.lastChild); }
If bp is before the range’s start, or if range’s root is not equal to node’s root, set range’s start to bp.
You will also have to tell AngularJS what part of the directive's HTML template that is to contain the transcluded HTML
cf. The concept of 'slots' in the Shadow DOM spec.