Тихо обновить URL-адрес без запуска маршрута в vue-router

Мне нужно обновить хеш URL-адреса, фактически не вызывая vue-router для перехода по этому маршруту. Что-то вроде:

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

Это обновит URL-адрес до .../#/my/new/path, но сам маршрутизатор не будет направлять по этому пути.

Есть ли элегантный способ добиться этого?


person Rinux    schedule 14.07.2018    source источник
comment
что случилось, когда вы использовали этот код?   -  person Niklesh Raut    schedule 14.07.2018
comment
Может быть, это проблема xy ..?   -  person Rainb    schedule 14.07.2018
comment
@ C2486 этот код - просто пример элегантного решения. К сожалению, вторым аргументом функции замены должен быть обратный вызов onComplete.   -  person Rinux    schedule 14.07.2018
comment
@Rainb, может быть. Мне нужно загрузить определенные страницы нашего старого приложения, изолированного в iframe в нашем новом приложении. При навигации в этом iframe хеш URL-адреса в верхнем окне должен быть обновлен, чтобы история работала правильно. Поскольку навигация уже выполняется в рамках iframe, сам маршрут не должен обновляться. После того, как пользователь фактически переместится с помощью адресной строки или с помощью функции «назад / вперед», компонент с iframe должен быть обновлен с использованием правильного URL-адреса. Я знаю, что есть некоторые красные флажки, но мне нужно использовать iframe, чтобы иметь возможность изолировать старое приложение.   -  person Rinux    schedule 14.07.2018


Ответы (4)


Маршрутизатор Vue либо включен, либо выключен, поэтому вы не можете «заставить его не обнаруживать определенные URL-адреса». Тем не менее, Vue повторно использует компоненты, если не нужно их уничтожать, и позволяет использовать псевдонимы для URL-адресов. Это позволяет вам использовать URL-адреса вашего приложения iframe в качестве псевдонимов в вашем маршруте и поддерживать работу одного и того же компонента в течение этого времени, предотвращая перезагрузку вашего 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/>"
});

В этом примере route1, route2, route3 и route4 будут обрабатываться так, как будто нужно загрузить route1, в результате чего ваш компонент Comp1 останется в живых.

Изменить  Шаблон Vue

person Sumurai8    schedule 14.07.2018
comment
Я не понимаю, как это отвечает на вопрос. Нет кода для обновления URL-адреса родительского окна, если URL-адрес внутри iframe изменяется. Нет кода для обновления маршрутизатора iframe, если URL-адрес родительского окна изменяется. - person jansolo; 10.12.2020
comment
@jansolo Требуемое поведение OP: (1) изменяется URL-адрес родительского объекта, (2) маршрутизатор vue не должен обновлять представление. Решением здесь является использование псевдонима, чтобы маршрутизатор Vue обрабатывал несколько URL-адресов как один и тот же маршрут. Этот вопрос не о том, как обновить дочерний iframe с помощью этой информации, а скорее о том, как избежать перезагрузки этого iframe при каждом изменении маршрута. - person Sumurai8; 11.12.2020

Без перезагрузки страницы и обновления 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-адрес изменился, поэтому он не отражает URL-адрес после pushState.

person ManUtopiK    schedule 20.06.2019
comment
Чтобы использовать этот подход с динамическим URL-адресом, вы можете использовать метод resolve(): const { href } = this.$router.resolve(route); window.history.pushState({}, null, href); - person Gustavo Gondim; 13.10.2020

если то, что вы пытаетесь сделать, это обновить URL-адрес, чтобы показать состояние страницы (возможно, что-то вроде ?search=something), вы можете сделать такой трюк. основная идея заключается в использовании переключателя this.respondToRouteChanges для игнорирования изменений, когда URL-адрес обновляется вашим кодом.

при обновлении маршрута (например, в методе 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 || '';
    },
person Tom Carchrae    schedule 04.03.2021

Я нашел, как Silently update url, но маршрут все равно срабатывает (но, возможно, это не проблема - зависит от ситуации).

В моем случае пользователь может создать профиль, например, через URL http://localhost:8080/#/user/create/, предоставить некоторую информацию о профиле, и после нажатия кнопки «Сохранить» пользователь перенаправляется на его / ее созданный профиль с URL-адресом, например 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 + router silently обновляет URL-адрес, повторно используя тот же компонент ProfileUser.

person TitanFighter    schedule 09.12.2019