动态添加的内容没有正确调整容器大小。

huangapple go评论78阅读模式
英文:

Dynamically added content is not resizing container correctly

问题

我已将代码翻译好:

我已将代码简化到最小,实现了我想要的功能并仍然显示了问题。

我有一个对话框,分为头部、内容和底部三部分。对话框内容进一步分为内部内容和内部底部。

内部内容通过ajax调用获取数据。数据是可折叠树。问题发生在我点击一个节点展开时,内部底部和对话框底部被推出对话框的可见部分。

对话框可以调整大小,即使我调整大小只有一像素,布局也会立即纠正。我已经在这个问题上工作了几天,但没有运气。欢迎任何建议。

JSFiddle Demo

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<title>测试可折叠树</title>
		<style>
		// 省略部分CSS样式
		</style>
		<script>
		// 省略部分JavaScript代码
		</script>
	</head>
	<body onload="init();">
		<button onclick="javascript:fm.showDialog();">对话框</button>
	</body>
</html>

动态添加的内容没有正确调整容器大小。

动态添加的内容没有正确调整容器大小。

动态添加的内容没有正确调整容器大小。

英文:

I have stripped down my code to the minimum that does what I want and still shows the problem.

I have a dialog that has three parts: header, content and footer. The dialog content is further broken down into an inner content and an inner footer.

The inner content gets it's data from an ajax call. The data is a collapsible tree. The problem occurs when I click on a node to expand it, the inner footer and dialog footer get pushed off the visible part of the dialog.

The dialog is resizable, and the moment I resize it even by a pixel, the layout immediately corrects itself. I have been working on this for a few days now with no luck. Open to any suggestions.

