vue 骚操作 同时使用v-if v-show保持页面只第一次渲染时调接口

博客讨论了Vue中实现两个页面首次打开才调接口的问题。仅用keepAlive、v-if或v-show都无法达到理想效果,提出同时使用v-if和v-show的方案,让v-if与data挂钩,v-show与tabNav挂钩,页面mounted时设置对应值,避免反复调接口,节省资源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

想要实现这两个页面第一次打开时才调接口,光keepAlive还不行,只使用v-if达不到效果,使用v-show又一下调了两页面的接口

可以同时使用v-if和v-show

v-if跟个data挂钩  ,例如叫showPage: [true, false](默认第一屏显示)

v-show跟tabNav挂钩,这里只有0,1

当页面mounted时将对应的showpage置true,这样来回切换时就不会反复调接口了

分析原因:

v-if是将dom元素删除,v-show则是display:none

v-if不为真时整个组件是被销毁了的,再次打开又是重新渲染

这里加了个showPage,就是保证第一次加载后组件不被销毁,后面就用v-show控制显示,达到节省接口的目的

 

 

<think>我们面临的核心问题:在Vue3中使用v-if控制组件,希望组件只加载一次,避免重复渲染(即切换时保留状态,不重新创建)。 根据引用内容: 引用[2]指出:v-if在条件为false时会销毁DOM元素和组件实例,条件为true时重新创建。这会导致组件状态丢失。 引用[4]展示了在vue2中,当使用v-if切换相同组件的不同状态时,组件会重新渲染。 在Vue3中,我们可以使用`<keep-alive>`组件来缓存v-if切换的组件,使其不被销毁,从而保留状态。 具体方案: 1. 使用`<keep-alive>`包裹需要缓存的组件。 2. 结合`v-if`或动态组件`:is`来实现条件渲染。 但是注意:用户要求使用v-if,并且希望避免重复渲染(即只加载一次)。这里有两种情况: a. 组件第一次渲染后,即使被v-if设为false,再次显示时也不重新创建(使用缓存)。 b. 组件第一次渲染后,后续切换时都不重新创建。 因此,我们可以使用`<keep-alive>`来缓存组件。 示例代码: 假设我们有两个组件,但用户可能是同一个组件的不同实例,或者不同的组件。根据引用[4]的场景,可能是同一个组件(CommonForm)的不同实例,但传递不同的props。 如果使用同一个组件,但通过不同的v-if块来显示,那么每次切换都会重新创建,因为v-if会销毁和重建。 为了解决,我们可以使用`<keep-alive>`包裹,并给每个组件一个唯一的key(如果组件类型相同,则必须用key来区分,否则复用同一个实例导致状态混乱),或者使用动态组件。 但是,用户要求用v-if,所以我们不用动态组件,而是用多个v-if,但用keep-alive包裹每个组件。 然而,注意:keep-alive只能缓存被切换掉的组件。如果同时存在多个,那么它们都会被缓存吗?不会,因为v-if是互斥的,同一时间只有一个显示。 所以,我们可以这样: ```html <template> <div> <!-- 使用keep-alive包裹每个组件,这样每个组件第一次渲染后都会被缓存,即使被v-if销毁,也会被keep-alive保存实例 --> <keep-alive> <ComponentA v-if="type === 'A'" :key="'A'"/> </keep-alive> <keep-alive> <ComponentB v-if="type === 'B'" :key="'B'"/> </keep-alive> </div> </template> ``` 但是,这样写会使得每个keep-alive单独缓存一个组件。实际上,我们也可以用一个keep-alive包裹多个组件: ```html <template> <div> <keep-alive> <ComponentA v-if="type === 'A'" key="A"/> <ComponentB v-else-if="type === 'B'" key="B"/> </keep-alive> </div> </template> ``` 注意:这里必须给每个组件设置不同的key,这样keep-alive才能区分它们,分别缓存。 如果两个组件是同一个组件,只是props不同,那么我们可以: ```html <template> <div> <keep-alive> <CommonForm v-if="type === '1'" :formData="{a:1}" key="1"/> <CommonForm v-if="type === '2'" :formData="{b:2}" key="2"/> </keep-alive> </div> </template> ``` 这样,当type从'1'切换到'2'时,第一个CommonForm会被缓存,第二个CommonForm会被创建并缓存。当切换回'1'时,第一个CommonForm会从缓存中恢复,不会重新创建。 但是,注意:v-if和v-else-if也可以,但这里用了两个v-if,因为条件不是互斥的?实际上,我们通常用互斥条件,所以用v-if和v-else-if。 关键点:给同一个组件的不同实例设置不同的key,这样keep-alive会分别缓存它们。 这样,每个组件实例(根据key区分)都只会在第一次渲染时创建,之后切换时都会从缓存中恢复。 另外,如果用户希望组件只加载一次,那么当组件被缓存后,再次显示时就不会重新加载(即不会执行onMounted等)。但是,如果用户希望在激活时重新获取数据,可以使用onActivated生命周期钩子。 总结步骤: 1. 在需要缓存的地方使用`<keep-alive>`包裹。 2. 为每个条件分支的组件设置唯一的key(特别是同一组件不同实例时)。 3. 使用v-if/v-else-if来控制显示。 注意事项: - 被缓存的组件会触发activated和deactivated生命周期钩子,而不是unmounted。 - 如果需要强制刷新,可以改变key(但这样会重新创建,不符合只加载一次的要求)。 - 如果组件不需要缓存,可以排除,或者使用max限制缓存数量。 因此,针对用户的问题,使用keep-alive包裹v-if组件,并设置key,即可实现只加载一次(每个条件分支的组件实例只创建一次),避免重复渲染。 代码示例(Vue3 Composition API): ```html <template> <div class="app-container"> <button @click="toggleType">切换类型</button> <keep-alive> <!-- 注意:这里使用两个v-if也可以,但条件互斥,所以用v-if和v-else-if --> <CommonForm v-if="type === '1'" :formData="{a:1}" key="1" /> <CommonForm v-else-if="type === '2'" :formData="{b:2}" key="2" /> </keep-alive> </div> </template> <script setup> import { ref } from 'vue'; import CommonForm from './CommonForm.vue'; const type = ref('1'); function toggleType() { type.value = type.value === '1' ? '2' : '1'; } </script> ``` 这样,无论切换多少次,每个key对应的组件实例都只会在第一次渲染时创建,之后切换时都是激活/停用状态,不会重新加载。 如果用户希望整个组件树只加载一次(即不关心内部条件分支,只希望整个组件第一次出现后即使被v-if隐藏再显示也不重新加载),那么可以这样: ```html <template> <div> <button @click="show = !show">切换</button> <keep-alive> <MyComponent v-if="show" /> </keep-alive> </div> </template> ``` 这样,当show从true变为false时,MyComponent被缓存,再次变为true时,从缓存恢复,不会重新加载。 所以,根据用户的具体需求,我们可以灵活运用keep-alive和v-if。 注意:v-show不能解决这个问题,因为v-show只是切换CSS,组件始终存在,不会被销毁,所以状态会保留。但是,如果用户希望组件在条件为false时从DOM中移除(节省DOM节点数量),但又希望再次显示时保留状态,那么就必须用v-if+keep-alive。 引用文献: [^2] 解释了v-if和v-show的区别,v-if会销毁组件,而v-show只是隐藏。 [^4] 展示了在vue2中相同组件在v-if切换时会重新渲染的问题,在Vue3中同样存在,解决方法就是使用keep-alive。 因此,我们通过使用keep-alive解决了v-if切换时组件重新加载的问题。</think>在 Vue3 中,使用 `v-if` 控制组件时避免重复渲染的关键是使用 `<keep-alive>` 组件配合合理的键值策略。以下是具体实现方案: ### 解决方案:`<keep-alive>` + 唯一键值 ```html <template> <keep-alive> <!-- 方案1:同一组件不同状态 --> <CommonForm v-if="showComponent" :formData="formData" :key="componentKey" <!-- 关键:使用唯一键值 --> /> <!-- 方案2:不同条件渲染同一组件 --> <template v-if="type === '1'"> <CommonForm :formData="{a:1}" key="type1" /> </template> <template v-else-if="type === '2'"> <CommonForm :formData="{b:2}" key="type2" /> </template> </keep-alive> </template> <script setup> import { ref, computed } from 'vue'; import CommonForm from './CommonForm.vue'; // 方案1:控制同一组件 const showComponent = ref(true); const formData = ref({ a: 1 }); const componentKey = computed(() => JSON.stringify(formData.value)); // 动态生成唯一键 // 方案2:不同条件渲染 const type = ref('1'); </script> ``` ### 核心原理说明 1. **`<keep-alive>` 的作用**: - 缓存被移除的组件实例(而不是销毁) - 再次渲染时直接复用缓存实例 - 避免重复执行 `created/mounted` 生命周期 - 保留组件内部状态(data、表单输入等) 2. **键值策略的重要性**: - 为同一组件的不同状态设置唯一键值(如 `key="type1"`) - 当键值改变时强制刷新组件(需要时) - 当键值不变时直接复用缓存实例 - 推荐使用数据特征生成键值:`:key="JSON.stringify(formData)"` 3. **与 `v-show` 的本质区别**: | 特性 | `v-if` + `<keep-alive>` | `v-show` | |--------------|----------------------------------|------------------------| | **DOM 状态** | 条件为假时移除 DOM | 始终存在(display:none)| | **内存占用** | 缓存组件实例 | 保持完整组件实例 | | **适用场景** | 需要保留状态的重型组件 | 轻量级频繁切换的组件 | | **生命周期** | 触发 activated/deactivated 钩子 | 无特殊钩子 | ### 高级用法:精确控制缓存 ```html <keep-alive :include="['CommonForm']" <!-- 只缓存指定组件 --> :max="3" <!-- 最大缓存实例数 --> > <component :is="currentComponent" :key="componentKey" /> </keep-alive> ``` ### 生命周期变化 ```javascript import { onActivated, onDeactivated } from 'vue'; // 组件激活时触发(从缓存恢复) onActivated(() => { console.log('组件从缓存恢复'); // 可在这里刷新数据 }); // 组件停用时触发(进入缓存) onDeactivated(() => { console.log('组件进入缓存'); }); ``` ### 注意事项 1. 当需要强制刷新组件时,可改变键值: ```javascript const refreshComponent = () => componentKey.value = Date.now(); ``` 2. 避免对大型组件使用 `<keep-alive>`,可能造成内存压力 3. 使用 `shallowRef` 避免组件对象被不必要地转为响应式: ```javascript const currentComponent = shallowRef(CommonForm); ``` > 此方案完美解决了 `v-if` 导致的组件重复渲染问题,同时保留了组件状态。在需要保留表单数据、避免重复请求等场景效果显著[^2][^4]。 --- ### 相关问题 1. `<keep-alive>` 缓存的组件如何强制刷新数据? 2. Vue3 中 `activated` 和 `deactivated` 生命周期有哪些使用技巧? 3. 如何限制 `<keep-alive>` 缓存的组件数量? 4. `v-show` 和 `<keep-alive>` 在性能优化上的本质区别是什么? 5. 动态组件和异步组件结合使用时需要注意什么?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值