在 vue-router 中静默更新 url 而不会触发路由

Posted

技术标签:

【中文标题】在 vue-router 中静默更新 url 而不会触发路由【英文标题】:Silently update url without triggering route in vue-router 【发布时间】: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 才能对旧应用程序进行沙箱处理。 【参考方案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/,其中用户可以继续编辑个人资料表单。

我该怎么做?

    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
            
        ]
    
]

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

  next()
)
    当点击“保存”按钮时,在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 组件。

【讨论】:

以上是关于在 vue-router 中静默更新 url 而不会触发路由的主要内容,如果未能解决你的问题,请参考以下文章

Vue-router

微端热更新

vue-router 不渲染组件,但在 this.$router.push 上更改 url

如何在 React Router v5 中更新 URL 并替换历史状态而不重新渲染整个应用程序?

使用新 URL 更新地址栏而不使用哈希或重新加载页面 [重复]

使 django url 标签静默失败