v-if与v-show造成部分元素丢失的问题——v-if复用元素问题

Posted lxm-cnblog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了v-if与v-show造成部分元素丢失的问题——v-if复用元素问题相关的知识,希望对你有一定的参考价值。

问题描述

在写tab切换时遇到了一个问题,以下为简化后的问题所在的代码:

<img v-if="tabIndex === 2" id="t1">
<div v-if="tabIndex === 2" id="t2"></div>
<div v-if="tabIndex === 2" id="t3"></div>
<div v-show="tabIndex === 2" id="t4">
    <div id="content"></div>
</div>

当页面加载时,先向id为content的div中添加了一些元素:

function addContent() 
    const newDiv = document.createElement(\'div\');
    newDiv.innerHTML = \'123456789\';
    document.getElementById(\'content\').appendChild(newDiv);

  • 如果当tabIndex为2时执行addContent(),上述123456789能够正常显示;
  • 但如果:
    • 在此时将tabIndex改为1,再将tabIndex改为2,
    • 或者在tabIndex不为2时执行addContent(),再将tabIndex改为2,
      这两种情况下,123456789都无法正常显示。

问题探索

首先尝试将目标元素输出到控制台。在切换tabIndex前,先获取原来的元素:

var oldT4 = document.getElementById(\'t4\');
var oldContent = document.getElementById(\'content\');

此时输出显然能得到正确的结果。
然后在切换tabIndex后,再获取新的元素:

var newT4 = document.getElementById(\'t4\');
var newContent = document.getElementById(\'content\');
console.log(oldT4, newT4);
console.log(oldContent, newContent);

此时会发现:

  • oldContent元素虽然能正常输出,但在页面上已经不存在了,此时oldContent仅仅是引用了一个不存在的元素;
  • newContent元素就是当前页面上的content元素,但其中的内容已被清空。
  • newT4元素就是当前页面上的t4元素。
  • oldT4却离奇的变为了t2元素,console.log(oldT4 === document.getElementById(\'t2\'))的结果为true

问题原因

这是因为t4tabIndex切换时,复用了被v-if隐藏的t2元素,复用时会重新渲染t4内的所有内容,这种情况下,动态添加到content元素中的内容就会被清空。
这里复用的顺序则是从第一个同样为div的被v-if隐藏的元素开始复用,即t2元素。类似的,如果此时进一步将t2元素的v-if修改成v-show,则oldT4就会去复用t3元素。

解决方案

要保留content元素中的内容,可以考虑:

  1. t2t3v-if改成v-show
  2. 如果确实不方便修改v-if,则可以给t2t3添加key属性,使其不会被复用。

v-if与v-show的区别

场景:

  1、使用element-ui中el-upload组件作图片上传

  2、上传成功后来回切换tab

  3、tab是否显示使用的是v-if

  技术图片(粗略图)

问题:

  1、上传成功后,图片显示,切换tab之后图片不显示

  2、来回切换,图片的地址是一致的

问题分析:

  1、图片是否显示与图片路径有关

  2、console.log()以及查看元素,图片地址一致,排除切换前后路径不一致导致图片显示问题

  3、v-if的原理:v-if是通过控制dom节点的存在与否来控制元素的显隐,来回切换tab导致元素销毁、重建

问题解决:

  使用v-show代替v-if,避免销毁和重建导致节点内部事件监听和子组件。

问题延伸:v-if和v-show的区别,什么时候使用v-if或v_show?

  区别:1)v-if是通过控制dom节点的存在与否来控制元素的显隐;v-show是通过设置DOM元素的display样式,block为显示,none为隐藏;

     2)编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换;

     3)编译条件:v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译(编译被缓存?编译被缓存后,然后再切换的时候进行局部卸载); v-show是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且DOM元素保留;

      4)性能消耗:v-if有更高的切换消耗;v-show有更高的初始渲染消耗;

  使用场景:如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

  总结:v-if判断是否加载,可以减轻服务器的压力,在需要时加载,但有更高的切换开销;v-show调整DOM元素的CSS的dispaly属性,可以使客户端操作更加流畅,但有更高的初始渲染开销。如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

 

参考: https://www.jianshu.com/p/7af8554d8f08 

以上是关于v-if与v-show造成部分元素丢失的问题——v-if复用元素问题的主要内容,如果未能解决你的问题,请参考以下文章

vue中v-show与v-if的区别

vue v-if与v-show使用注意问题

vue中的v-if与v-show

前端面试 vue 部分 ——v-show和v-if的区别

Vue学习之v-if与v-show的区别

v-show v-if v-for