【问题标题】:你能强制 Vue.js 重新加载/重新渲染吗?
【发布时间】:2015-11-13 09:09:58
【问题描述】:

只是一个简单的问题。

你能强制Vue.js重新加载/重新计算一切吗?如果有,怎么做?

【问题讨论】:

  • 这里可能会得到更好的支持github.com/vuejs/Discussion/issues
  • 太好了,不知道那个讨论的地方。我去那边试试。
  • 您最终收到回复了吗?我也很想知道。
  • 不记得了。但这是我用一些线索打开的问题:github.com/vuejs/Discussion/issues/356
  • 我在视图中有 v-for 指令,并且当我手动交换该数组上的两个对象时有用例。在此之后 Vue 不会自动重新渲染模板。我使用了解决方法:只需对这个数组执行任何操作(推送空对象然后拼接)——这会触发重新渲染。但这是特例。

标签: javascript vue.js frontend reload rerender


【解决方案1】:

试试这个魔法:

vm.$forceUpdate();

无需创建任何悬挂变量 :)

更新:我刚开始使用 VueJS 时发现了这个解决方案。然而,进一步的探索证明这种方法是一种拐杖。据我回忆,有一段时间我摆脱了它,只是将所有无法自动刷新的属性(主要是嵌套属性)放入计算属性中。

更多信息在这里:https://vuejs.org/v2/guide/computed.html

【讨论】:

  • 当我在 Vue 中将它与表单向导组件一起使用时,这真的帮助了我。尽管数据变量完好无损,但我的表单字段字段正在丢失状态。现在我用它来刷新视图,当我回去的时候,我不得不把它放在 setTimeout 函数中。
  • 注意在vue文件中你需要'this.$forceUpdate();'
  • 这非常适合在长时间的 axios 调用后更新。
  • 以某种绝对奇怪的方式$forceUpdate() 在 2.5.17 上从来没有为我工作过。
  • @AbanaClara $forceUpdate() 从来都不是公共方法,我发现它在挖掘 Vue 的源代码。而且由于它的使用从来都不是 Vue'ing 的正确方式,也许它可以被剥离。不能确定它是否仍然存在,因为我不再做前端了。
【解决方案2】:

这似乎是来自matthiasg this issue 的一个非常干净的解决方案:

您也可以使用:key="someVariableUnderYourControl" 并在您想要完全重建组件时更改密钥

对于我的用例,我将 Vuex getter 作为道具提供给组件。 Vuex 会以某种方式获取数据,但反应性并不能可靠地重新渲染组件。就我而言,将组件 key 设置为 prop 上的某个属性可确保在 getter(和属性)最终解析时刷新。

【讨论】:

  • 这是一个巧妙的小技巧,它基本上强制重新实例化组件(mounted 将运行等)
  • @btk 我同意,这可能不是“正确”的做事方式,但它是一个相当干净的 hack,就其本身而言。
  • 这很有帮助。当路由发生变化时,我使用路由完整路径作为重新渲染相同组件的关键。 :key="$route.fullPath"
  • 这是正确的答案,尤其是关于 vuex 状态和 vue 路由器。
【解决方案3】:

请阅读本文 http://michaelnthiessen.com/force-re-render/

可怕的方式:重新加载整个页面
可怕的方式: 使用 v-if hack
更好的方法:使用 Vue 的内置 forceUpdate 方法
最好的方法:在你的 组件

<template>
   <component-to-re-render :key="componentKey" />
</template>

<script>
 export default {
  data() {
    return {
      componentKey: 0,
    };
  },
  methods: {
    forceRerender() {
      this.componentKey += 1;  
    }
  }
 }
</script>

在某些情况下,我也使用 watch:。

【讨论】:

  • 该链接实际上并没有显示如何以可怕的方式做到这一点,不幸的是,这是我所需要的,因为我的应用程序是围绕着可怕的方式设计的。当前页面的简单 URL 似乎不起作用,至少在我正在处理的应用程序中不起作用,所以我实际上需要有关如何以可怕的方式进行操作的说明。
  • 对我来说,Michael Thiessen 的小费是最好的。
