v-for里面數據層次太多,或者套的組件層級太多, 數據變了,頁面沒有重新渲染,需手動強制刷新。
解決方法:運用 this.$forceUpdate()強制刷新
迫使 Vue 實例重新渲染。注意它僅僅影響實例本身和插入插槽內容的子組件,而不是所有子組件。
-------------------------------------------------------------------------------------------------------------------------------------
vue強制重新渲染四種方案對比
前言
Vue的雙向綁定屬於自動檔;在特定的情況下,需要手動觸發“刷新”操作,目前有四種方案可以選擇:
- 刷新整個頁面(最low的,可以借助route機制,不推薦)
- 使用v-if標記(比較low的,有時候不生效,不推薦)
- 使用內置的forceUpdate方法(較好的)
- 使用key-changing優化組件(最好的)
一、刷新整個頁面
this.$router.go(0)
二、使用v-if標記
如果是刷新某個子組件,則可以通過v-if指令實現。我們知道,當v-if的值發生變化時,組件都會被重新渲染一遍。因此,利用v-if指令的特性,可以達到強制刷新組件的目的。
<template> <comp v-if="refresh"></comp> <button @click="refreshComp()">刷新comp組件</button> </template> <script> import comp from '@/views/comp.vue' export default { name: 'parentComp', data() { return { refresh: true } }, methods: { refreshComp() { // 移除組件 this.refresh = false // 在組件移除后,重新渲染組件 // this.$nextTick可實現在DOM 狀態更新后,執行傳入的方法。 this.$nextTick(() => { this.refresh = true }) } } } </script>
三、forceUpdate
組件內置$forceUpdate方法,如果不能強制刷新,嘗試使用前在配置中啟用。
import Vue from 'vue' Vue.forceUpdate()
<template> <div> <button @click="handleUpdateClick()">Refresh當前組件</button> </div> </template> export default { methods: { handleUpdateClick() { // built-in this.$forceUpdate() } } }
四、key-changing
原理很簡單,vue使用key標記組件身份,當key改變時就是釋放原始組件,重新加載新的組件。
<template> <div> <span :key="key"></span> </div> </template> <script> export default { data() { return { key: 0 } }, methods: { handleUpdateClick() { this.key += 1 // 或者 this.key = new Date(); } } } </script>
五、應用場景
vue具有緩存的頁面的強制刷新
有些列表頁面需要進入詳情返回時有緩存功能,但是每次進入列表頁面又需要刷新列表,這種時候就需要手動刷新頁面
const routerConfig = { path: "/List", query: { time: new Date().getTime(), } }; this.goPath(routerConfig);
List.vue created () { this.initData(); this.preTime = Number(this.$route.query.time); }, activated () { const curTime = Number(this.$route.query.time); if(this.preTime !== curTime) { document.documentElement.scrollTop = 0; this.preTime = curTime; this.listInfo = { pageSize: 10, pageContext: '', hasMore: false, list: [], }; this.initData(); } },
goPath是vue跳轉的一個封裝
main.js /** * 根據前端路由跳轉到webview * @param config * @param type inPage: 利用h5路由跳轉 */ Vue.prototype.goPath = function (routerConfig, type = 'web') { const config = routerConfig; // 統一添加參數 if (this.$route.query.isSelfManage === '1') { config.query.isSelfManage = 1; } console.log(config); if (window.__wxjs_environment === 'miniprogram') { if (window.wx) { const params = this.$router.resolve(config).href; // 添加參數,兼容跳轉問題 const toUrl = `${location.protocol}//${location.host}${location.pathname}${location.search}${params}`; if (type === 'web') { window.wx.miniProgram.navigateTo({ url: `/pages/webview/index?url=${encodeURIComponent(toUrl)}`, }); } else if (type === 'inPage') { this.$router.push(config); if (!config.replace) { this.$router.push(config); } else { this.$router.replace(config); } } else { window.wx.miniProgram.navigateTo(config); } } } else { if (!config.replace) { this.$router.push(config); } else { this.$router.replace(config); } } };
例如:進入頁面輸入框自動聚焦
一般情況下,加上以下代碼就可以聚焦
<template> <div> <input placeholder="大家都在搜" type="text" maxlength="500" v-model="inputInfo.msg" @blur="resizeView" v-focus > </div> </template> <script> export default { data() { return { inputInfo: { // 輸入框對象 num: 0, // 字數 msg: '' // 內容 }, } }, watch: { [`options.msg`] () { let length = utils.fancyCount2(this.inputInfo.msg); this.$set(this.inputInfo, 'num', length); } }, directives: { focus: { // 指令的定義 inserted: function(el) { el.focus(); } } }, methods: { /** * input元素失去焦點時觸發 */ resizeView () { document.body.scrollIntoView(true); }, } } </script>
但是在有緩存的頁面,一般就只有第一次會聚焦,后面進入都不會聚焦,辦法就是用第四種強制刷新輸入框來聚焦
<template> <div> <input placeholder="大家都在搜" type="text" maxlength="500" v-model="inputInfo.msg" @blur="resizeView" v-focus :key="inputInfo.focus" > <button @click="handleUpdateClick()">Refresh當前組件</button> </div> </template> <script> export default { data() { return { inputInfo: { // 輸入框對象 num: 0, // 字數 msg: '', // 內容 focus: '', }, } }, activated () { this.inputInfo.focus = new Date().getTime(); }, methods: { handleUpdateClick() { // built-in this.inputInfo.focus = new Date().getTime(); } } </script>