为什么Vue会显示v-if条件的两个备选项?

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

Why is Vue displaying both alternatives of a v-if condition?

问题

以下是您要翻译的内容:

"I am somehow ending up with Vue displaying both variants of a v-if condtion, when it should be displaying only one.

The layout starts like this:

为什么Vue会显示v-if条件的两个备选项?

and after a drag operation looks like this, with the extra component ( a vuetify v-chip) being pushed into a new row because there isn't enough room (there should be only 5 in a row):

为什么Vue会显示v-if条件的两个备选项?

I have checked the contents of the grid row that contains the data for these chips and confirmed that, after the drag, it still has only five columns, so there should be just 5 chips. The duplicated chip (the first 'A', the one that should not be there) has the outlined variant and the correct one (the blue 'A') does not - this is the correct result of dragging the original outlined 'A' chip out of the grid. The Vue template section is:

<v-container id="startgrid" style="max-width: 240px; height: 250px; position: relative;">
  <v-row v-for="(row,r) in startGrid" >
    <template v-for="(chip,c) in row" :key="chip.id" >
      <v-chip v-if="!chip.used" size="x-large" variant="outlined" class="copyable changeclass"
          @dropped="drop"
          @swapped="swap"
          :data-keep-row = r
          :data-keep-col = c
          :data-letter = chip.name
          :id=idString(0,r,c)
          > {{ chip.name }}
      </v-chip>
      <v-chip v-else size="x-large" 
          :data-letter = chip.name
          :id=idString(0,r,c)
          color="blue"
          > {{ chip.name }}
      </v-chip>
    </template>
  </v-row>
</v-container>

To confirm that I really am seeing both conditions of the v-if, I temporarily added the row and column numbers to the text of the blue variant but not to the outlined one, the result being (for a different letter being dragged):

为什么Vue会显示v-if条件的两个备选项?

Also (although not shown here) I temporarily added the length of the grid row to the chip name, to see how long 'Vue' thought it was when it was actually rendered. It was 5.

Looking at the elements in the browser debugger confirms what I am seeing, i.e. an extra component with opposing styles.

The drag/drop code manipulating the components (the code that provides the dropped and swapped events) is too involved to replicate here, so I am just wondering what sort of error might lead to this? How can chip.used (the conditional value) be both true and false at the same time?

Edit

A suggested answer is that the :key values may be duplicated. I have checked these and they are all defined uniquely - 1 to 25 for each cell of the 5 x 5 grid. Having said that, is there a way I can view these :key values for each component in a browser inspector? I can see the element id's but not any :key values. More specifically, if I am copying/replacing an element (see code below), do I need to reset the :key? If so, how?

I have also been asked to provide a reproducible example. Currently there are hundreds of code lines leading to this error, but I will try to arrange something smaller. In the meantime, the specific lines causing it are something like this:

function copyObject(source,dest) {

  const parent2 = dest.parentNode;
  const parent1 = source.parentNode;
  const nextSib = source.nextSibling;

  if (parent1 === null || parent2 === null)
    throw 'null parent(s) in copying element';

  // a copy needed to replace the one being copied and moved
  const copyElement = source.cloneNode(true);

  // move to new grid
  parent2.replaceChild(source,dest);
  // replaceChild() removes original , so replace the original with the copy
  parent1.insertBefore(copyElement.el,nextSib);
}

如果您有任何其他问题或需要进一步的帮助,请随时告诉我。

英文:

I am somehow ending up with Vue displaying both variants of a v-if condtion, when it should be displaying only one.

The layout starts like this:

为什么Vue会显示v-if条件的两个备选项?

and after a drag operation looks like this, with the extra component ( a vuetify v-chip) being pushed into a new row because there isn't enough room (there should be only 5 in a row):

为什么Vue会显示v-if条件的两个备选项?

I have checked the contents of the grid row that contains the data for these chips and confirmed that, after the drag, it still has only five columns, so there should be just 5 chips. The duplicated chip (the first 'A', the one that should not be there) has the outlined variant and the correct one (the blue 'A') does not - this is the correct result of dragging the original outlined 'A' chip out of the grid. The Vue template section is:

&lt;v-container id=&quot;startgrid&quot; style=&quot;max-width: 240px; height: 250px; position: relative;&quot;&gt;
  &lt;v-row v-for=&quot;(row,r) in startGrid&quot; &gt;
	&lt;template v-for=&quot;(chip,c) in row&quot; :key=&quot;chip.id&quot; &gt;
		&lt;v-chip v-if=&quot;!chip.used&quot; size=&quot;x-large&quot; variant=&quot;outlined&quot; class=&quot;copyable changeclass&quot;
		    @dropped=&quot;drop&quot;
			@swapped=&quot;swap&quot;
			:data-keep-row = r
		    :data-keep-col = c
			:data-letter = chip.name
			:id=idString(0,r,c)
			&gt; {{ chip.name }}
		&lt;/v-chip&gt;
		&lt;v-chip v-else size=&quot;x-large&quot; 
			:data-letter = chip.name
			:id=idString(0,r,c)
			color=&quot;blue&quot;
			&gt; {{ chip.name }}
		&lt;/v-chip&gt;
	&lt;/template&gt;
  &lt;/v-row&gt;
