在Vue项目开发中,不同路由页面之间的数据传递和状态同步是高频需求,比如从列表页跳转详情页传递ID,或者页面A操作后让页面B实时更新。本文基于实际开发场景,梳理三种最实用的跨页面通信方式:路由参数传递(query/params)、全局状态管理(Pinia/Vuex)、本地存储(localStorage/sessionStorage),覆盖Vue2和Vue3,每个方案均附带完整可运行的Demo代码与关键注意事项。
一、路由参数传递(页面跳转传值首选)
适用场景:列表页→详情页传递简单ID、名称等轻量数据,或传递敏感临时数据。分为 query 和 params 两种方式,按需选择。
1. query参数(路径可见,刷新不丢失)
优点:参数直接显示在URL中(如 /pageB?id=123),刷新页面仍保留,适合非敏感数据。
Vue3完整示例(组合式API):- // 路由配置(router/index.js)
- import { createRouter, createWebHistory } from 'vue-router';
- import PageA from '@/views/PageA.vue';
- import PageB from '@/views/PageB.vue';
- const routes = [
- { path: '/pageA', name: 'PageA', component: PageA },
- { path: '/pageB', name: 'PageB', component: PageB }
- ];
- const router = createRouter({
- history: createWebHistory(),
- routes
- });
- export default router;
复制代码- // 页面A(跳转方,@/views/PageA.vue)
- <template>
- <div>
- <h3>页面A</h3>
- <router-link :to="{ path: '/pageB', query: { id: 123, name: 'Vue跨页面通信Demo' } }" class="btn">
- 点击跳转页面B(router-link)
- </router-link>
- <button @click="goToPageB" class="btn">点击跳转页面B(编程式)</button>
- </div>
- </template>
- <script setup>
- import { useRouter } from 'vue-router';
- const router = useRouter();
- const goToPageB = () => {
- router.push({
- path: '/pageB',
- query: { id: 123, name: 'Vue跨页面通信Demo' }
- });
- };
- </script>
- <style scoped>
- .btn { margin: 0 10px; padding: 6px 12px; cursor: pointer; }
复制代码- // 页面B(接收方,@/views/PageB.vue)
- <template>
- <div>
- <h3>页面B</h3>
- <div>接收的ID:{{ id }}</div>
- <div>接收的名称:{{ name }}</div>
- </div>
- </template>
- <script setup>
- import { useRoute } from 'vue-router';
- import { ref, watch } from 'vue';
- const route = useRoute();
- const id = ref(Number(route.query.id));
- const name = ref(route.query.name);
- watch(() => route.query, (newQuery) => {
- id.value = Number(newQuery.id);
- name.value = newQuery.name;
- }, { immediate: true });
- </script>
复制代码
Vue2版本(选项式API)只需将 $router.push 和 $route.query 换成 this.$router 和 this.$route,并在 watch 中监听 '$route.query',结构类似,不再赘述。
2. params参数(路径不可见,适合敏感临时数据)
优点:参数不会出现在URL中,适合传递密码、token等敏感信息。注意:必须配合路由配置中的占位符(如 /pageB/:id/:name)使用,且跳转时必须使用 name,不能使用 path。刷新页面时若配置了占位符则不会丢失。
Vue3示例(仅展示差异部分):- // 路由配置(需添加占位符)
- { path: '/pageB/:id/:name', name: 'PageB', component: PageB }
- // 页面A跳转(必须用name)
- router.push({ name: 'PageB', params: { id: 456, name: '敏感数据Demo' } });
- // 页面B接收
- const id = ref(Number(route.params.id));
- const name = ref(route.params.name);
复制代码
Vue2跳转方式:this.$router.push({ name: 'PageB', params: { id: 456, name: '敏感数据Demo' } }),接收使用 this.$route.params。
注意事项:
- query参数路径可见,适合简单字符串/数字;params参数路径不可见,但若未配置占位符,刷新后丢失。
- 传递对象/数组时,需先 JSON.stringify,接收时 JSON.parse,避免数据错乱。
二、全局状态管理(Pinia / Vuex)
适用场景:多个页面共享同一份数据(如用户信息、全局配置),且需要实时联动更新。Vue3 推荐 Pinia,Vue2 常用 Vuex。
1. Pinia(Vue3首选,更轻量简洁)
使用步骤:安装依赖(npm install pinia)→ 创建 Pinia 实例并注册 → 定义 store → 在组件中直接调用。
- // main.js 注册 Pinia
- import { createApp } from 'vue';
- import { createPinia } from 'pinia';
- import App from './App.vue';
- import router from './router';
- const app = createApp(App);
- app.use(createPinia());
- app.use(router);
- app.mount('#app');
复制代码- // store/modules/user.js 定义仓库
- export const useUserStore = defineStore('user', {
- state: () => ({
- userInfo: { id: 1, name: '测试用户', age: 20 },
- count: 0
- }),
- actions: {
- setUserInfo(info) { this.userInfo = info; },
- addCount() { this.count++; },
- resetCount() { this.count = 0; }
- }
- });
复制代码- // 页面A(修改数据)
- <script setup>
- import { useUserStore } from '@/store/modules/user';
- const userStore = useUserStore();
- const updateUserInfo = () => {
- userStore.setUserInfo({ id: 2, name: '新用户', age: 22 });
- };
- </script>
- <template>
- <div>当前计数器:{{ userStore.count }}</div>
- <button @click="userStore.addCount">+1</button>
- </template>
复制代码- // 页面B(读取数据)
- <script setup>
- import { useUserStore } from '@/store/modules/user';
- const userStore = useUserStore();
- </script>
- <template>
- <div>用户:{{ userStore.userInfo.name }}</div>
- </template>
复制代码
注意:Pinia 无需手动注册到 Vue,直接 useStore() 即可。数据在页面刷新后会丢失,需配合 localStorage 做持久化。
2. Vuex(Vue2 标准方案)
使用前安装 vuex@3,在 main.js 中 Vue.use(Vuex) 并注入 store。
- // store/index.js
- export default new Vuex.Store({
- state: { userInfo: { id: 1, name: '测试用户', age: 20 }, count: 0 },
- mutations: {
- setUserInfo(state, info) { state.userInfo = info; },
- addCount(state) { state.count++; },
- resetCount(state) { state.count = 0; }
- },
- actions: {
- addCountAsync({ commit }) { setTimeout(() => commit('addCount'), 1000); }
- },
- getters: { userName: state => state.userInfo.name }
- });
复制代码- // 页面中通过 $store 访问
- this.$store.commit('addCount');
- this.$store.dispatch('addCountAsync');
- this.$store.state.count;
- this.$store.getters.userName;
复制代码
Vuex 的 mutation 必须同步,异步操作需要放在 action 中。使用 getters 简化读取。
三、localStorage / sessionStorage(本地存储持久化)
适用场景:需要跨页面持久保存的数据(如登录 token、用户偏好设置),刷新页面也不会丢失。localStorage 除非手动删除否则永久保存,sessionStorage 在关闭浏览器标签后清除。
推荐封装通用工具函数,方便统一管理对象序列化/反序列化:- // utils/storage.js
- export const setLocal = (key, value) => {
- const val = typeof value === 'object' ? JSON.stringify(value) : value;
- localStorage.setItem(key, val);
- };
- export const getLocal = (key) => {
- const val = localStorage.getItem(key);
- try { return JSON.parse(val); } catch { return val; }
- };
- export const removeLocal = (key) => { localStorage.removeItem(key); };
- export const setSession = (key, value) => {
- const val = typeof value === 'object' ? JSON.stringify(value) : value;
- sessionStorage.setItem(key, val);
- };
- export const getSession = (key) => {
- const val = sessionStorage.getItem(key);
- try { return JSON.parse(val); } catch { return val; }
- };
- export const removeSession = (key) => { sessionStorage.removeItem(key); };
复制代码
在 Vue 组件中使用时,直接调用这些方法即可同步数据。若要实现“多页面实时同步”,可配合 storage 事件(window.addEventListener('storage', handler))或定时器轮询。
总结:以上三种方式覆盖了 Vue 跨页面通信的绝大多数场景:简单的跳转传值用路由参数;多页面全局共享用 Pinia/Vuex;需要持久化且不依赖框架层则用 localStorage。根据实际需求选择最合适的方案,避免过度设计。后续还会补充 EventBus、Cookie、postMessage 等进阶方式,但在日常开发中,掌握这三种已足以应对 80% 的需求。 |