【解决方案4】:

为什么?

...您需要强制更新吗?

也许你没有在最好的状态下探索 Vue:

要让 Vue自动对值的变化做出反应,对象必须data中进行初始声明。或者,如果没有,则必须使用Vue.set() 添加。

在下面的演示中查看 cmets。或者打开same demo in a JSFiddle here

new Vue({
  el: '#app',
  data: {
    person: {
      name: 'Edson'
    }
  },
  methods: {
    changeName() {
      // because name is declared in data, whenever it
      // changes, Vue automatically updates
      this.person.name = 'Arantes';
    },
    changeNickname() {
      // because nickname is NOT declared in data, when it
      // changes, Vue will NOT automatically update
      this.person.nickname = 'Pele';
      // although if anything else updates, this change will be seen
    },
    changeNicknameProperly() {
      // when some property is NOT INITIALLY declared in data, the correct way
      // to add it is using Vue.set or this.$set
      Vue.set(this.person, 'address', '123th avenue.');
      
      // subsequent changes can be done directly now and it will auto update
      this.person.address = '345th avenue.';
    }
  }
})
/* CSS just for the demo, it is not necessary at all! */
span:nth-of-type(1),button:nth-of-type(1) { color: blue; }
span:nth-of-type(2),button:nth-of-type(2) { color: red; }
span:nth-of-type(3),button:nth-of-type(3) { color: green; }
span { font-family: monospace }
<script src="https://unpkg.com/vue"></script>

<div id="app">
  <span>person.name: {{ person.name }}</span><br>
  <span>person.nickname: {{ person.nickname }}</span><br>
  <span>person.address: {{ person.address }}</span><br>
  <br>
  <button @click="changeName">this.person.name = 'Arantes'; (will auto update because `name` was in `data`)</button><br>
  <button @click="changeNickname">this.person.nickname = 'Pele'; (will NOT auto update because `nickname` was not in `data`)</button><br>
  <button @click="changeNicknameProperly">Vue.set(this.person, 'address', '99th st.'); (WILL auto update even though `address` was not in `data`)</button>
  <br>
  <br>
  For more info, read the comments in the code. Or check the docs on <b>Reactivity</b> (link below).
</div>

要掌握这部分 Vue,请查看Official Docs on Reactivity - Change Detection Caveats。必读!

【讨论】:

  • 绝对同意您应该质疑这一刷新要求,但有时您只需要重新渲染 UI,因为视口已更改并且您需要显示不同的资产(例如)。数据实际上可能没有改变。
  • 为什么需要重新加载?在某些情况下,浏览器缓存的资源文件(样式表/js)需要在一段时间后重新加载。我有一个样式表需要在 7 天后重新加载,如果用户保持打开一个带有页面访问权限的选项卡并在 7 天后返回浏览该页面,则 css 已经超过 7 天了。
  • @AchielVolckaert 您可能已经找到了答案,但是是的,Vue.set() 也适用于组件。
  • @the_dude_abides 和 @Aurovrata,我同意这些是刷新的合法用途。我提出的问题是,人们经常出于错误的原因进行提神。
  • 也许你只是想修复一个设计不佳的 web 应用程序中的一个错误,它纯粹使用 vue 作为渲染工具,例如,每当它进入服务器时都会重新加载整个应用程序,而忽略客户端vue的侧应用能力。在现实世界中,你并不总是有时间修复你发现的每一个可憎的东西。
【解决方案5】:

尝试使用this.$router.go(0);手动重新加载当前页面。

【讨论】:

  • 更简单:this.$router.go()
  • 实际上@MariusAndreiana - .go() 函数需要 1 个非可选参数
【解决方案6】:

使用vm.$set('varName', value)。详情请到Change_Detection_Caveats

