同一页面多Vue应用间响应式localStorage状态共享问题
解决侧边栏切换时导航栏宽度同步变化的问题
首先修正你Sidebar.vue里的小问题:Vue Options API中,data返回的对象不需要用ref包裹(ref是Composition API语法),直接定义状态即可。
下面提供两种实用解决方案:
方案1:父子组件通信(适合简单场景)
假设导航栏组件(比如Navbar.vue)是Sidebar的父组件,按以下步骤修改:
1. 调整导航栏组件(Navbar.vue)
<template> <div class="navbar" :class="{ 'sidebar-expanded': isSidebarExpanded }"> <!-- 导航栏自身内容 --> <Sidebar @toggle-sidebar="toggleSidebar" :is-expanded="isSidebarExpanded" /> </div> </template> <script> import Sidebar from './Sidebar.vue' export default { components: { Sidebar }, data() { return { isSidebarExpanded: localStorage.getItem('is_expanded') === 'true' } }, methods: { toggleSidebar() { this.isSidebarExpanded = !this.isSidebarExpanded localStorage.setItem('is_expanded', this.isSidebarExpanded) } } } </script> <style scoped> .navbar { width: calc(100% - 60px); /* 侧边栏收起时的宽度,按需调整 */ transition: width 0.3s ease; /* 平滑过渡动画 */ } .navbar.sidebar-expanded { width: calc(100% - 250px); /* 侧边栏展开时的宽度,按需调整 */ } </style>
2. 修改Sidebar.vue组件
把状态改为props接收,点击按钮时触发事件通知父组件:
<template> <aside :class="{ 'is-expanded': isExpanded }"> <div class="head-aside"> <div class="app-logo"> <i class="bx bxl-trip-advisor"></i> </div> <span class="app-name">CONTROLPANEL</span> </div> <div class="menu-toggle-wrap"> <button class="menu-toggle" @click="emitToggle"> <span class="boxicons"><i :class="isExpanded ? 'bx bx-chevrons-left' : 'bx bx-chevrons-right'"></i></span> </button> </div> </aside> </template> <script> export default { props: { isExpanded: { type: Boolean, required: true } }, methods: { emitToggle() { this.$emit('toggle-sidebar') } } } </script>
方案2:用Pinia做状态管理(适合多组件共享状态)
如果项目中有多个组件需要用到侧边栏状态,用Pinia统一管理更高效:
1. 安装并配置Pinia
npm install pinia
在main.js中注册Pinia:
import { createPinia } from 'pinia' import { createApp } from 'vue' import App from './App.vue' const app = createApp(App) app.use(createPinia()) app.mount('#app')
2. 创建侧边栏状态Store
新建stores/sidebar.js:
import { defineStore } from 'pinia' export const useSidebarStore = defineStore('sidebar', { state: () => ({ isExpanded: localStorage.getItem('is_expanded') === 'true' }), actions: { toggle() { this.isExpanded = !this.isExpanded localStorage.setItem('is_expanded', this.isExpanded) } } })
3. 修改Sidebar.vue组件
<template> <aside :class="{ 'is-expanded': sidebarStore.isExpanded }"> <!-- 模板内容不变 --> <div class="menu-toggle-wrap"> <button class="menu-toggle" @click="sidebarStore.toggle()"> <span class="boxicons"><i :class="sidebarStore.isExpanded ? 'bx bx-chevrons-left' : 'bx bx-chevrons-right'"></i></span> </button> </div> </aside> </template> <script> import { useSidebarStore } from '@/stores/sidebar' export default { setup() { const sidebarStore = useSidebarStore() return { sidebarStore } } } </script>
4. 调整导航栏组件(Navbar.vue)
<template> <div class="navbar" :class="{ 'sidebar-expanded': sidebarStore.isExpanded }"> <!-- 导航栏内容 --> <Sidebar /> </div> </template> <script> import Sidebar from './Sidebar.vue' import { useSidebarStore } from '@/stores/sidebar' export default { components: { Sidebar }, setup() { const sidebarStore = useSidebarStore() return { sidebarStore } } } </script> <style scoped> .navbar { width: calc(100% - 60px); transition: width 0.3s ease; } .navbar.sidebar-expanded { width: calc(100% - 250px); } </style>
内容的提问来源于stack exchange,提问作者furaxsme
相关产品推荐
相关产品推荐

