英文:
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:
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):
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):
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:
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):
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):
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);
}
答案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?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论