【问题标题】:Update VueJs component on route change在路由更改时更新 VueJs 组件
【发布时间】:2017-09-13 16:26:46
【问题描述】:

有没有办法在路由更改时重新渲染组件?我正在使用 Vue Router 2.3.0,并且在多个路由中使用相同的组件。它第一次运行良好,或者如果我导航到不使用该组件的路线然后转到使用该组件的路线。我正在传递像这样的道具有什么不同

{
  name: 'MainMap',
  path: '/',
  props: {
    dataFile: 'all_resv.csv',
    mapFile: 'contig_us.geo.json',
    mapType: 'us'
  },
  folder: true,
  component: Map
},
{
  name: 'Arizona',
  path: '/arizona',
  props: {
    dataFile: 'az.csv',
    mapFile: 'az.counties.json',
    mapType: 'state'
  },
  folder: true,
  component: Map
}

然后我使用道具来加载新地图和新数据,但地图保持与首次加载时相同。我不确定发生了什么。

组件如下所示:

data() {
  return {
    loading: true,
    load: ''
  }
},

props: ['dataFile', 'mapFile', 'mapType'],

watch: {
    load: function() {
        this.mounted();
    }
},

mounted() {
  let _this = this;
  let svg = d3.select(this.$el);

  d3.queue()
    .defer(d3.json, `static/data/maps/${this.mapFile}`)
    .defer(d3.csv, `static/data/stations/${this.dataFile}`)
    .await(function(error, map, stations) {
    // Build Map here
  });
}

【问题讨论】:

  • 显示组件?
  • 还有,什么路由器版本?
  • @BertEvans 我已经用组件和 vue 路由器版本更新了问题。谢谢

标签: vue.js vuejs2 vue-component


【解决方案1】:

此问题的替代解决方案在更多情况下可以处理这种情况。

首先,你真的不应该自己打电话给mounted()。将您在mounted 中所做的事情抽象为您可以从mounted 调用的方法。其次,Vue 将尽可能重用组件,因此您的主要问题可能是 mounted 只被触发一次。相反,您可以尝试使用 updatedbeforeUpdate lifecycle 事件。

const Map = {
  data() {
    return {
      loading: true,
      load: ''
    }
  },
  props: ['dataFile', 'mapFile', 'mapType'],
  methods:{
    drawMap(){
        console.log("do a bunch a d3 stuff")
    }
  },
  updated(){
    console.log('updated')
    this.drawMap()
  },
  mounted() {
    console.log('mounted')
    this.drawMap()
  }
}

这是一个little example,不是绘制 d3 的东西,而是显示当你交换路由时mountedupdated 是如何被触发的。打开控制台,你会看到mounted 只被触发过一次。

【讨论】:

  • 但是当一起使用mounted和update,并且有axios http请求时,会重复发送请求。 (对不起英文)
  • 我同意上面的@FarshidRezaei:如果您在updated() 中放入http 请求,那么该请求返回的数据肯定会更改(或更新)组件数据,这将再次触发updated() 并导致一个无限循环。
  • 那么解决办法是什么?我对 axios 也有同样的问题
  • @qwertzuiop 答案如下。是解决这个问题的更好方法。我会删除这个答案,但它被接受了,我现在不能。
【解决方案2】:

您可能希望像这样向<router-view> 添加一个 :key 属性:

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

这样,一旦路径发生变化,Vue Router 就会重新加载组件。如果没有密钥,它甚至不会注意到发生了一些变化,因为正在使用相同的组件(在您的例子中是 Map 组件)。

【讨论】:

  • 这可行,但效率可能很低。假设您移动地图并将 URL 更改为 gps 坐标...这将刷新整个组件,每次。
  • 有没有对应这个问题的github issue?
  • 简单的解决方案,完美
  • 我讨厌这是最好的答案,但这是一个很好的答案,除了@RayFoss 提到的缺点。
  • 就我而言,我确实在组件/foo/1/foo/2 的两个不同实例之间导航,因此我需要真正刷新整个组件。所以谢谢你。
【解决方案3】:

更新 --- 2019 年 7 月 3 日

我在vue-router 文档中找到了这个东西,它叫做In Component Guards。根据它的描述,它确实适合您的需求(实际上也是我的需求)。所以代码应该是这样的。

export default () {
  beforeRouteUpdate (to, from, next) {
    // called when the route that renders this component has changed,
    // but this component is reused in the new route.
    // For example, for a route with dynamic params `/foo/:id`, when we
    // navigate between `/foo/1` and `/foo/2`, the same `Foo` component instance
    // will be reused, and this hook will be called when that happens.
    // has access to `this` component instance.
    
    const id = to.params.id
    this.AJAXRequest(id)
    next()
  },
}

如您所见,我只是添加了一个next() 函数。希望这对你有帮助!祝你好运!


以下是我的旧答案。
仅出于“进步”的目的而保存

我对这个问题的解决方案是查看$route 属性。
最终你会得到两个值,即tofrom

watch: {
  '$route'(to, from) {
    const id = to.params.id
    this.AJAXRequest(id)
  }
},

【讨论】:

  • 我试过了,但它似乎不起作用,我想是因为我已经更改了路由配置并使用了 vue-cli-plugin-ssr 。我可以访问路由配置中的 beforeEach 挂钩。有没有办法可以专门针对我的组件并更改其 data() 属性之一?
  • 你好@SearchingSolutions。嗯..我从未使用过vue-cli-plugin-ssr,我认为您应该创建新问题。因为您的案例可能与当前问题不同但相似。我也没有找到任何关于 beforeRouteUpdate 和您正在使用的插件的信息(但那是因为我只是快速浏览了一下)。
  • 这种方式比keyhacky方式好很多。
  • 是的@AbdallaArbab,key hacky 方式实际上会触发整个生命周期钩子,每次$route.fullPath 这包括查询字符串和动态值的变化等变化时都会渲染整个孩子。查看有关key 的官方文档以了解更多信息。
  • 最佳答案,比 中发送的低效“key”方法好多了 谢谢!
【解决方案4】:

是的,我遇到了同样的问题,通过以下方式解决了;

ProductDetails.vue

 data() {
    return {
       ...
       productId: this.$route.params.productId,
       ...
     };
   },
 methods: {
  ...mapActions("products", ["fetchProduct"]),
  ...
 },
created() {
    this.fetchProduct(this.productId);
...
}

fetchProduct 函数来自Vuex 商店。当点击另一个产品时,路由参数由productId 更改,但component 不会重新渲染,因为created 生命周期挂钩在初始化阶段执行。

当我在父组件 app.vue 文件上添加 router-view 上的键时

app.vue

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

现在它对我很有效。希望这对 Vue 开发者有所帮助!

【讨论】:

    【解决方案5】:

    您可以只使用以下代码:

      watch: {
        $route(to, from) {
          // react to route changes...
        }
      }
    

    【讨论】:

      猜你喜欢
      • 2018-02-20
      • 2018-01-05
      • 1970-01-01
      • 1970-01-01
      • 2017-07-04
      • 2020-08-14
      • 2017-06-10
      • 1970-01-01
      • 2021-04-06
      相关资源
      最近更新 更多