JSFiddle Demo

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Testing Collapsable Trees</title>
<style>
ul.tree
{
margin-block-start: 0;
}
ul.tree li:hover
{
background-color: yellow;
}
ul.tree li 
{
padding-top : 0.25em;
list-style-type: none;
position: relative;
}
ul.tree ul 
{
display: none;
}
ul.tree ul.open
{
display: block;
}
ul.tree li::before 
{
height: 1em;
padding: 0.1em;
font-size: 0.8em;
display: block;
position: absolute;
left: -1.3em;
top: 0.35em;
}
ul.tree li:has(+ul)
{
text-decoration : underline black double 1px;
}
ul.tree li:has(+ul)::before 
{
content: '+';
}
ul.tree li:has(+ul.open)::before 
{
content: '-';
}
.selectedNode
{
color : green;
}
dialog
{
overflow: hidden;
resize: both;
padding : 0;
margin: auto;
max-height: 25%;
}
dialog h3
{
margin : 0.25em 0;
}
dialog button
{
margin: 0.33em;
padding: 0.33em 0.5em;
}
.dlgbody
{
height: 100%;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas: 'header' 'main' 'footer';
}
.dlgheader 
{
background-color: lightgreen;
display: flex;
justify-content: center;
border-bottom: 2px double black;
grid-area: header;
}
.dlgcontent 
{
overflow: hidden;
background-color: white;
grid-area: main;
padding: 5px;
}
.dlgfooter 
{
background-color: lightblue;
padding-right: 0.5em;
display: flex;
justify-content: flex-end;
border-top: 2px double black;
grid-area: footer;
}
.fmbody
{
height: 100%;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr auto;
grid-template-areas: 'fmmain' 'fmfooter';
}
.fmcontent 
{
background-color: white;
grid-area: fmmain;
overflow: auto;
padding: 0px 5px 0px 5px;
}
.fmfooter 
{
background-color: white;
border-top: 1px solid black;
grid-area: fmfooter;
}
</style>
<script>
class Tree
{
constructor(root)
{
this.root = document.createElement("ul");
this.root.classList.add("tree");
this.root.tabIndex = "-1";
this.root.addEventListener("click", evt => this.mouseHandler(evt));
}
toggleCollapse(evt)
{
let node = evt.target.nextElementSibling;
if(node == null || node.nodeName != "UL")
return;
if(node.classList.contains("open")) 
{
node.classList.remove('open');
let opensubs = node.querySelectorAll(':scope .open');
for(let i = 0; i < opensubs.length; i++) 
opensubs[i].classList.remove('open'); 
} 
else 
node.classList.add('open'); 
}
mouseHandler(evt)
{
this.toggleCollapse(evt);
let node = this.getSelected();
if(node != null)
node.classList.remove("selectedNode");
evt.target.classList.add("selectedNode");
this.root.dispatchEvent(new Event("selected"));
}
getRoot()
{
return this.root;
}
getSelected()
{
return this.root.querySelector(":scope .selectedNode");
}
}
class Dialog
{
constructor()
{
this.dialogDiv = document.createElement("dialog");
this.dlgHeader = document.createElement("div");
this.dlgContent = document.createElement("div");
this.dlgFooter = document.createElement("div");
}
init(opts)
{
let body = document.createElement("div");
body.classList.add("dlgbody");
// Build header
let title = document.createElement("h3");
title.innerHTML = opts.title;
this.dlgHeader.appendChild(title);
this.dlgHeader.classList.add("dlgheader");
body.appendChild(this.dlgHeader);
// build div for dialog content
this.dlgContent.classList.add("dlgcontent");
body.appendChild(this.dlgContent);
// build footer
let okbutton = document.createElement("button");
okbutton.textContent = "OK";
okbutton.onclick = (evt) => { this.dialogDiv.close("OK"); }
this.dlgFooter.appendChild(okbutton);
this.dlgFooter.classList.add("dlgfooter");
body.appendChild(this.dlgFooter);
this.dialogDiv.appendChild(body);
document.body.appendChild(this.dialogDiv);
}
show()
{
this.dialogDiv.returnValue = "";
this.dialogDiv.showModal();
}
getContentDiv()
{
return this.dlgContent;
}
getDialogRoot()
{
return this.dialogDiv;
}
}	
class FileManager
{
constructor(opts)
{
this.uiList = document.createElement("div");
this.files = new Tree();
this.dialog = new Dialog();
this.dialog.init({title : opts.title});
this.uiList.classList.add("fmcontent");
this.uiList.appendChild(this.files.getRoot());
let uiFooter = document.createElement("div");
uiFooter.classList.add("fmfooter");
let label = document.createElement("h3");
label.textContent = "Content Footer";	
uiFooter.appendChild(label);
let ui = document.createElement("div");
ui.classList.add("fmbody");
ui.appendChild(this.uiList);
ui.appendChild(uiFooter);
this.dialog.getContentDiv().appendChild(ui);
}
loadData()
{
let tree = this.files.getRoot();
let data = JSON.parse(testData);
this.build(tree, data);
}
showDialog()
{
this.dialog.show();
this.files.getRoot().focus();
if(this.files.getRoot().children.length == 0)
this.loadData();
}
build(tree, data)
{
for(let i = 0; i < data.length; i++)
{
if(i == 0)
{
if(data[i] == "")
continue;
let li = document.createElement("li");
li.textContent = data[i];
tree.appendChild(li);
let ul = document.createElement("ul");
tree.appendChild(ul);
tree = ul;
}
if(Array.isArray(data[i]))
this.build(tree, data[i]);
else if(i > 0)
{
let li = document.createElement("li");
li.textContent = data[i];
tree.appendChild(li);
}
}
}
}
var testData = '["", ["files", "subfile1", "subfile2", "subfile3", "subfile4", "subfile5", "subfile6"], ["images", "image 1"]]';
var fm = null;
function init()
{
fm = new FileManager({title : "Dialog Header"});
}
</script>
</head>
<body onload="init();">
<button onclick="javascript:fm.showDialog();">Dialog</button>
</body>
</html>

动态添加的内容没有正确调整容器大小。

动态添加的内容没有正确调整容器大小。

动态添加的内容没有正确调整容器大小。

答案1

得分: 1

The issue was the max-height set for dialog. Changed it to height and the issue was gone.

