提前感谢您的帮助!我正在尝试做一些递归范围标记“replaceWith”操作,用div和3个子跨度替换span。我的子对象(包含要替换的跨度)有一个巨大的问题,当第一个跨度被替换时会以某种方式更新(导致我的对象每次增长2),所以我想我会尝试制作对象恒定然后冷冻或密封它。我不确定这是否是正确的方法,但我不是一个足够好的javascript程序员知道。无论如何,我以这种方式得到我的跨度对象:
let el = document.getElementById("container");
let nodes = el.children[0];
Object.seal(nodes);//THIS SEALS/FREEZES JUST FINE
let spans = {};//TRIED WITH AND W/O THIS JUST TO MAKE SURE THE OBJECT WAS CREATED
const spans = nodes.children;
console.log('type of spans: '+typeof spans);//RETURNS object
console.log('spans length: '+spans.length);//RETURNS spans length: 3
console.log('spans: '+JSON.stringify(spans));//RETURNS spans: {"0":{},"1":{},"2":{}}
Object.seal(spans);///RETURNS Uncaught TypeError: Cannot Seal
HTML很简单:
<body>
<button id="fractalize">Fractalize</button>
<br/>
<br/>
<div id="container">
<div class="sierpinski">
<span></span>
<span></span>
<span></span>
</div>
</div>
</body>
跨越作为对象返回,除了它之外的所有内容在使用Object.freeze或Object.seal时都会失败!我需要知道是否有人可以告诉我我做错了什么..跨度对象看起来与节点对象没有任何不同,节点对象冻结/密封就好了。 如果我可以将这些对象冻结,那么我的计划是对替换进行以下操作:
for( let key in spans ) {
if( spans.hasOwnProperty(key) ) {
console.log(key + " -> " + JSON.stringify(spans[key]));
let nDiv = document.createElement("div");
nDiv.className="sierpinski";
nDiv.innerHTML="<span></span><span></span><span></span>";
spans[key].replaceWith(nDiv.cloneNode(true));
nDiv.remove();
}
}
感谢您的任何见解!
修改 为了洞察力,这就是我想要的;
<body>
<button id="fractalize">Fractalize</button>
<br/>
<br/>
<div id="container">
<div class="sierpinski">
<div class="sierpinski">
<div class="sierpinski">
<span></span>
<span></span>
<span></span>
</div>
<div class="sierpinski">
<span></span>
<span></span>
<span></span>
</div>
<div class="sierpinski">
<span></span>
<span></span>
<span></span>
</div>
</div>
<div class="sierpinski">
<div class="sierpinski">
<span></span>
<span></span>
<span></span>
</div>
<div class="sierpinski">
<span></span>
<span></span>
<span></span>
</div>
<div class="sierpinski">
<span></span>
<span></span>
<span></span>
</div>
</div>
<div class="sierpinski">
<div class="sierpinski">
<span></span>
<span></span>
<span></span>
</div>
<div class="sierpinski">
<span></span>
<span></span>
<span></span>
</div>
<div class="sierpinski">
<span></span>
<span></span>
<span></span>
</div>
</div>
</div>
</div>
</body>
这就是我目前所得到的;
<body>
<button id="fractalize">Fractalize</button>
<br/>
<br/>
<div id="container">
<div class="sierpinski">
<div class="sierpinski">
<span></span>
<div class="sierpinski">
<span></span>
<div class="sierpinski">
<span></span>
<div class="sierpinski">
<span></span>
<span></span>
<span></span>
</div>
<span></span>
</div>
<span></span>
</div>
<span></span>
</div>
<span></span>
<span></span>
</div>
</div>
</body>
答案 0 :(得分:1)
所以我是否添加/删除类或其他东西,以便代码迭代具有某种锚点?我只是不明白我如何声明一个等于某些子元素的变量,而不是永久的。如何在不重新定义变量的情况下改变DOM中的内容会改变变量中的内容??
使用正确的方法收集元素/节点*对DOM操作很重要。旧方法.children
,.getElementsByTagName()
,.getElementsByName()
,.getElementsByClassName()
等返回DOM对象的 Live Collection 。这意味着此集合中的任何对象(即元素,即<div>
,<span>
,即非spans={}
)(又名 HTMLCollection ,又名 NodeList < / em>)被修改或删除,或者如果添加了新对象, 整个集合将立即更改 。这使得许多递归方式变得不可能和随机。
出于某种原因,MDN将实时集合称为HTMLCollection或NodeList,但提到如果使用诸如.querySelectorAll()
之类的方法,则NodeList不是“实时”。为什么它不被称为“静态”集合,将其与不同的行为区分开来,尤其是如果实时集合更像是您遇到的常见问题的来源。
<小时/>
Object.seal(nodes);//THIS SEALS/FREEZES JUST FINE
let spans = {};//TRIED WITH AND W/O THIS JUST TO MAKE SURE THE OBJECT WAS CREATED
const spans = nodes.children;
console.log('type of spans: '+typeof spans);//RETURNS object
console.log('spans length: '+spans.length);//RETURNS spans length: 3
console.log('spans: '+JSON.stringify(spans));//RETURNS spans: {"0":{},"1":{},"2":{}}
Object.seal(spans);///RETURNS Uncaught TypeError: Cannot Seal
spans
不是<span></span><span></span><span></span>
,spans
是{"0":{},"1":{},"2":{}}
。前者是 HTMLCollection (或 NodeList ),后者是 Object Literal ,苹果和橘子。 Object.seal()
是原型属性的方法。此外,请使用var
,直到您获得更多经验。如果您不注意范围,let
和const
可能会轻易削弱您的代码。
<template>
标记<template>
个组件for
循环let
注意:布局保持接近OP,但以下情况除外:
使用<template>
目标元素隐藏在<template>
没有打算创建4个嵌套级别,其中3个应该足够
不会尝试使用Sierpinski三角形,因此更改了类来代表书籍
详情在演示
中发表
// Refer to HTMLFormControlsCollection
var UI = document.forms.ui.elements;
// Register click event to button
UI.btn.addEventListener('click', generate);
function generate() {
// Reference to #main
var main = document.getElementById('main');
// Refer to Template Tag
var library = document.querySelector('.library');
var lib = library.content.cloneNode(true);
/* Refer to HTMLFormControlsCollection
|| The user data is collected in a live collection
|| Note that these values are outside of the loops
*/
var ct = UI.ct.value;
var bk = UI.bk.value;
var pg = UI.pg.value;
/* let declaration limits it's value to the block.
|| var limit's its value to the function.
|| In this example let declares the initial value
|| inside each FOR loop. If a var was used then it
|| would be declared outside of the loop.
==
|| Recursion is nested 2 levels deep and on each
|| iteration, a component from template.library
|| is cloned and appended.
*/
for (let l = 0; l < ct; l++) {
// Reference lib .category
let cat = lib.querySelector('.category');
// Create a shallow clone of .category (sec)
var sec = cat.cloneNode(false);
// Append sec it to #main
main.appendChild(sec);
for (let b = 0; b < bk; b++) {
// Reference lib .category .book
let book = lib.querySelector('.book');
// Create shallow clone of .book (pub)
var pub = book.cloneNode(false);
// Append it to .category (sec)
sec.appendChild(pub);
for (let p = 0; p < pg; p++) {
// Reference lib .category .book .page
let page = lib.querySelector('.page');
// Create a deep clone of.page (copy)
var copy = page.cloneNode(true);
// Append it to .book (pub)
pub.appendChild(copy);
}
// Continue to add a cloned copy to pub [pg] times
}
// Continue to add cloned pub to sec [bk] times
}
// Continue to add cloned sec to #main [ct] times
}
input {
font: inherit;
width: 4ch;
}
button {
font: inherit;
width: 10ch;
}
#main {
border: 6px dotted grey;
display: table
}
.category {
background: rgba(0, 0, 0, .6);
display: table-row
}
.category::before {
content: '\1f4da';
}
.book {
border: 3px solid red;
display: table-cell
}
.book::before {
content: '\1f4d8';
}
.page {
border: 1px solid gold;
display: inline-block;
}
.page::before {
content: '\1f4c3';
}
<!doctype html>
<html>
<head>
</head>
<body>
<form id='ui'>
<label>Categories:
<input id='ct' type='number' min='1' max='10' value='1'>
Books:
<input id='bk' type='number' min='1' max='10' value='1'>
Pages:
<input id='pg' type='number' min='1' max='10' value='1'>
</label>
<button id="btn" type='button'>Generate</button>
<br/>
<br/>
<!-- Refer to Template Tag-->
<template class='library'>
<section class='category'>
<article class='book'>
<span class='page'></span>
</article>
</section>
</template>
<main id="main">
</main>
</form>
</body>
</html>