Skip to content

适配器 ​

适配器负责将 vue-qs 连接到 URL。每个应用通过插件安装且只安装一个适配器:

ts
import { createVueQs } from 'vue-qs';

app.use(createVueQs({ adapter }));
适配器导入路径适用场景
createVueRouterAdapter(router)vue-qs/adapters/vue-router使用 Vue Router 的应用、Nuxt
createHistoryAdapter()vue-qs/adapters/history不使用路由的应用
createTestingAdapter(options)vue-qs/adapters/testing单元测试
createAdapter(adapter)vue-qs其他任何场景

如果没有安装适配器,组合式函数会抛出一个说明清晰的错误。

Vue Router ​

ts
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
import { createVueQs } from 'vue-qs';
import { createVueRouterAdapter } from 'vue-qs/adapters/vue-router';

const router = createRouter({ history: createWebHistory(), routes });

createApp(App)
  .use(router)
  .use(createVueQs({ adapter: createVueRouterAdapter(router) }))
  .mount('#app');
  • 状态会跟随每一次导航:router.push({ query })、<RouterLink>、后退/前进。
  • URL 更新通过 router.replace / router.push 完成,并保留当前的路径、params、 hash 以及其他查询键。
  • 导航守卫可以取消或重定向一次更新,此时状态会跟随最终的 URL。
  • 通过 parseAsNativeArrayOf 支持重复的键(?id=1&id=2)。

Nuxt ​

Nuxt 使用 Vue Router,因此在插件中使用 Vue Router 适配器即可:

ts
// plugins/vue-qs.ts
import { createVueQs } from 'vue-qs';
import { createVueRouterAdapter } from 'vue-qs/adapters/vue-router';

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(createVueQs({ adapter: createVueRouterAdapter(useRouter()) }));
});

该插件在服务端会为每个请求单独运行,因此状态不会在请求之间共享。组合式函数在 SSR 期间读取请求的 URL,水合完成后再跟随客户端导航。

如需在服务端路由或中间件中读取查询参数,请使用 createLoader(英文)。

History API ​

适用于不使用路由的应用:

ts
import { createVueQs } from 'vue-qs';
import { createHistoryAdapter } from 'vue-qs/adapters/history';

app.use(createVueQs({ adapter: createHistoryAdapter() }));
  • URL 更新使用 history.replaceState / pushState,并保留路径和 hash。
  • 状态会跟随后退/前进(popstate),以及其他代码对 pushState / replaceState 的调用。
  • 在服务端,查询参数为空。

全局设置 ​

插件还接受一些设置,它们作用于使用该适配器的所有组合式函数:

ts
app.use(
  createVueQs({
    adapter: createVueRouterAdapter(router),
    // Defaults for URL update options, overridden by parser, composable and call options
    defaultOptions: { history: 'push', clearOnDefault: false },
    // Runs right before each URL update
    processUrlSearchParams: (search) => {
      search.sort(); // canonical key order
      return search;
    },
  })
);

defaultOptions 接受 history、scroll、shallow、clearOnDefault 和 limitUrlUpdates。processUrlSearchParams 接收即将写入的查询参数,可以修改后返回, 也可以返回新的查询参数。如果它抛出错误,这次更新会被丢弃,状态重新跟随 URL。 createSerializer 也接受同样的 processUrlSearchParams 选项。

为应用的一部分提供适配器 ​

在父组件的 setup 中使用 provideQueryAdapter(adapter, settings?),或使用 VueQsAdapter 组件,它通过 props(defaultOptions、processUrlSearchParams)接收设置:

vue
<script setup lang="ts">
import { VueQsAdapter } from 'vue-qs';
import { createHistoryAdapter } from 'vue-qs/adapters/history';

const adapter = createHistoryAdapter();
</script>

<template>
  <VueQsAdapter :adapter="adapter">
    <Widget />
  </VueQsAdapter>
</template>

在组件外使用组合式函数 ​

组合式函数需要注入上下文才能找到适配器。在 Pinia 的 setup store 中可以直接使用。 在其他地方,请使用 app.runWithContext,并配合 effectScope 在用完后停止监听:

ts
const scope = effectScope();
const page = app.runWithContext(() =>
  scope.run(() => useQueryState('page', parseAsInteger.withDefault(1)))
);
// later
scope.stop();

自定义适配器 ​

一个适配器需要实现三个函数:

ts
import { createAdapter } from 'vue-qs';

const adapter = createAdapter({
  // Return the current search params (do not mutate them)
  getSearchParams: () => new URLSearchParams(myStore.search),
  // Write the new search params; may return a promise
  updateUrl: (search, { history, scroll, shallow }) => {
    myStore.navigate(`?${search}`, { replace: history === 'replace' });
  },
  // Call onChange when the URL changes from outside; return an unsubscribe function
  subscribe: (onChange) => myStore.onChange(onChange),
});

如果 URL 没有接受某次更新(例如导航守卫取消或重定向了它),请让 updateUrl 返回或 resolve false。组合式函数随后会重新读取 URL,而不是保留被拒绝的值。

设置可选的 rateLimitFactor 可以缩放节流延迟(0 表示禁用节流)。

Released under the MIT License. Questions or ideas? Join the GitHub Discussions.