类似以下的代码片段需要翻译:

  • class Treeclass FileManager 的部分
  • ul.tree.fmfooter 的 CSS 样式
  • HTML 中的部分,包括 <!DOCTYPE html><button onclick="javascript:fm.showDialog();">Dialog</button> 的内容。
英文:

The issue was the max-height set for dialog. Changed it to height and the issue was gone.

(Just run snippet in full page to see the result)

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

class Tree
{
constructor(root)
{
this.root = document.createElement(&quot;ul&quot;);
this.root.classList.add(&quot;tree&quot;);
this.root.tabIndex = &quot;-1&quot;;
this.root.addEventListener(&quot;click&quot;, evt =&gt; this.mouseHandler(evt));
}
toggleCollapse(evt)
{
let node = evt.target.nextElementSibling;
if(node == null || node.nodeName != &quot;UL&quot;)
return;
if(node.classList.contains(&quot;open&quot;)) 
{
node.classList.remove(&#39;open&#39;);
let opensubs = node.querySelectorAll(&#39;:scope .open&#39;);
for(let i = 0; i &lt; opensubs.length; i++) 
opensubs[i].classList.remove(&#39;open&#39;); 
} 
else 
node.classList.add(&#39;open&#39;); 
}
mouseHandler(evt)
{
this.toggleCollapse(evt);
let node = this.getSelected();
if(node != null)
node.classList.remove(&quot;selectedNode&quot;);
evt.target.classList.add(&quot;selectedNode&quot;);
this.root.dispatchEvent(new Event(&quot;selected&quot;));
}
getRoot()
{
return this.root;
}
getSelected()
{
return this.root.querySelector(&quot;:scope .selectedNode&quot;);
}
}
class Dialog
{
constructor()
{
this.dialogDiv = document.createElement(&quot;dialog&quot;);
this.dlgHeader = document.createElement(&quot;div&quot;);
this.dlgContent = document.createElement(&quot;div&quot;);
this.dlgFooter = document.createElement(&quot;div&quot;);
}
init(opts)
{
let body = document.createElement(&quot;div&quot;);
body.classList.add(&quot;dlgbody&quot;);
// Build header
let title = document.createElement(&quot;h3&quot;);
title.innerHTML = opts.title;
this.dlgHeader.appendChild(title);
this.dlgHeader.classList.add(&quot;dlgheader&quot;);
body.appendChild(this.dlgHeader);
// build div for dialog content
this.dlgContent.classList.add(&quot;dlgcontent&quot;);
body.appendChild(this.dlgContent);
// build footer
let okbutton = document.createElement(&quot;button&quot;);
okbutton.textContent = &quot;OK&quot;;
okbutton.onclick = (evt) =&gt; { this.dialogDiv.close(&quot;OK&quot;); }
this.dlgFooter.appendChild(okbutton);
this.dlgFooter.classList.add(&quot;dlgfooter&quot;);
body.appendChild(this.dlgFooter);
this.dialogDiv.appendChild(body);
document.body.appendChild(this.dialogDiv);
}
show()
{
this.dialogDiv.returnValue = &quot;&quot;;
this.dialogDiv.showModal();
}
getContentDiv()
{
return this.dlgContent;
}
getDialogRoot()
{
return this.dialogDiv;
}
}	
class FileManager
{
constructor(opts)
{
this.uiList = document.createElement(&quot;div&quot;);
this.files = new Tree();
this.dialog = new Dialog();
this.dialog.init({title : opts.title});
this.uiList.classList.add(&quot;fmcontent&quot;);
this.uiList.appendChild(this.files.getRoot());
let uiFooter = document.createElement(&quot;div&quot;);
uiFooter.classList.add(&quot;fmfooter&quot;);
let label = document.createElement(&quot;h3&quot;);
label.textContent = &quot;Content Footer&quot;;	
uiFooter.appendChild(label);
let ui = document.createElement(&quot;div&quot;);
ui.classList.add(&quot;fmbody&quot;);
ui.appendChild(this.uiList);
ui.appendChild(uiFooter);
this.dialog.getContentDiv().appendChild(ui);
}
loadData()
{
let tree = this.files.getRoot();
let data = JSON.parse(testData);
this.build(tree, data);
}
showDialog()
{
this.dialog.show();
this.files.getRoot().focus();
if(this.files.getRoot().children.length == 0)
this.loadData();
}
build(tree, data)
{
for(let i = 0; i &lt; data.length; i++)
{
if(i == 0)
{
if(data[i] == &quot;&quot;)
continue;
let li = document.createElement(&quot;li&quot;);
li.textContent = data[i];
tree.appendChild(li);
let ul = document.createElement(&quot;ul&quot;);
tree.appendChild(ul);
tree = ul;
}
if(Array.isArray(data[i]))
this.build(tree, data[i]);
else if(i &gt; 0)
{
let li = document.createElement(&quot;li&quot;);
li.textContent = data[i];
tree.appendChild(li);
}
}
}
}
var testData = &#39;[&quot;&quot;, [&quot;files&quot;, &quot;subfile1&quot;, &quot;subfile2&quot;, &quot;subfile3&quot;, &quot;subfile4&quot;, &quot;subfile5&quot;, &quot;subfile6&quot;], [&quot;images&quot;, &quot;image 1&quot;]]&#39;;
var fm = null;
function init()
{
fm = new FileManager({title : &quot;Dialog Header&quot;});
}

<!-- language: lang-css -->

ul.tree
{
margin-block-start: 0;
}
ul.tree li:hover
{
background-color: yellow;
}
ul.tree li 
{
padding-top : 0.25em;
list-style-type: none;
position: relative;
}
ul.tree ul 
{
display: none;
}
ul.tree ul.open
{
display: block;
}
ul.tree li::before 
{
height: 1em;
padding: 0.1em;
font-size: 0.8em;
display: block;
position: absolute;
left: -1.3em;
top: 0.35em;
}
ul.tree li:has(+ul)
{
text-decoration : underline black double 1px;
}
ul.tree li:has(+ul)::before 
{
content: &#39;+&#39;;
}
ul.tree li:has(+ul.open)::before 
{
content: &#39;-&#39;;
}
.selectedNode
{
color : green;
}
dialog
{
overflow: hidden;
resize: both;
padding : 0;
margin: auto;
height: 25%;  
}
dialog h3
{
margin : 0.25em 0;
}
dialog button
{
margin: 0.33em;
padding: 0.33em 0.5em;
}
.dlgbody
{
height: 100%;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas: &#39;header&#39; &#39;main&#39; &#39;footer&#39;;
}
.dlgheader 
{
background-color: lightgreen;
display: flex;
justify-content: center;
border-bottom: 2px double black;
grid-area: header;
}
.dlgcontent 
{
overflow: hidden;
background-color: white;
grid-area: main;
padding: 5px;
}
.dlgfooter 
{
background-color: lightblue;
padding-right: 0.5em;
display: flex;
justify-content: flex-end;
border-top: 2px double black;
grid-area: footer;
}
.fmbody
{
height: 100%;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr auto;
grid-template-areas: &#39;fmmain&#39; &#39;fmfooter&#39;;
}
.fmcontent 
{
background-color: white;
grid-area: fmmain;
overflow: auto;
padding: 0px 5px 0px 5px;
}
.fmfooter 
{
background-color: white;
border-top: 1px solid black;
grid-area: fmfooter;
}

<!-- language: lang-html -->

&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
&lt;meta charset=&quot;utf-8&quot;&gt;
&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;
&lt;title&gt;Testing Collapsable Trees&lt;/title&gt;
&lt;/head&gt;
&lt;body onload=&quot;init();&quot;&gt;
&lt;button onclick=&quot;javascript:fm.showDialog();&quot;&gt;Dialog&lt;/button&gt;
&lt;/body&gt;
&lt;/html&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年6月8日 12:32:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76428643.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定