【讨论】:

    【解决方案7】:

    当然..您可以随时使用 key 属性强制重新渲染(重新创建)。

    &lt;mycomponent :key="somevalueunderyourcontrol"&gt;&lt;/mycomponent&gt;

    请参阅https://jsfiddle.net/mgoetzke/epqy1xgf/ 了解示例

    这里也讨论过:https://github.com/vuejs/Discussion/issues/356#issuecomment-336060875

    【讨论】:

      【解决方案8】:
      <my-component :key="uniqueKey" />
      

      同时使用this.$set(obj,'obj_key',value) 并为对象(obj)值中的每个更新更新uniqueKey 每次更新this.uniqueKey++

      这种方式对我有用

      【讨论】:

        【解决方案9】:

        所以有两种方法可以做到这一点,

        1. 您可以在方法处理程序中使用$forceUpdate(),即

        &lt;your-component @click="reRender()"&gt;&lt;/your-component&gt;

        <script>
        export default {
           methods: {
             reRender(){
                this.$forceUpdate()
             }
           }
        }
        </script>
        
        1. 您可以为组件赋予:key 属性,并在需要重新渲染时递增

        &lt;your-component :key="index" @click="reRender()"&gt;&lt;/your-component&gt;

        <script>
        export default {
           data() {
             return {
                index: 1
             }
           },
           methods: {
             reRender(){
                this.index++
             }
           }
        }
        </script>
        

        【讨论】:

          【解决方案10】:

          为了重新加载/重新渲染/刷新组件,请停止长编码。有一种 Vue.JS 方法可以做到这一点。

          只需使用:key 属性。

          例如:

          <my-component :key="unique" />
          

          我在 BS Vue Table Slot 中使用那个。告诉我会为这个组件做点什么,所以让它独一无二。

          【讨论】:

            【解决方案11】:

            使用 v-if 指令

            <div v-if="trulyvalue">
              <component-here />
            </div>
            

            所以简单地把truevalue的值从false改成true就会导致div之间的组件再次重​​新渲染

            【讨论】:

            • 在我看来这是重新加载组件的最干净的方式。在 created() 方法中,你可以添加一些初始化的东西。
            【解决方案12】:

            这对我有用。

            created() {
                EventBus.$on('refresh-stores-list', () => {
                    this.$forceUpdate();
                });
            },
            

            其他组件触发 refresh-stores-list 事件会导致当前组件重新渲染

            【讨论】:

            • EventBus 究竟从何而来?它不存在。
            【解决方案13】:

            我找到了办法。这有点 hacky 但很有效。

            vm.$set("x",0);
            vm.$delete("x");
            

            vm 是您的视图模型对象,x 是不存在的变量。

            Vue.js 会在控制台日志中抱怨这一点,但它确实会触发所有数据的刷新。使用版本 1.0.26 测试。

            【讨论】:

              【解决方案14】:

              为我工作

                  data () {
                      return {
                          userInfo: null,
                          offers: null
                      }
                  },
              
                  watch: {
                      '$route'() {
                          this.userInfo = null
                          this.offers = null
                          this.loadUserInfo()
                          this.getUserOffers()
                      }
                  }
              

              【讨论】:

                【解决方案15】:
                <router-view :key="$route.params.slug" />
                

                只需将 key 与您的任何参数一起使用它的自动重新加载子项..

                【讨论】:

                • 尝试提供有关您的解决方案的详细信息。添加您的代码,突出显示关键字
                • 谢谢,这对我有用。当使用子路由并且你想根据不同的路由重新加载内容时很方便。
                【解决方案16】:

                添加此代码:

                this.$forceUpdate()
                

                【讨论】:

                • 如果您需要重新触发实际的路由,这将不起作用,这会触发路由保护中的数据获取,以获取 vue-router 插入的组件属性的数据。
                【解决方案17】:

                2021 年 12 月更新:

                您可以通过添加 :key="$route.fullPath" 来强制重新加载组件。

                对于组件:

                <Child :key="$route.fullPath" />
                

                对于router-view标签:

                <router-view :key="$route.fullPath" />
                

                但是,:key="$route.fullPath" 只能强制重载不同路由的组件,不能强制重载同一路由的组件。为了能够强制重新加载同一路由的组件,我们需要将"value"与数组添加到:key="$route .fullPath"更改“值”。所以它变成了:key="[$route.fullPath, value]",我们需要改变“value”

                *我们可以将 Array 分配给 :key=

                <template>
                  <Child 
                    :key="[$route.fullPath, value]" // Can assign "Array" to ":key="
                    @childReload="reload" // Call @click="$emit('childReload')" in   
                  />                      // Child Component to increment the value.
                </template> 
                
                    OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR
                
                <template>
                  <router-view 
                    :key="[$route.fullPath, value]" // Can assign "Array" to ":key="
                    @routerViewReload="reload" // Call @click="$emit('routerViewReload')"
                  />                           // in Child Component to increment the value.
                </template>
                    
                <script>
                export default {
                  name: "Parent", components: { Child, },
                  data() {
                    return {
                      value: 0,
                    };
                  },
                  methods: {
                    reload() {
                      this.value++;
                    }
                  }
                }
                </script>
                

                但是,要同时使用 "$route.fullPath" 和 "value" 有时会导致一些错误,所以只有当像 Click 这样的事件发生时,我们才会同时使用 “$route.fullPath” 和 “value”。除了像 Click 这样的事件发生时,我们总是只需要使用 "$route.fullPath"

                这是最终代码:

                <template>
                  <Child 
                    :key="state ? $route.fullPath : [$route.fullPath, value]"
                    @childReload="reload" // Call @click="$emit('childReload')" in
                  />                      // Child Component to increment the value.
                </template>
                    
                    OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR
                    
                <template>
                  <router-view 
                    :key="state ? $route.fullPath : [$route.fullPath, value]"
                    @routerViewReload="reload" // Call @click="$emit('routerViewReload')" in
                  />                           // Child Component to increment the value.
                </template>
                        
                <script>
                export default {
                  name: "Parent", components: { Child, },
                  data() {
                    return {
                      state: true,
                      value: 0,
                    };
                  },
                  methods: {
                    reload() {
                      this.state = false;
                      this.value++;
                      this.$nextTick(() => this.state = true);
                    }
                  }
                }
                </script>
                

                不幸的是,没有简单的方法可以在 Vue 中正确地强制重新加载组件。这就是目前 Vue 的问题。

                【讨论】:

                  【解决方案18】:

                  :key 添加到 vue-router lib 的 router-view 组件的方法对我来说是个问题,所以我使用 vue-router 的“组件内保护”来拦截更新并在有更新时相应地刷新整个页面同一条路线上的路径(因为 $router.go、$router.push、$router.replace 没有任何帮助)。唯一需要注意的是,我们将通过刷新页面来打破单页应用程序的行为。

                    beforeRouteUpdate(to, from, next) {
                      if (to.path !== from.path) {
                        window.location = to.path;
                      }
                    },
                  

                  【讨论】:

                    【解决方案19】:

                    除了页面重新加载方法(闪烁),它们都不适合我(:key 不起作用)。

                    我从旧的 vue.js 论坛找到了这个方法,它对我有用:

                    https://github.com/vuejs/Discussion/issues/356

                    <template>
                        <div v-if="show">
                           <button @click="rerender">re-render</button>
                        </div>
                    </template>
                    <script>
                        export default {
                            data(){
                                return {show:true}
                            },
                            methods:{
                                rerender(){
                                    this.show = false
                                    this.$nextTick(() => {
                                        this.show = true
                                        console.log('re-render start')
                                        this.$nextTick(() => {
                                            console.log('re-render end')
                                        })
                                    })
                                }
                            }
                        }
                    </script>
                    

                    【讨论】:

                      猜你喜欢
                      • 2014-07-27
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2015-08-18
                      • 2016-05-12
                      • 2014-04-20
                      • 2017-05-08
                      • 2017-11-13
                      相关资源
                      最近更新 更多