在同一页面上的多个 vue 应用程序之间共享反应式 localStorage 状态

问题描述 投票:0回答:4

我正在使用 Laravel 和 VueJS 创建一个仪表板,我创建了一个按钮,允许在

Sidebar.vue
组件中放大或缩小我的侧边栏,这是我的组件:

<template>
  <aside :class="`${is_expanded ? 'is-expanded' : ''}`">
    <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="ToggleMenu()">
        <span class="boxicons"><i class="bx bx-chevrons-right"></i></span>
      </button>
    </div>
  </aside>
</template>

<script>
export default {
  data() {
    return {
      is_expanded: ref(localStorage.getItem('is_expanded') === 'true'),
    }
  },

  methods: {
    ToggleMenu() {
      this.is_expanded = !this.is_expanded
      localStorage.setItem('is_expanded', this.is_expanded)
    },
  },
}
</script>

出现的问题是,在另一个组件中我创建了一个具有固定宽度的导航栏,我想做的是,当我的侧边栏更改大小时,我希望我的导航栏也发生变化,在另一个组件中我只有一个模板带有导航和侧边栏的导入。

javascript vuejs3 toggle sidebar
4个回答
1
投票

你说你正在使用 laravel 和 vue。目前尚不清楚 vue 组件是如何集成的,但我假设 laravel 注入了您想要通信的各个 vue 组件。 (与仅使用 API 与 Laravel 通信的基于 vue 的 SPA 不同)

这两个组件彼此不了解。即使它们都可以访问相同的 localStorage,但它们不知道那里的值何时更新。

有多种方法可以解决这个问题,这是一种方法

在组件外部创建一个响应式对象来管理共享状态

import { ref, computed } from 'vue'
const isExpandedRef = ref(localStorage.getItem('is_expanded') === 'true');

window.IS_EXPANDED = computed({
  get(){
    return isExpandedRef.value
  },
  set(value){
    isExpandedRef.value = !!value;
    localStorage.setItem('is_expanded', isExpandedRef.value);
  }
})

需要

ref
,以便当
isExpandedRef.value
更改时,计算的 getter 会向其侦听器触发通知。

如果在任何组件之前加载它,您将创建一个可用于页面上任何脚本的计算(反应)变量(除了框架和影子 dom)

然后你可以像这样在你的组件中使用。

<template>
  <aside :class="`${is_expanded ? 'is-expanded' : ''}`">
    <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="is_expanded = !is_expanded">
        <span class="boxicons"><i class="bx bx-chevrons-right"></i></span>
      </button>
    </div>
  </aside>
</template>

<script>
export default {
  data() {
    return {
      is_expanded: window.IS_EXPANDED,
    }
  },
}
</script>

因为

is_expanded
是通过 getter 和 setter 进行计算的,您可以直接从模板设置值,或者在方法中使用
this.is_expanded = !this.is_expanded

如前所述,这依赖于使用全局

window
对象。提出该解决方案是为了其简单性。使用 window 对象有一些缺点,更强大的解决方案将依赖于注入此类共享状态而不是依赖于 window,但它会带来更多开销。


0
投票

这段代码运行良好

<template>
  <aside :class="`${is_expanded ? 'is-expanded' : ''}`">
    <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="ToggleMenu()">
        <span class="boxicons">
          <i class="bx bx-chevrons-right"></i>click me
        </span>
      </button>
    </div>
  </aside>
</template>

<script>
export default {
  data() {
    return {
      is_expanded: localStorage.getItem("is_expanded") === "true",
    };
  },

  methods: {
    ToggleMenu() {
      this.is_expanded = !this.is_expanded;
      localStorage.setItem("is_expanded", this.is_expanded);
    },
  },
};
</script>

这里有一个 GIF 显示实际结果:https://share.cleanshot.com/TtKsUj


0
投票

通过使用 watcher 并将其 deep 属性设置为 true 使本地存储具有反应性 https://vuejs.org/guide/essentials/watchers.html#deep-watchers 或者如果您使用的是 vue2,则使用事件总线


0
投票

使用 Vue 3 组合 API

let isOpen = ref(localStorage.getItem('is_open') === 'true');

const openMenu = () => {
            isOpen.value = !isOpen.value
            localStorage.setItem('is_open', isOpen.value);
     }

<aside id="logo-sidebar" :class="isOpen ? 'w-24 collapsed' : 'w-64' ">
© www.soinside.com 2019 - 2024. All rights reserved.