关于v-if和v-show页面渲染的问题

关于v-if和v-show页面渲染的问题。
在使用v-if时,v-if里面的表达式变化的时候,页面会进行自动同步渲染显示元素或者删除元素。
但是使用v-show的时候,需要重新编译一次页面,他才反应得过来,把元素隐藏/显示。

vue文件代码:

    <view>
        <view class="" v-show="arr.length !== 0">
            show1
        </view>
        <view v-show="arr.length === 0">
            show2
        </view>
        <button @click="add">change</button>
    </view>
<script>
    import {
        mapState,
        mapActions,
    } from 'vuex'
    export default {
        data() {
            return {

            };
        },
        methods: {
            ...mapActions('m_cart1', ['change','add']),
        },
        computed: {
            ...mapState('m_cart1', ['BooleanText']),
            ...mapState('m_cart1', ['arr']),
        }
    }
</script>

store文件夹的js文件代码:

export default {
    // 为当前模块开启命名空间
    namespaced: true,

    state: () => ({
        BooleanText:JSON.parse(uni.getStorageSync('text') || true),
        arr:JSON.parse(uni.getStorageSync('arr') || "[]"),
    }),
    actions: {
        change(context, value){
            context.commit("CHANGE", value);
        },
        add(context, value){
            context.commit("ADD", value);
        },
        saveToStorage(context, value) {
            context.commit("SAVETOSTORAGE", value);
        }
    },
    // 模块的 mutations 方法
    mutations: {
        CHANGE(state){
            state.BooleanText=!state.BooleanText;
        },
        ADD(state){
            state.arr.push(1);
            this.commit('m_cart1/SAVETOSTORAGE')
        },
        SAVETOSTORAGE(state) {
            uni.setStorageSync('text', JSON.stringify(state.BooleanText))
            uni.setStorageSync('arr', JSON.stringify(state.arr))
        }
    },
}
// 1. 导入 Vue 和 Vuex
import Vue from 'vue';
import Vuex from 'vuex';
import moduleCart1 from './cart1.js'
Vue.use(Vuex)


// 3. 创建 Store 的实例对象
const store = new Vuex.Store({
    // TODO:挂载 store 模块
    modules: {
        m_cart1: moduleCart1
    },

})

// 4. 向外共享 Store 的实例对象
export default store

代码概况:
点击change按钮就会往arr数组里利用push方法去添加一个元素,当arr的长度不等于0的时候,就展示show1,
等于0则展示show2。

结果:使用v-show去写隐藏条件v-show="arr.length !== 0"

img


初始没有问题,但是当我点击了change按钮,往arr添加元素之后,应该展示show1。

img


可以从控制台看到,arr数组的长度已经为1,元素添加成功了,但是依然展示show2,不是show1.
当我不清缓存重新编译,即相当于重新渲染页面,才显示show1.

img


这是为什么呢?数组的长度明明是发送了变化。对于vue不能感知到这个数组的变化,我是不怎么认同的,因为我在updated函数里面,打印这个arr数组的长度,他是可以正确打印出来的,确实发送了变化,而且我直接在页面上使用插值语法去显示这个arr数组的长度也是正确的。这里的尝试的代码和图片就不展示出来了。我觉得这就说明了vue是感知到了arr数组的变化的,但是就是不知道为什么v-show的判断条件没有进行重新判断?而是等页面重新渲染之后才判断。我也觉得这个说法说不通,因为我直接使用一个布尔类型变量去判断是可以的,使用数组.length!==0就不行。
当我使用v-if去判断v-if="arr.length !== 0"的时候,就没有这个问题,一点chang,数组长度变化,页面也跟着变化为show1,不需要重新编译。
这是为什么?v-if和v-show在这里有什么差异?
题外话:在以前,我们把数据放到自己的data里面是没有这个问题的,v-show和v-if都是直接自动刷新的,难道是因为这个arr是从store里读出来的缘故,亦或者是这个arr是计算属性的缘故?

在Vue中,当使用v-show时,元素始终存在于DOM中,只是通过CSS的display属性来控制元素是否显示。因此,当改变v-show表达式的值时,只会更新CSS属性而不会重新编译整个模板。这也就是为什么需要重新编译页面才能看到v-show的变化。

相比之下,当使用v-if时,每次表达式的值发生变化时,Vue会根据新值重新编译对应的模板,并且销毁或创建元素(取决于表达式的值)。因此,v-if更适合用于频繁切换的场景,但需要注意性能问题。

至于你遇到的问题,可能与Vuex相关。如果store中的数据被修改,Vue不能自动检测到这些变化并更新视图。你需要手动触发一个state的变化来通知Vue进行重新渲染。可以尝试在mutations中添加一行代码:

state.arr = state.arr.slice();

这将使数组重新分配内存,从而通知Vue重新渲染视图。

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 帮你找了个相似的问题, 你可以看下: https://ask.csdn.net/questions/935339
  • 你也可以参考下这篇文章:小工匠聊架构 - 缓存与数据库【双写不一致】&【读写并发不一致】解决方案一览
  • 除此之外, 这篇博客: 回流(重排)和重绘中的 对于复杂动画效果,使用绝对定位让其脱离文档流 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

    css有三种基本的定位机制:普通流、浮动和绝对定位。

    position 属性值的含义:

    static

    元素框正常生成。块级元素生成一个矩形框,作为文档流的一部分,行内元素则会创建一个或多个行框,置于其父元素中。

    relative

    元素框偏移某个距离。元素仍保持其未定位前的形状,它原本所占的空间仍保留。

    absolute

    元素框从文档流完全删除,并相对于其包含块定位。包含块可能是文档中的另一个元素或者是初始包含块。元素原先在正常文档流中所占的空间会关闭,就好像元素原来不存在一样。元素定位后生成一个块级框,而不论原来它在正常流中生成何种类型的框。

    fixed

    元素框的表现类似于将 position 设置为 absolute,不过其包含块是视窗本身

     

    对于复杂动画效果,由于会经常的引起回流重绘,因此,我们可以使用绝对定位,让它脱离文档流。否则会引起父元素以及后续元素频繁的回流。这个我们就直接上个

    例子

    从上图中,我们可以看到,帧数一直都没到60。这个时候,只要我们点击一下那个按钮,把这个元素设置为绝对定位,帧数就可以稳定60。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^