Como definir parâmetros de consulta de URL no Vue com Vue-Router

114

Estou tentando definir parâmetros de consulta com Vue-router ao alterar os campos de entrada, não quero navegar para outra página, mas apenas modificar os parâmetros de consulta de url na mesma página, estou fazendo assim:

this.$router.replace({ query: { q1: "q1" } })

Mas isso também atualiza a página e define a posição y para 0, ou seja, rola para o topo da página. Esta é a maneira correta de definir os parâmetros de consulta de URL ou existe uma maneira melhor de fazer isso.


Editado:

Aqui está o código do meu roteador:

export default new Router({
  mode: 'history',
  scrollBehavior: (to, from, savedPosition)  => {
    if (to.hash) {
      return {selector: to.hash}
    } else {
      return {x: 0, y: 0}
    }
  },
  routes: [
    ....... 
    { path: '/user/:id', component: UserView },
  ]
})
Saurabh
fonte

Respostas:

132

Aqui está o exemplo em docs:

// with query, resulting in /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})

Ref: https://router.vuejs.org/en/essentials/navigation.html

Conforme mencionado nesses documentos, router.replacefunciona comorouter.push

Então, você parece ter acertado em seu código de amostra em questão. Mas acho que você pode precisar incluir o parâmetro nameou pathtambém, para que o roteador tenha alguma rota para navegar. Sem um nameou path, não parece muito significativo.

Este é meu entendimento atual agora:

  • query é opcional para o roteador - algumas informações adicionais para o componente construir a visão
  • nameou pathé obrigatório - ele decide qual componente mostrar em seu <router-view>.

Isso pode ser o que está faltando em seu código de amostra.

EDIT: detalhes adicionais após comentários

Você já tentou usar rotas nomeadas neste caso? Você tem rotas dinâmicas e é mais fácil fornecer parâmetros e consultas separadamente:

routes: [
    { name: 'user-view', path: '/user/:id', component: UserView },
    // other routes
]

e então em seus métodos:

this.$router.replace({ name: "user-view", params: {id:"123"}, query: {q1: "q1"} })

Tecnicamente, não há diferença entre o acima e this.$router.replace({path: "/user/123", query:{q1: "q1"}}), mas é mais fácil fornecer parâmetros dinâmicos em rotas nomeadas do que compor a string de rota. Mas em ambos os casos, os parâmetros de consulta devem ser levados em consideração. Em qualquer dos casos, não consegui encontrar nada de errado com a forma como os parâmetros de consulta são tratados.

Depois de estar dentro da rota, você pode buscar seus parâmetros dinâmicos como this.$route.params.ide seus parâmetros de consulta como this.$route.query.q1.

Mani
fonte
Tentei indicar o caminho também, mas não parava de rolar para o topo da página, editei a pergunta com as opções do roteador também, pode ser que haja alguma alteração necessária aí.
Saurabh
O seu parâmetro de consulta pretende rolar para o lugar certo no documento? Gostou da sua outra pergunta sobre tags âncora ?
Mani
Não, eu só quero adicionar o parâmetro de consulta na URL, não quero nenhum scroll aqui.
Saurabh
Acabei de testar as opções na minha configuração local, os parâmetros de consulta funcionam normalmente. Consigo navegar para uma nova rota e acessar os parâmetros de consulta, conforme mostrado na minha resposta atualizada. Então, o problema é - você não quer que ele role? Ou o problema é que todo o aplicativo está sendo atualizado novamente?
Mani
então estou na mesma página, quando seleciono alguma entrada, quero adicioná-la na URL, mas quando faço isso, acontece a rolagem. Rolar é o problema para mim. Não estou tentando navegar para outra página, apenas quero estar na mesma página e adicionar / modificar parâmetros de consulta de url sem problemas.
Saurabh
15

Sem recarregar a página ou atualizar o dom, history.pushStatepode fazer o trabalho.
Adicione este método em seu componente ou em outro lugar para fazer isso:

