【问题标题】:Silently update url without triggering route in vue-router在 vue-router 中静默更新 url 而不会触发路由
【发布时间】:2018-12-22 13:13:28
【问题描述】:

我需要更新 url 的哈希值,而不是真正触发 vue-router 去那个路由。类似的东西:

router.replace('my/new/path', {silent:true})

这会将 url 更新为 .../#/my/new/path,但路由器本身不会路由到该路径。

有没有优雅的方法来实现这一点?

【问题讨论】:

  • 当你使用这段代码时会发生什么?
  • 这可能是 xy 问题..?
  • @C2486 此代码只是一个优雅解决方案的示例。不幸的是,替换函数中的第二个参数应该是一个onComplete 回调。
  • @Rainb,可能是。我需要在新应用程序的 iframe 中加载旧应用程序的某些页面。在此 iframe 中导航时,顶部窗口中的 url 哈希应该更新,这样历史记录才能正常工作。由于导航已经在 iframe 中完成,因此不应更新路线本身。一旦用户实际使用地址栏或使用后退/前进导航,应使用正确的 url 更新带有 iframe 的组件。我知道,那里有一些危险信号,但我需要使用 iframe 才能对旧应用程序进行沙箱处理。

标签: vue.js vue-router


【解决方案1】:

无需重新加载页面或刷新 dom,history.pushState 就可以完成这项工作。
在你的组件或其他地方添加这个方法来做到这一点:

addHashToLocation(params) {
  history.pushState(
    {},
    null,
    this.$route.path + '#' + encodeURIComponent(params)
  )
}

因此,在组件中的任何位置,调用 addHashToLocation('/my/new/path') 以将当前位置与 window.history 堆栈中的查询参数一起推送。

要将查询参数添加到当前位置不推送新的历史记录条目,请改用history.replaceState

应该与 Vue 2.6.10 和 Nuxt 2.8.1 一起使用。

小心这种方法!
Vue Router 不知道 url 发生了变化,所以 pushState 后没有反映 url。

【讨论】:

  • 要将此方法与动态 URL 一起使用,您可以使用 resolve() 方法:const { href } = this.$router.resolve(route); window.history.pushState({}, null, href);
【解决方案2】:

Vue 路由器要么打开要么关闭,所以你不能“让它不检测某些 url”。也就是说,如果 Vue 不需要销毁组件并允许您为 url 起别名,它会重用组件。这允许您将 iframe 应用程序中的 url 作为路由中的别名,并在此期间保持相同的组件处于活动状态,从而防止您的 iframe 重新加载。

// router.js
import Comp1 from "./components/Comp1";
import Comp2 from "./components/Comp2";

export default [
  {
    path: "/route1",
    component: Comp1,
    alias: ["/route2", "/route3", "/route4"]
  },
  {
    path: "/otherroute",
    component: Comp2
  }
];
// main.js
import Vue from "vue";
import App from "./App";
import VueRouter from "vue-router";
import routes from "./router";

Vue.config.productionTip = false;
Vue.use(VueRouter);

const router = new VueRouter({
  routes
});

/* eslint-disable no-new */
new Vue({
  el: "#app",
  router,
  components: { App },
  template: "<App/>"
});

在此示例中,route1route2route3route4 都将被视为必须加载 route1,从而使您的组件 Comp1 保持活动状态。

【讨论】:

  • 我不明白这是如何回答这个问题的。如果 iframe 内的 url 发生变化,则没有更新父窗口 url 的代码。如果父 windows url 发生变化,则没有更新 iframe 路由器的代码。
  • @jansolo OP想要的行为是:(1)父级的url更改,(2)vue路由器不应该更新视图。这里的解决方案是使用别名,以便 Vue 路由器将多个 url 视为同一路由。这个问题不是关于如何使用该信息更新子 iframe,而是如何避免在每次路由更改时重新加载该 iframe。
【解决方案3】:

