为什么浏览器在路由/url 更改时显示缓存的 Vue.js 视图?

vol*_*one 2 vue.js vue-router

我有一个带有<router-link>查看标签的主页。这是一个简单的主/明细关系,其中Homepage是产品目录,Product明细页面/视图显示每个项目的信息。

当我第一次启动网站并单击Homepage视图上的一个项目(例如 URL: http://localhost:8080/100-sql-server-2019-licence)时,Product视图被加载并且产品详细信息加载正常。

如果我然后按浏览器中的后退按钮返回到Homepage,然后单击不同的Product(例如 URL: http://localhost:8080/101-oracle-12c-licence),则浏览器地址栏中的 URL 会更改,但我会获得以前产品的信息。它闪电般快速,并且没有完成新的网络调用,这意味着它只显示先前产品的缓存页面。如果我在该页面上点击刷新按钮,则会进行网络调用并显示正确的产品信息。

我在网上进行了搜索,但在搜索结果中找不到描述的这个问题。谁能指出我如何在路线更改时刷新/重新渲染路线的正确方向?

Tur*_*ght 6

怎么了

vue-router默认情况下将缓存您的组件。
因此,当您导航到第二个产品(可能呈现与第一个产品相同的组件)时,出于性能原因,将不会再次实例化该组件。

vue-router文档

例如,对于带有动态 params 的路由/foo/:id,当我们在/foo/1和之间导航时/foo/2Foo将重用相同的组件实例。

简单(但肮脏)的修复

解决这个问题的简单但不推荐的方法是给你<router-view />一个关键属性,例如:

<router-view :key="$route.fullPath" />
Run Code Online (Sandbox Code Playgroud)

这将强制vue-router每次 url 更改时重新实例化视图组件。
但是,您将失去通常从缓存中获得的所有性能优势。

清洁修复:正确处理路线变化

解决这个问题的清洁方式是在你的组件路由变化(主要是将此归结为移动ajax调用反应mounted到一个$route观察者),例如:

<script>
export default {
  data() {
    return {
      productDetails: null,
      loading: false
    };
  },
  watch: {
    '$route': {
      // with immediate handler gets called on first mount aswell
      immediate: true,
      // handler will be called every time the route changes.
      // reset your local component state and fetch the new data you need here.
      async handler(route) {
        this.loading = true;
        this.productDetails = null;
        try {
          // example for fetching your product data
          const res = await fetch("http://give.me.product.data/" + encodeURIComponent(route.params.id));
          this.productDetails = await res.json();
        } finally {
          this.loading = false;
        }
      }
    }
  }
};
</script>
Run Code Online (Sandbox Code Playgroud)

替代方案:导航卫士

或者,您也可以使用vue-routers In-Component Navigation Guards对路线更改做出反应:

<script>
export default {
  async beforeRouteUpdate (to, from, next) {
    // TODO: The route has changed.
    // The old route is in `from`, the new route in `to`.
    this.productData = await getProductDataFromSomewhere();

    // route will not change before you haven't called `next()`
    next();
  }
};
</script>
Run Code Online (Sandbox Code Playgroud)
  • 导航守卫的缺点是你只能直接在路由渲染的组件中使用它们。
    所以你不能在层次结构中更深的组件中使用导航守卫。
  • 好处是浏览器不会在您调用之前查看您的站点next(),这让您有时间在显示路线之前加载必要的数据。

一些有用的资源