&lt;/v-container&gt;

To confirm that I really am seeing both conditions of the v-if, I temporarily added the row and column numbers to the text of the blue variant but not to the outlined one, the result being (for a different letter being dragged):

为什么Vue会显示v-if条件的两个备选项?

Also (although not shown here) I temporarily added the length of the grid row to the chip name, to see how long 'Vue' thought it was when it was actually rendered. It was 5.

Looking at the elements in the browser debugger confirms what I am seeing, i.e. an extra component with opposing styles.

The drag/drop code manipulating the components (the code that provides the dropped and swapped events) is too involved to replicate here, so I am just wondering what sort of error might lead to this? How can chip.used (the conditional value) be both true and false at the same time?


Edit

A suggested answer is that the :key values may be duplicated. I have checked these and they are all defined uniquely - 1 to 25 for each cell of the 5 x 5 grid. Having said that, is there a way I can view these :key values for each component in a browser inspector? I can see the element id's but not any :key values. More specifically, if I am copying/replacing an element (see code below), do I need to reset the :key? If so, how?


I have also been asked to provide a reproducible example. Currently there are hundreds of code lines leading to this error, but I will try to arrange something smaller. In the meantime, the specific lines causing it are something like this:

function copyObject(source,dest) {

  const parent2 = dest.parentNode;
  const parent1 = source.parentNode;
  const nextSib = source.nextSibling;

  if (parent1 === null || parent2 === null)
    throw &#39;null parent(s) in copying element&#39;

  // a copy needed to replace the one being copied and moved
  const copyElement = source.cloneNode(true);

  // move to new grid
  parent2.replaceChild(source,dest);
  // replaceChild() removes original , so replace the original with the copy
  parent1.insertBefore(copyElement.el,nextSib);
}

答案1

得分: 3

Most likely, your :key is not unique, leading to Vue being unable to detect which nodes to remove. Here is a playground reproducing the behavior.

Could this be your issue?

英文:

Most likely, your :key is not unique, leading to Vue being unable to detect which nodes to remove. Here is a playground reproducing the behavior.

Could this be your issue?

答案2

得分: 1

@陶的建议实际上就是答案。在使用Vue(或其他响应式库)时尝试操纵DOM是不正确的。
我所需要做的只是忽略我的拖放库的最终DOM操作:

function copyObject(source, dest) {

  if (Draggable.options.reactive)
    // 这里无需操作
    return;

  const parent2 = dest.parentNode;
  const parent1 = source.parentNode;
  const nextSib = source.nextSibling;
  .....
  .....
}

然后简单更改,将新图像复制回数据源,以供Vue渲染:

trackGrid[toRow][toCol].type = fromType;
trackGrid[toRow][toCol].content = cellImage(fromType);

现在这比尝试移动元素本身要简单得多。
我仍然在临时更改时使用DOM操作(例如,在拖动过程中在屏幕上移动复制图像),因此我的库的大部分其余部分仍然完好无损,既可以用于Vue,也可以用于纯JS。

此外,还有一个额外的好处,通过评论我还了解到了Chrome的vue DevTools - 看起来很不错!为什么我没有早点发现它呢?

英文:

@Tao's suggestion was in fact the answer. It is incorrect to try to manipulate the DOM when using Vue (or, I suppose , other reactive-type libraries).
All I needed to do was to ignore the final DOM manipulation of my drag/drop library:

function copyObject(source,dest) {

  if (Draggable.options.reactive)
    // nothing to do here
        return;

  const parent2 = dest.parentNode;
  const parent1 = source.parentNode;
  const nextSib = source.nextSibling;
  .....
  .....
}

plus a simple change afterwards to copy the new images back into the data source, ready for Vue to render.

trackGrid[toRow][toCol].type = fromType;
trackGrid[toRow][toCol].content = cellImage(fromType);

This is now so much more straightforward than trying to move the elements themselves.
I am still using DOM manipulation for temporary changes (e.g. moving an copy image across the screen during a drag) so most of the rest of my library remains intact, and can still be used both for Vue and for plain JS.

Plus a bonus, from a comment I also learned about vue DevTools for Chrome - it looks great! Why didn't I find it sooner?

huangapple
  • 本文由 发表于 2023年5月17日 17:51:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76270772.html
匿名

发表评论

匿名网友

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

确定