在路线更改时更新 VueJs 组件

问题描述 投票:0回答:7

有没有办法在路由更改时重新渲染组件?我正在使用 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
  });
}
vue.js vuejs2 vue-component
7个回答
96
投票

您可能想向

<router-view>
添加 :key 属性,如下所示:

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

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


22
投票

更新 --- 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
属性。
最终你会得到两个值,即
to
from

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

17
投票

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

首先,你不应该自己打电话给

mounted()
。将您在
mounted
中所做的事情抽象为可以从
mounted
调用的方法。其次,Vue 将在可能的情况下尝试重用组件,因此您的主要问题可能是
mounted
只被触发一次。相反,您可以尝试使用
updated
beforeUpdate
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()
  }
}

这里有一个小例子,不是画 d3 的东西,而是展示当你交换路线时

mounted
updated
是如何被触发的。打开控制台,您将看到
mounted
只被触发一次。


2
投票

您可以使用此代码:

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

0
投票

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

产品详情.vue

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

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

当我在父组件

router-view
文件上添加
app.vue
上的键时

app.vue

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

现在对我来说效果很好。希望这会对 Vue 开发者有所帮助!


0
投票

我遇到了同样的问题,但略有不同。我刚刚在道具上添加了一个手表,然后在道具更改上重新启动了 fetch 方法。

import { ref, watch } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import Page  from './content/Page.vue';
import Post  from './content/Post.vue';

const props = defineProps({ pageSlug: String });
const pageData = ref(false);
const pageBodyClass = ref('');

function getPostContent() {
    let postRestEndPoint = '/wp-json/vuepress/v1/post/' + props.pageSlug;
    fetch(postRestEndPoint, { method: 'GET', credentials: 'same-origin' })
        .then(res => res.json())
        .then(res => {
            pageData.value = res;
            
        })
        .catch(err => console.log(err));
}
getPostContent();

watch(props, (curVal, oldVal) => {
    getPostContent();
});
watch(pageData, (newVal, oldVal) => { 
    if (newVal.hasOwnProperty('data') === true && newVal.data.status === 404) {
        pageData.value = false;
        window.location.href = "/404";
    }

    
    
});

路由器-index.js

       {
            path: "/:pageSlug",
            name: "Page",
            component: Page,
            props: true,
        },
        {
            path: "/product/:productSlug",
            name: "Product",
            component: Product,
        },
        {
            path: "/404",
            name: "404",
            component: Error404,
        }


0
投票

对组件进行包装,这将通过使用“key”属性强制重新加载原始组件。如果分配了唯一的“键”值,Vue 不会重用 DOM 的组件/部分。

例如,您有 UserList 组件,每次路由发生变化时,您都希望完全重新加载该组件(通过调用 onMounted)。

使用以下内容制作包装器 UserListRefresh

<script lang="ts" setup>
    import { useRoute } from "vue-router";
    import UsersList from "./UsersList.vue";
    const route=useRoute();
</script>

<template>
    <UsersList :key="route.fullPath"></UsersList>
</template>

现在将此 UserListRefresh 分配给路由而不是原始的 UserList。这样就可以解决问题,导航到具有不同 :groupId 部分的相同路径,您将看到该组件正在重建。

{
    path: "/administrative/users/:groupId",
    component: UsersListRefresh,
    name: 'UsersList',
    meta: {
        title: 'User List of Group',
    },
},
© www.soinside.com 2019 - 2024. All rights reserved.