addParamsToLocation(params) {
  history.pushState(
    {},
    null,
    this.$route.path +
      '?' +
      Object.keys(params)
        .map(key => {
          return (
            encodeURIComponent(key) + '=' + encodeURIComponent(params[key])
          )
        })
        .join('&')
  )
}

Portanto, em qualquer lugar em seu componente, chame addParamsToLocation({foo: 'bar'})para enviar o local atual com parâmetros de consulta na pilha window.history.

Para adicionar parâmetros de consulta à localização atual sem empurrar uma nova entrada de histórico , use history.replaceState.

Testado com Vue 2.6.10 e Nuxt 2.8.1.

Cuidado com este método!
O Vue Router não sabe que o url mudou, então ele não reflete o url após pushState.

ManUtopiK
fonte
5
this.$router.push({ query: Object.assign(this.$route.query, { new: 'param' }) })
Boston Kenne
fonte
1
Gostei mais dessa resposta. Infelizmente, isso causaError: Avoided redundant navigation to current location
Max Coplan
Correção:this.$router.push({ query: Object.assign({...this.$route.query}, { new: 'param' }) })
Max Coplan
2
Mas agora que pensei sobre isso, você pode simplesmente fazerthis.$router.push({ query: {...this.$route.query,new: 'param'},) })
Max Coplan
3

Se você estiver tentando manter alguns parâmetros, enquanto altera outros, certifique-se de copiar o estado da consulta do roteador vue e não reutilizá-la.

Isso funciona, pois você está fazendo uma cópia sem referência:

  const query = Object.assign({}, this.$route.query);
  query.page = page;
  query.limit = rowsPerPage;
  await this.$router.push({ query });

enquanto abaixo irá fazer com que o Vue Router pense que você está reutilizando a mesma consulta e levará ao NavigationDuplicatederro:

  const query = this.$route.query;
  query.page = page;
  query.limit = rowsPerPage;
  await this.$router.push({ query });

Claro, você pode decompor o objeto de consulta, como a seguir, mas você precisa estar ciente de todos os parâmetros de consulta de sua página, caso contrário, você corre o risco de perdê-los na navegação resultante.

  const { page, limit, ...otherParams } = this.$route.query;
  await this.$router.push(Object.assign({
    page: page,
    limit: rowsPerPage
  }, otherParams));
);

Observe que, embora o exemplo acima seja para push(), ele também funciona com replace().

Testado com vue-router 3.1.6.

Andre M
fonte
3

Para adicionar vários parâmetros de consulta, isso é o que funcionou para mim (aqui https://forum.vuejs.org/t/vue-router-programmatically-append-to-querystring/3655/5 ).

uma resposta acima estava perto ... embora com Object.assign ele irá transformar este. $ route.query que não é o que você deseja fazer ... certifique-se de que o primeiro argumento é {} ao fazer Object.assign

this.$router.push({ query: Object.assign({}, this.$route.query, { newKey: 'newValue' }) });
Boris
fonte
2

Para definir / remover vários parâmetros de consulta de uma vez, acabei com os métodos abaixo como parte dos meus mixins globais ( thisaponta para o componente vue):

    setQuery(query){
        let obj = Object.assign({}, this.$route.query);

        Object.keys(query).forEach(key => {
            let value = query[key];
            if(value){
                obj[key] = value
            } else {
                delete obj[key]
            }
        })
        this.$router.replace({
            ...this.$router.currentRoute,
            query: obj
        })
    },

    removeQuery(queryNameArray){
        let obj = {}
        queryNameArray.forEach(key => {
            obj[key] = null
        })
        this.setQuery(obj)
    },
vírus
fonte
1

Eu normalmente uso o objeto de histórico para isso. Também não recarrega a página.

Exemplo:

history.pushState({}, '', 
                `/pagepath/path?query=${this.myQueryParam}`);
Mostafa
fonte
0

Esta é minha solução simples para atualizar os parâmetros de consulta na URL sem atualizar a página. Certifique-se de que funciona para o seu caso de uso.

const query = { ...this.$route.query, someParam: 'some-value' };
this.$router.replace({ query });
parker_codes
fonte