子元素显示更新时如何消除宽度计算错误?

问题描述 投票:0回答:1

我做了一个网站,在侧边栏中有一个树浏览器。这棵树的节点是可点击的,以显示或隐藏它们的子树。目前,当我切换子树时,资源管理器的宽度计算错误。该问题出现在适用于 Ubuntu 桌面的 Chrome 版本 111.0.5563.64 上,并在下面的代码片段中重现。请看一下。

var [leftEl, rightEl] = (
  document.getElementById("grid")
).children;

var tree = `\
node /1
  node /1/1
  node /1/2
  node /1/3
    node /1/3/1
    node /1/3/2
    node /1/3/3
node /2
  node /2/1
  node /2/2
  node /2/3
`;

leftEl.innerHTML = "<ul>" + (
  tree.split("\n").slice(0, -1)
  // string to nested objects
. reduce(function (stack, line) {
    var i = line.search(/[^ ]/);
    var depth = i / 2;
    if (depth + 1 > stack.length) {
      var [tree] = stack.slice(-1);
      tree = tree.children.slice(-1)[0];
      tree.children = [];
      stack.push(tree);
    } else {
      stack = stack.slice(0, depth + 1);
      var [tree] = stack.slice(-1);
    }
    tree.children.push(
      { name : line.slice(i) }
    );
    return stack;
  }, [{ children : [] }])[0]
  // nested objects to HTML
. children.reduce(function nodeToHtml (
    [html, depth], { name, children }
  ) {
    children = !children ? "" : "<ul>" + (
      children.reduce(nodeToHtml, ["", depth + 1])[0]
    ) + "</ul>";
    return [html + (
      "<li" + (children ? "" : ' class="leaf"') + ">"
    +   `<div style="padding-left:${.5 + depth}em">${name}</div>`
    +   children
    + "</li>"
    ), depth];
  }, ["", 0])[0]
) + "</ul>";

leftEl.addEventListener("click", function({ target }) {
  if (target !== this) if (target.tagName === "DIV") {
    var liEl = target.parentNode;
    var classAttr = liEl.getAttribute("class");
    if (classAttr === "unfolded") {
      liEl.removeAttribute("class");
    } else if (classAttr !== "leaf") {
      liEl.setAttribute("class", "unfolded");
    }
  }
});

leftEl.addEventListener("mouseover", function({ target }) {
  if (target !== this) if (target.tagName === "DIV") {
    target.setAttribute("class", "highlighted");
    rightEl.textContent = target.textContent;
  }
});

leftEl.addEventListener("mouseout", function({ target }) {
  if (target !== this) if (target.tagName === "DIV") {
    target.removeAttribute("class");
  }
});
#grid {
  height: 150px;
  display: grid;
  grid-template: 1fr / auto minmax(0, 1fr);
  background: pink;
}

#grid > div:first-child {
  grid-row: 1 / 2;
  grid-column: 1 / 2;
  background: yellow;
  user-select: none;
  overflow: auto;
}

#grid > div:last-child {
  grid-row: 1 / 2;
  grid-column: 2 / 3;
  background: cyan;
  padding: .25em;
}

ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

li {
  line-height: 1.2em;
}

li div {
  cursor: pointer;
  padding: .2em .5em;
  margin-bottom: .2em;
  white-space: nowrap;
  border-right: 10px solid lime;
}

li div.highlighted {
  background: cyan;
}

li div::before {
  content: "▸\a0\a0";
}

li.unfolded > div::before {
  content: "▾\a0\a0";
}

li.leaf div::before {
  visibility: hidden;
}

li ul {
  display: none;
}

li.unfolded > ul {
  display: block;
}
<div id="grid">
  <div></div>
  <div></div>
</div>

如您所见,我们在网格布局中并排放置了两个

div
元素。

黄色

div
元素(左侧)是树浏览器。这个
div
元素必须是垂直滚动的,因为它的高度是固定的,而且它的内容可以是任意长的。树本身由嵌套的
ul
元素组成,如下所示,面向每个节点名称的绿色边框旨在显示文本溢出(如果有)。

<ul>
  <li>
    <div>node /1</div>
    <ul>
      <li class="leaf">
        <div>node /1/1</div>
      </li>
      <li class="leaf">
        <div>node /1/2</div>
      </li>
    </ul>
  </li>
</ul>

蓝色

div
元素(右边)根据
fr
单位增长。每次鼠标光标悬停在树浏览器中的节点上时,其内容都会更新。

错误计算在树溢出黄色

div
元素时出现,并在蓝色
div
元素内容更新时消失

你知道为什么会出现这种宽度计算错误以及我如何摆脱它(最好使用 CSS)吗?

javascript css grid scrollbar width
1个回答
0
投票

这似乎是 p 标签周围的 div 的问题。 添加:

1: wrap.style.width = "0px"

到案例2里面的JavaScript代码,然后:

2: wrap.style.width = ""

对于案例 0,解决了状态 4 上的边界。但是它在状态 2 上仍然没有很好地显示。

添加:

3: overflow-y: scroll;

#grid div:first-child 和:

4: overflow: hidden;

to #grid 允许隐藏水平滚动条,尽管这会导致垂直滚动条在第一个状态下可见。 然后添加:

5: gridEl.style.overflow = "visible"

JS 使其再次可见。

添加:

6: #wrap {
      display: none;
   }

CSS 消除了初始滚动条。然后添加:

7: wrap.style.display = "block"

JS让它在那之后显示。 我已将上述更改添加到您的以下代码中:

var i = 0;
var infoEl = document.getElementById("info");
var gridEl = document.getElementById("grid");
var wrap = document.getElementById("wrap");
var [leftEl, rightEl] = gridEl.children;
rightEl.addEventListener("click", function() {
  infoEl.textContent = (
    "STATE #" + (((i + 1) % 4) + 1)
  );
  /* change 5 */
  gridEl.style.overflow = "visible"
  /* change 7 */
  wrap.style.display = "block"
  
  switch (i++ % 4) {
    case 0:
      leftEl.setAttribute("class", "show-children");
      /* change 2 */
      wrap.style.width = ""
      
      break;
    case 2:
      /* change 1 */
      wrap.style.width = "0px"
      
      leftEl.removeAttribute("class");
      break;
    default: // = case 1 and case 3
      rightEl.innerHTML = "UPDATE #" + (i / 2);
      break;
  }
});
#grid {
  height: 100px;
  display: grid;
  grid-template: 1fr / auto minmax(0, 1fr);
  background: pink;
  /* change 4 */
  overflow: hidden;
  
}

#grid div:first-child {
  grid-row: 1 / 2;
  grid-column: 1 / 2;
  background: yellow;
  /* change 3 */
  overflow-y: scroll;
  
}

#grid div:last-child {
  grid-row: 1 / 2;
  grid-column: 2 / 3;
  background: cyan;
  user-select : none;
}

#grid p {
  margin: 1em 0;
  white-space: nowrap;
  border-right: 10px solid red;
  display: none;
  margin: 0;
}

#grid .show-children p {
  display: block;
}

/* change 6 */
#wrap {
  display: none;
}
<p id="info">STATE #1</p>
<div id="grid">
  <div id="wrap">
    <p>A B C D E F G</p>
    <p>A B C D E F G</p>
    <p>A B C D E F G</p>
    <p>A B C D E F G</p>
    <p>A B C D E F G</p>
    <p>A B C D E F G</p>
    <p>A B C D E F G</p>
    <p>A B C D E F G</p>
    <p>A B C D E F G</p>
  </div>
  <div>CLICK ME (SLOWLY)</div>
</div>

© www.soinside.com 2019 - 2024. All rights reserved.