如果您尝试更新 url 以显示页面状态(可能类似于 ?search=something),那么您可以使用这样的技巧。关键思想是使用切换this.respondToRouteChanges 在您的代码更新网址时忽略更改。

更新路由时(例如,在组件中的 vue 方法中)

          this.respondToRouteChanges = false;
          this.$router.replace({query: { search: this.search })
              .finally(() => {
                this.respondToRouteChanges = true;
              });

以及在通常会监视/处理路由更改的组件代码中

    setSearch() {
      if (!this.respondToRouteChanges){
        // console.log('ignoring since route changes ignored')
        return;
      }
      if (this.search !== this.querySearch)
        this.search = this.querySearch;
    },

  watch: {
     // watch for changes in the url
    'querySearch': 'setSearch',

注意respondToRouteChanges 只是在组件中定义为data() 的布尔值

  data() {
    return {
      respondToRouteChanges: true,
      ...

querySearch 只是一个返回路由的计算值

    querySearch() {
      return this.$route.query.search || '';
    },

【讨论】:

  • this.$router.replace({query: { search: this.search }) 无论如何都不会触发重定向...似乎只是 URL 路径的变化。
  • @foobored - 没有重定向,这是关于 vue-router 的调用。 router.vuejs.org/guide/essentials/…
  • 你是对的 - 感谢您指出这一点。这应该是公认的答案。也许将“在通常会监视/处理更改路由的组件代码中”替换为不那么通用,而更像一个路由器保护示例,例如“在 router.beforeEach / component.beforeRouteUpdate 中”
  • 它当然可以是一个路由器保护,但是,因为这会覆盖默认行为,我认为将它添加到特定组件可能更安全(最不意外的原则)。如果您需要为许多组件执行此操作,那么将其放入路由器中会更有说服力。
  • 另外,我不确定你是否想要一个组件来控制路由器中的一些“respondToRouteChanges”标志——这在状态/责任方面似乎有点混乱。
【解决方案4】:

我找到了Silently update url 的方法,但无论如何都会触发路由(但这可能不是问题 - 取决于具体情况)。

在我的情况下,用户可以创建个人资料,例如通过 URL http://localhost:8080/#/user/create/,提供一些个人资料信息,一旦单击“保存”,用户就会被重定向到他/她创建的个人资料,网址为 http://localhost:8080/#/FaFYhTW9gShk/,其中用户可以继续编辑个人资料表单。

我该怎么做?

  1. user/create/ 页面 (ProfileCreate) 和 FaFYhTW9gShk/ 页面 (ProfileDetails) 使用相同的 ProfileUser 组件。
// router.js
const routes = [
    {
        path: '/user/create',
        component: Profile,
        children: [
            {
                path: '',
                name: 'ProfileCreate',
                component: ProfileUser
            }
        ]
    }
    { path: '/:profileUrl',
        component: Profile,
        children: [
            {
                path: '',
                name: 'ProfileDetails',
                component: ProfileUser
            }
        ]
    }
]

  1. router.beforeEach 中,我检查是否需要从后端加载数据,还是只需要更改 URL?
// router.js
router.beforeEach((to, from, next) => {
    if (!('isProfileLoaded' in to.params)) {
        // load profile from backend and update Vuex
    }

  next()
})
  1. 当点击“保存”按钮时,在action我发送数据到后端+调用router.push
// action.js
import router from '@/router'

// Here I send data to backend
// Some code

// Update-URL-Trick
router.push({
    name: 'ProfileDetails',
    params: { profileUrl: profileUrl isProfileLoaded: true }
})

就提供isProfileLoaded 而言,Vue 重复使用来自 Vuex 的配置文件数据 + 路由器 silently 更新 URL 重复使用相同的 ProfileUser 组件。

【讨论】:

    猜你喜欢
    • 2018-01-02
    • 1970-01-01
    • 1970-01-01
    • 2019-06-23
    • 2013-12-17
    • 1970-01-01
    • 2018-12-13
    • 2020-10-14
    • 2018-03-27
    相关资源
    最近更新 更多