在Vue项目开发中,跨页面通信(非父子组件、不同路由页面间)是高频需求,比如“列表页跳转详情页传递数据”“页面A操作后同步更新页面B内容”。本文整理8种主流通信方式,按“常用度+实用性”排序,每种方式附完整可运行Demo、适配场景和注意事项,覆盖Vue2、Vue3所有项目场景,新手也能直接复制落地。

核心思路:通过路由跳转时携带参数,目标页面接收参数,适合“页面跳转传值”场景(如列表页→详情页),分为「query参数」和「params参数」两种,按需选择。
适配场景:列表页跳转详情页,传递简单ID、名称等数据,刷新页面不丢失。
前置准备:已配置Vue Router(Vue2/Vue3均可,以下Demo分别提供两种版本)。
Vue3 Demo(组合式API)
// 1. 路由配置(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;// 2. 页面A(跳转方,@/views/PageA.vue)<template> <div class="page-a"> <h3>页面A(query参数跳转)</h3> <!-- 方式1:router-link跳转 --> <router-link :to="{ path: '/pageB', query: { id: 123, name: 'Vue跨页面通信Demo' } }" class="btn" > 点击跳转页面B(router-link) </router-link> <!-- 方式2:编程式导航跳转 --> <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; }</style>// 3. 页面B(接收方,@/views/PageB.vue)<template> <div class="page-b"> <h3>页面B(接收query参数)</h3> <div>接收的ID:{{ id }}</div> <div>接收的名称:{{ name }}</div> <!-- 返回页面A --> <router-link to="/pageA" class="btn">返回页面A</router-link> </div></template><script setup>import { useRoute } from 'vue-router';import { ref } from 'vue';const route = useRoute();// 接收参数(query参数默认是字符串,需手动转类型)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>// 4. main.js(入口文件)import { createApp } from 'vue';import App from './App.vue';import router from './router';createApp(App).use(router).mount('#app');Vue2 Demo(选项式API)
// 1. 路由配置(router/index.js)import Vue from 'vue';import Router from 'vue-router';import PageA from '@/views/PageA';import PageB from '@/views/PageB';Vue.use(Router);export default new Router({ routes: [ { path: '/pageA', name: 'PageA', component: PageA }, { path: '/pageB', name: 'PageB', component: PageB } ]});// 2. 页面A(跳转方,@/views/PageA.vue)<template> <div class="page-a"> <h3>页面A(query参数跳转)</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>export default { methods: { goToPageB() { this.$router.push({ path: '/pageB', query: { id: 123, name: 'Vue跨页面通信Demo' } }); } }};</script>// 3. 页面B(接收方,@/views/PageB.vue)<template> <div class="page-b"> <h3>页面B(接收query参数)</h3> <div>接收的ID:{{ id }}</div> <div>接收的名称:{{ name }}</div> <router-link to="/pageA" class="btn">返回页面A</router-link> </div></template><script>export default { data() { return { id: '', name: '' }; }, mounted() { // 初始接收参数 this.id = Number(this.$route.query.id); this.name = this.$route.query.name; }, watch: { // 监听路由变化,同步更新参数 '$route.query': { handler(newQuery) { this.id = Number(newQuery.id); this.name = newQuery.name; }, immediate: true } }};</script>// 4. main.js(入口文件)import Vue from 'vue';import App from './App';import router from './router';new Vue({ el: '#app', router, components: { App }, template: '<App/>'});适配场景:传递敏感数据(如用户隐私信息),路径不可见,需路由配置占位符避免刷新丢失。
Vue3 Demo(组合式API)
// 1. 路由配置(router/index.js,必须添加params占位符)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 }, // 配置params占位符::id、:name(与传递的参数名一致) { path: '/pageB/:id/:name', name: 'PageB', component: PageB }];const router = createRouter({ history: createWebHistory(), routes});export default router;// 2. 页面A(跳转方,@/views/PageA.vue)<template> <div class="page-a"> <h3>页面A(params参数跳转)</h3> <!-- 注意:params参数必须用name跳转,不能用path --> <button @click="goToPageB" class="btn">点击跳转页面B</button> </div></template><script setup>import { useRouter } from 'vue-router';const router = useRouter();const goToPageB = () => { router.push({ name: 'PageB', // 必须用name params: { id: 456, name: '敏感数据Demo' } // 传递params参数 });};</script>// 3. 页面B(接收方,@/views/PageB.vue)<template> <div class="page-b"> <h3>页面B(接收params参数)</h3> <div>接收的ID:{{ id }}</div> <div>接收的敏感名称:{{ name }}</div> <router-link to="/pageA" class="btn">返回页面A</router-link> </div></template><script setup>import { useRoute } from 'vue-router';import { ref, watch } from 'vue';const route = useRoute();const id = ref(Number(route.params.id));const name = ref(route.params.name);// 监听路由变化,同步更新参数watch( () => route.params, (newParams) => { id.value = Number(newParams.id); name.value = newParams.name; }, { immediate: true });</script>Vue2 Demo(选项式API)
// 1. 路由配置(router/index.js)import Vue from 'vue';import Router from 'vue-router';import PageA from '@/views/PageA';import PageB from '@/views/PageB';Vue.use(Router);export default new Router({ routes: [ { path: '/pageA', name: 'PageA', component: PageA }, { path: '/pageB/:id/:name', name: 'PageB', component: PageB } ]});// 2. 页面A(跳转方,@/views/PageA.vue)<template> <div class="page-a"> <h3>页面A(params参数跳转)</h3> <button @click="goToPageB" class="btn">点击跳转页面B</button> </div></template><script>export default { methods: { goToPageB() { this.$router.push({ name: 'PageB', params: { id: 456, name: '敏感数据Demo' } }); } }};</script>// 3. 页面B(接收方,@/views/PageB.vue)<template> <div class="page-b"> <h3>页面B(接收params参数)</h3> <div>接收的ID:{{ id }}</div> <div>接收的敏感名称:{{ name }}</div> <router-link to="/pageA" class="btn">返回页面A</router-link> </div></template><script>export default { data() { return { id: '', name: '' }; }, mounted() { this.id = Number(this.$route.params.id); this.name = this.$route.params.name; }, watch: { '$route.params': { handler(newParams) { this.id = Number(newParams.id); this.name = newParams.name; }, immediate: true } }};</script>注意事项
核心思路:通过全局状态仓库存储数据,所有页面均可读写,适合“多页面共享数据”场景(如用户信息、全局配置、多页面联动),Vue2常用Vuex,Vue3首选Pinia(更轻量、简洁)。
适配场景:多页面共享用户信息、全局计数器等,支持跨页面实时联动,无需手动传递参数。
前置准备:安装Pinia依赖(npm install pinia)。
// 1. 创建Pinia实例并注册(main.js)import { createApp } from 'vue';import App from './App.vue';import { createPinia } from 'pinia'; // 引入Piniaimport router from './router';const app = createApp(App);app.use(createPinia()); // 注册Piniaapp.use(router);app.mount('#app');// 2. 创建全局仓库(store/modules/user.js)import { defineStore } from 'pinia';// 定义仓库(user为仓库唯一标识)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; } }});// 3. 页面A(修改全局数据,@/views/PageA.vue)<template> <div class="page-a"> <h3>页面A(修改Pinia全局数据)</h3> <div>当前全局计数器:{{ userStore.count }}</div> <button @click="userStore.addCount" class="btn">计数器+1</button> <button @click="updateUserInfo" class="btn">修改用户信息</button> <router-link to="/pageB" class="btn">跳转到页面B查看数据</router-link> </div></template><script setup>import { useUserStore } from '@/store/modules/user';// 引入并使用仓库const userStore = useUserStore();// 修改用户信息const updateUserInfo = () => { userStore.setUserInfo({ id: 2, name: '新用户', age: 22 });};</script>// 4. 页面B(读取/修改全局数据,@/views/PageB.vue)<template> <div class="page-b"> <h3>页面B(读取Pinia全局数据)</h3> <div>用户ID:{{ userStore.userInfo.id }}</div> <div>用户名:{{ userStore.userInfo.name }}</div> <div>当前全局计数器:{{ userStore.count }}</div> <button @click="userStore.addCount" class="btn">计数器+1</button> <button @click="userStore.resetCount" class="btn">重置计数器</button> <router-link to="/pageA" class="btn">返回页面A</router-link> </div></template><script setup>import { useUserStore } from '@/store/modules/user';const userStore = useUserStore();</script>前置准备:安装Vuex依赖(npm install vuex@3,Vue2对应Vuex3版本)。
// 1. 创建Vuex仓库并注册(main.js)import Vue from 'vue';import App from './App';import router from './router';import Vuex from 'vuex'; // 引入Vueximport store from './store'; // 引入仓库Vue.use(Vuex); // 注册Vuexnew Vue({ el: '#app', router, store, // 注入仓库 components: { App }, template: '<App/>'});// 2. 创建全局仓库(store/index.js)import Vue from 'vue';import Vuex from 'vuex';Vue.use(Vuex);export default new Vuex.Store({ state: { userInfo: { id: 1, name: '测试用户', age: 20 }, count: 0 }, mutations: { // 同步修改状态(必须通过mutation修改state) setUserInfo(state, info) { state.userInfo = info; }, addCount(state) { state.count++; }, resetCount(state) { state.count = 0; } }, actions: { // 异步修改状态(如接口请求后修改) addCountAsync({ commit }) { setTimeout(() => { commit('addCount'); // 调用mutation修改state }, 1000); } }, getters: { // 计算属性(简化数据读取) userName: state => state.userInfo.name }});// 3. 页面A(修改全局数据,@/views/PageA.vue)<template> <div class="page-a"> <h3>页面A(修改Vuex全局数据)</h3> <div>当前全局计数器:{{ $store.state.count }}</div> <div>用户名:{{ $store.getters.userName }}</div> <button @click="$store.commit('addCount')" class="btn">计数器+1(同步)</button> <button @click="$store.dispatch('addCountAsync')" class="btn">计数器+1(异步)</button> <button @click="updateUserInfo" class="btn">修改用户信息</button> <router-link to="/pageB" class="btn">跳转到页面B查看数据</router-link> </div></template><script>export default { methods: { updateUserInfo() { // 调用mutation修改用户信息 this.$store.commit('setUserInfo', { id: 2, name: '新用户', age: 22 }); } }};</script>// 4. 页面B(读取/修改全局数据,@/views/PageB.vue)<template> <div class="page-b"> <h3>页面B(读取Vuex全局数据)</h3> <div>用户ID:{{ $store.state.userInfo.id }}</div> <div>用户名:{{ $store.getters.userName }}</div> <div>当前全局计数器:{{ $store.state.count }}</div> <button @click="$store.commit('addCount')" class="btn">计数器+1</button> <button @click="$store.commit('resetCount')" class="btn">重置计数器</button> <router-link to="/pageA" class="btn">返回页面A</router-link> </div></template><script>export default {};</script>注意事项
核心思路:利用浏览器本地存储API,将数据存入本地,所有页面均可读取,适合“持久化数据”场景(如用户登录状态、记住密码、长期保存的配置),分为两种存储方式,按需选择。
完整可运行Demo(Vue2/Vue3通用)
适配场景:持久化存储用户登录状态、记住密码,刷新页面不丢失,跨页面共享。
// 1. 封装本地存储工具(utils/storage.js,简化版,通用)// 存储localStorage(永久存储)export const setLocal = (key, value) => { // 处理对象/数组,转为字符串 const val = typeof value === 'object' ? JSON.stringify(value) : value; localStorage.setItem(key, val);};// 获取localStorageexport const getLocal = (key) => { const val = localStorage.getItem(key); try { // 尝试解析为对象/数组 return JSON.parse(val); } catch (e) { // 解析失败,返回原始字符串 return val; }};// 删除localStorageexport const removeLocal = (key) => { localStorage.removeItem(key);};// 存储sessionStorage(会话存储)export const setSession = (key, value) => { const val = typeof value === 'object' ? JSON.stringify(value) : value; sessionStorage.setItem(key, val);};// 获取sessionStorageexport const getSession = (key) => { const val = sessionStorage.getItem(key); try { return JSON.parse(val); } catch (e) { return val; }};// 2. 页面A(存储数据,@/views/PageA.vue,Vue3示例,Vue2用法类似)<template> <div class="page-a"> <h3>页面A(存储本地数据)</h3> <button @click="saveLocalData" class="btn">存储永久数据(localStorage)</button> <button @click="saveSessionData" class="btn">存储临时数据(sessionStorage)</button> <button @click="removeLocal('userInfo')" class="btn">删除永久数据</button> <router-link to="/pageB" class="btn">跳转到页面B读取数据</router-link> </div></template><script setup>import { setLocal, setSession, removeLocal } from '@/utils/storage';// 存储永久数据(刷新页面不丢失,除非手动删除)const saveLocalData = () => { setLocal('userInfo', { id: 1, name: '测试用户', remember: true }); alert('永久数据存储成功!');};// 存储临时数据(关闭标签页/浏览器后丢失)const saveSessionData = () => { setSession('tempData', '临时测试数据123'); alert('临时数据存储成功!');};</script>// 3. 页面B(读取数据,@/views/PageB.vue,Vue3示例)<template> <div class="page-b"> <h3>页面B(读取本地数据)</h3> <div>永久数据(localStorage):{{ userInfo }}</div> <div>临时数据(sessionStorage):{{ tempData }}</div> <router-link to="/pageA" class="btn">返回页面A</router-link> </div></template><script setup>import { ref, onMounted } from 'vue';import { getLocal, getSession } from '@/utils/storage';const userInfo = ref({});const tempData = ref('');// 页面挂载时读取数据onMounted(() => { userInfo.value = getLocal('userInfo') || {}; tempData.value = getSession('tempData') || '暂无临时数据';});</script>// Vue2 页面B示例(@/views/PageB.vue)<template> <div class="page-b"> <h3>页面B(读取本地数据)</h3> <div>永久数据(localStorage):{{ userInfo }}</div> <div>临时数据(sessionStorage):{{ tempData }}</div> <router-link to="/pageA" class="btn">返回页面A</router-link> </div></template><script>import { getLocal, getSession } from '@/utils/storage';export default { data() { return { userInfo: {}, tempData: '' }; }, mounted() { this.userInfo = getLocal('userInfo') || {}; this.tempData = getSession('tempData') || '暂无临时数据'; }};</script>注意事项
核心思路:创建一个全局事件总线,页面A触发事件并传递数据,页面B监听事件并接收数据,适合“简单跨页面联动”场景(如页面A操作后,页面B同步更新),Vue2和Vue3实现方式略有差异。
适配场景:页面A修改数据后,页面B实时更新,无需跳转路由(如两个标签页联动)。
// 1. 创建事件总线(utils/eventBus.js)import { ref } from 'vue';// 定义总线容器const bus = ref({});// 触发事件(发送数据)export const emitEvent = (eventName, data) => { // 若有监听该事件的回调,执行并传递数据 bus.value[eventName]?.(data);};// 监听事件(接收数据)export const onEvent = (eventName, callback) => { // 注册回调函数 bus.value[eventName] = callback;};// 取消监听(避免内存泄漏)export const offEvent = (eventName) => { // 删除事件回调 delete bus.value[eventName];};// 2. 页面A(触发事件,发送数据,@/views/PageA.vue)<template> <div class="page-a"> <h3>页面A(EventBus发送数据)</h3> <input v-model="message" placeholder="请输入要传递的内容" /> <button @click="sendData" class="btn">发送数据到页面B</button> <router-link to="/pageB" class="btn">跳转到页面B</router-link> </div></template><script setup>import { ref } from 'vue';import { emitEvent } from '@/utils/eventBus';const message = ref('');// 触发事件,传递数据const sendData = () => { if (!message.value) { alert('请输入内容'); return; } emitEvent('sendData', { message: message.value, time: new Date().toLocaleString() }); message.value = ''; alert('数据发送成功!');};</script>// 3. 页面B(监听事件,接收数据,@/views/PageB.vue)<template> <div class="page-b"> <h3>页面B(EventBus接收数据)</h3> <div class="data-list"> <div v-for="(item, index) in dataList" :key="index"> {{ item.time }}:{{ item.message }} </div> <div v-if="dataList.length === 0">暂无数据</div> </div> <router-link to="/pageA" class="btn">返回页面A</router-link> </div></template><script setup>import { ref, onMounted, onUnmounted } from 'vue';import { onEvent, offEvent } from '@/utils/eventBus';const dataList = ref([]);onMounted(() => { // 监听事件,接收数据 onEvent('sendData', (data) => { dataList.value.push(data); });});onUnmounted(() => { // 组件销毁时取消监听,避免内存泄漏 offEvent('sendData');});</script><style scoped>.data-list { margin: 20px 0; padding: 10px; border: 1px solid #eee; }.data-list div { margin: 5px 0; }</style>// 1. 注册全局EventBus(main.js)import Vue from 'vue';import App from './App';import router from './router';// 注册全局总线(挂载到Vue原型上)Vue.prototype.$bus = new Vue();new Vue({ el: '#app', router, components: { App }, template: '<App/>'});// 2. 页面A(触发事件,发送数据,@/views/PageA.vue)<template> <div class="page-a"> <h3>页面A(EventBus发送数据)</h3> <input v-model="message" placeholder="请输入要传递的内容" /> <button @click="sendData" class="btn">发送数据到页面B</button> <router-link to="/pageB" class="btn">跳转到页面B</router-link> </div></template><script>export default { data() { return { message: '' }; }, methods: { sendData() { if (!this.message) { alert('请输入内容'); return; } // 触发全局事件,传递数据 this.$bus.$emit('sendData', { message: this.message, time: new Date().toLocaleString() }); this.message = ''; alert('数据发送成功!'); } }};</script>// 3. 页面B(监听事件,接收数据,@/views/PageB.vue)<template> <div class="page-b"> <h3>页面B(EventBus接收数据)</h3> <div class="data-list"> <div v-for="(item, index) in dataList" :key="index"> {{ item.time }}:{{ item.message }} </div> <div v-if="dataList.length === 0">暂无数据</div> </div> <router-link to="/pageA" class="btn">返回页面A</router-link> </div></template><script>export default { data() { return { dataList: [] }; }, mounted() { // 监听全局事件 this.$bus.$on('sendData', (data) => { this.dataList.push(data); }); }, beforeDestroy() { // 组件销毁时取消监听,避免内存泄漏 this.$bus.$off('sendData'); }};</script>注意事项
核心思路:基于本地存储,监听存储数据的变化,当页面A修改本地存储时,页面B自动感知并更新,解决“本地存储数据变化不响应”的问题,适合“持久化数据联动”场景。
完整可运行Demo(Vue2/Vue3通用)
适配场景:页面A修改本地存储的用户配置,页面B自动同步更新,无需手动刷新。
// 1. 封装本地存储工具(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 (e) { return val; }};// 2. 页面A(修改本地存储,触发变化,@/views/PageA.vue,Vue3示例)<template> <div class="page-a"> <h3>页面A(修改本地存储)</h3> <button @click="updateCount" class="btn">修改全局计数(localStorage)</button> <div>当前计数:{{ count }}</div> <router-link to="/pageB" class="btn">跳转到页面B(自动同步)</router-link> </div></template><script setup>import { ref, onMounted } from 'vue';import { setLocal, getLocal } from '@/utils/storage';const count = ref(0);// 页面挂载时读取当前计数onMounted(() => { count.value = getLocal('count') || 0;});// 修改本地存储的计数(触发storage事件)const updateCount = () => { count.value++; setLocal('count', count.value);};</script>// 3. 页面B(监听本地存储变化,自动更新,@/views/PageB.vue,Vue3示例)<template> <div class="page-b"> <h3>页面B(监听本地存储变化)</h3> <div>同步的计数:{{ count }}</div> <router-link to="/pageA" class="btn">返回页面A</router-link> </div></template><script setup>import { ref, onMounted, onUnmounted } from 'vue';import { getLocal } from '@/utils/storage';const count = ref(0);// 监听storage事件const handleStorageChange = (e) => { // 判断是否是我们关注的key if (e.key === 'count') { count.value = Number(e.newValue); }};onMounted(() => { // 初始读取计数 count.value = getLocal('count') || 0; // 注册storage监听 window.addEventListener('storage', handleStorageChange);});onUnmounted(() => { // 取消监听,避免内存泄漏 window.removeEventListener('storage', handleStorageChange);});</script>// Vue2 页面B示例<script>import { getLocal } from '@/utils/storage';export default { data() { return { count: 0 }; }, mounted() { this.count = getLocal('count') || 0; window.addEventListener('storage', this.handleStorageChange); }, beforeDestroy() { window.removeEventListener('storage', this.handleStorageChange); }, methods: { handleStorageChange(e) { if (e.key === 'count') { this.count = Number(e.newValue); } } }};</script>注意事项
核心思路:利用浏览器Cookie存储小型数据,可设置过期时间,支持跨域(配置domain),适合“小型持久化数据”场景(如用户token、记住登录状态),容量较小(约4KB)。
完整可运行Demo(Vue2/Vue3通用)
适配场景:存储用户登录token、记住密码状态,跨页面共享,支持过期时间设置。
// 1. 封装Cookie工具(utils/cookie.js,通用)// 设置Cookie(支持过期时间、路径、域名)export const setCookie = (key, value, days = 7, path = '/', domain = '') => { let cookieStr = `${encodeURIComponent(key)}=${encodeURIComponent(value)}`; // 设置过期时间 if (days) { const date = new Date(); date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000); cookieStr += `;expires=${date.toUTCString()}`; } // 设置路径 if (path) cookieStr += `;path=${path}`; // 设置域名(跨域时使用) if (domain) cookieStr += `;domain=${domain}`; // 写入Cookie document.cookie = cookieStr;};// 获取Cookieexport const getCookie = (key) => { const cookies = document.cookie.split('; '); for (const cookie of cookies) { const [k, v] = cookie.split('='); if (k === encodeURIComponent(key)) { return decodeURIComponent(v); } } return '';};// 删除Cookieexport const removeCookie = (key, path = '/', domain = '') => { // 设置过期时间为过去,实现删除 setCookie(key, '', -1, path, domain);};// 2. 页面A(设置Cookie,@/views/PageA.vue,Vue3示例)<template> <div class="page-a"> <h3>页面A(设置Cookie)</h3> <div> <label>记住密码:</label> <input type="checkbox" v-model="remember" /> </div> <button @click="login" class="btn">模拟登录(设置Cookie)</button> <button @click="removeCookie('token')" class="btn">删除token</button> <router-link to="/pageB" class="btn">跳转到页面B读取Cookie</router-link> </div></template><script setup>import { ref } from 'vue';import { setCookie, removeCookie } from '@/utils/cookie';const remember = ref(false);// 模拟登录,设置Cookieconst login = () => { const token = 'abc123456789'; // 模拟后端返回的token // 记住密码:保存7天;不记住:不设置过期时间(会话结束后失效) setCookie('token', token, remember.value ? 7 : 0); alert('登录成功,Cookie已设置!');};</script>// 3. 页面B(读取Cookie,@/views/PageB.vue,Vue3示例)<template> <div class="page-b"> <h3>页面B(读取Cookie)</h3> <div>当前登录token:{{ token }}</div> <div v-if="!token">未获取到token(Cookie已过期或未设置)</div> <router-link to="/pageA" class="btn">返回页面A</router-link> </div></template><script setup>import { ref, onMounted } from 'vue';import { getCookie } from '@/utils/cookie';const token = ref('');// 页面挂载时读取CookieonMounted(() => { token.value = getCookie('token');});</script>// Vue2 页面B示例<script>import { getCookie } from '@/utils/cookie';export default { data() { return { token: '' }; }, mounted() { this.token = getCookie('token'); }};</script>注意事项
核心思路:通过window.postMessage方法,实现不同页面(甚至跨域页面、多窗口)间的通信,适合“跨域页面、多窗口联动”场景(如Vue页面与iframe页面通信、打开新窗口传值)。
完整可运行Demo(分2种场景,Vue2/Vue3通用)
场景1:页面A打开新窗口(页面B),传递数据
// 页面A(打开新窗口,发送数据,@/views/PageA.vue,Vue3示例)<template> <div class="page-a"> <h3>页面A(打开新窗口传值)</h3> <button @click="openPageB" class="btn">打开页面B并传递数据</button> </div></template><script setup>import { ref } from 'vue';// 存储新窗口实例const pageB = ref(null);// 打开页面B并发送数据const openPageB = () => { // 打开新窗口(同域场景,路径为页面B的路由) pageB.value = window.open('/pageB', '_blank'); // 确保页面B加载完成后发送数据(避免接收不到) setTimeout(() => { // 发送数据:第一个参数是数据,第二个参数是目标域名(*表示允许所有,生产环境需指定具体域名) pageB.value.postMessage( { type: 'init', data: { id: 123, name: '窗口通信Demo' } }, 'http://localhost:8080' // 生产环境替换为实际域名 ); }, 1000);};</script>// 页面B(新窗口,接收数据,@/views/PageB.vue,Vue3示例)<template> <div class="page-b"> <h3>页面B(新窗口接收数据)</h3> <div v-if="receivedData"> <div>接收的数据类型:{{ receivedData.type }}</div> <div>接收的ID:{{ receivedData.data.id }}</div> <div>接收的名称:{{ receivedData.data.name }}</div> </div> <div v-else>暂无数据接收</div> <button @click="sendBackData" class="btn">向页面A返回数据</button> </div></template><script setup>import { ref, onMounted, onUnmounted } from 'vue';const receivedData = ref(null);// 接收页面A发送的数据const handleMessage = (e) => { // 安全校验:只接收指定域名的消息(生产环境必加,防止恶意消息) if (e.origin !== 'http://localhost:8080') return; // 接收数据并赋值 receivedData.value = e.data;};// 向页面A返回数据const sendBackData = () => { if (!receivedData.value) { alert('未接收任何数据,无法返回'); return; } // 通过opener获取父窗口(页面A),发送返回数据 window.opener.postMessage( { type: 'reply', data: '已成功接收数据,感谢发送!' }, 'http://localhost:8080' ); alert('返回数据已发送给页面A');};onMounted(() => { // 注册message监听 window.addEventListener('message', handleMessage);});onUnmounted(() => { // 取消监听,避免内存泄漏 window.removeEventListener('message', handleMessage);});</script>// Vue2 页面B示例(@/views/PageB.vue)<script>export default { data() { return { receivedData: null }; }, mounted() { window.addEventListener('message', this.handleMessage); }, beforeDestroy() { window.removeEventListener('message', this.handleMessage); }, methods: { handleMessage(e) { if (e.origin !== 'http://localhost:8080') return; this.receivedData = e.data; }, sendBackData() { if (!this.receivedData) { alert('未接收任何数据,无法返回'); return; } window.opener.postMessage( { type: 'reply', data: '已成功接收数据,感谢发送!' }, 'http://localhost:8080' ); alert('返回数据已发送给页面A'); } }};</script>// 补充:页面A接收页面B返回数据(Vue3示例,添加到PageA的script中)<script setup>import { ref, onMounted, onUnmounted } from 'vue';const pageB = ref(null);const replyData = ref('');// 接收页面B返回的数据const handleReply = (e) => { if (e.origin !== 'http://localhost:8080') return; replyData.value = e.data.data; alert(`收到页面B返回:${replyData.value}`);};const openPageB = () => { pageB.value = window.open('/pageB', '_blank'); setTimeout(() => { pageB.value.postMessage( { type: 'init', data: { id: 123, name: '窗口通信Demo' } }, 'http://localhost:8080' ); }, 1000);};onMounted(() => { window.addEventListener('message', handleReply);});onUnmounted(() => { window.removeEventListener('message', handleReply);});</script>// 场景2:Vue页面与iframe页面通信(跨域/同域通用)// 1. 页面A(包含iframe,发送数据,@/views/PageA.vue,Vue3示例)<template> <div class="page-a"> <h3>页面A(iframe通信)</h3> <!-- iframe嵌入页面B(可跨域,如https://xxx.com/pageB) --> <iframe ref="iframeRef" src="http://localhost:8080/pageB" // 替换为实际iframe地址 width="800" height="400" ></iframe> <button @click="sendToIframe" class="btn" style="margin-top: 20px;">向iframe发送数据</button> <div>iframe返回数据:{{ iframeReply }}</div> </div></template><script setup>import { ref, onMounted, onUnmounted } from 'vue';const iframeRef = ref(null);const iframeReply = ref('');// 向iframe发送数据const sendToIframe = () => { if (!iframeRef.value) return; // 获取iframe的window对象,发送数据 iframeRef.value.contentWindow.postMessage( { type: 'iframeData', data: '来自Vue页面的iframe通信数据' }, 'http://localhost:8080' // 跨域时填写iframe的实际域名 );};// 接收iframe返回的数据const handleIframeReply = (e) => { if (e.origin !== 'http://localhost:8080') return; iframeReply.value = e.data.data;};onMounted(() => { window.addEventListener('message', handleIframeReply); // 等待iframe加载完成(可选,确保通信稳定) iframeRef.value.onload = () => { console.log('iframe加载完成,可开始通信'); };});onUnmounted(() => { window.removeEventListener('message', handleIframeReply);});</script>// 2. 页面B(iframe内嵌页面,接收/返回数据,@/views/PageB.vue,Vue3示例)<template> <div class="page-b"> <h3>iframe内嵌页面(接收数据)</h3> <div>接收的iframe数据:{{ iframeData }}</div> <button @click="replyToParent" class="btn">向父页面返回数据</button> </div></template><script setup>import { ref, onMounted, onUnmounted } from 'vue';const iframeData = ref('暂无数据');// 接收父页面(页面A)发送的数据const handleParentMessage = (e) => { // 安全校验,仅接收指定域名的消息 if (e.origin !== 'http://localhost:8080') return; iframeData.value = e.data.data;};// 向父页面返回数据const replyToParent = () => { // 通过parent获取父窗口,发送返回数据 window.parent.postMessage( { type: 'iframeReply', data: '已接收iframe数据,返回确认!' }, 'http://localhost:8080' );};onMounted(() => { window.addEventListener('message', handleParentMessage);});onUnmounted(() => { window.removeEventListener('message', handleParentMessage);});</script>// Vue2 iframe通信示例(页面B)<script>export default { data() { return { iframeData: '暂无数据' }; }, mounted() { window.addEventListener('message', this.handleParentMessage); }, beforeDestroy() { window.removeEventListener('message', this.handleParentMessage); }, methods: { handleParentMessage(e) { if (e.origin !== 'http://localhost:8080') return; this.iframeData = e.data.data; }, replyToParent() { window.parent.postMessage( { type: 'iframeReply', data: '已接收iframe数据,返回确认!' }, 'http://localhost:8080' ); } }};</script>以上就是Vue中跨页面通信的8种主流方式详解的详细内容,更多关于Vue跨页面通信的资料请关注本站其它相关文章!