我正在使用 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>
出现的问题是,在另一个组件中我创建了一个具有固定宽度的导航栏,我想做的是,当我的侧边栏更改大小时,我希望我的导航栏也发生变化,在另一个组件中我只有一个模板带有导航和侧边栏的导入。
你说你正在使用 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,但它会带来更多开销。
这段代码运行良好
<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
通过使用 watcher 并将其 deep 属性设置为 true 使本地存储具有反应性 https://vuejs.org/guide/essentials/watchers.html#deep-watchers 或者如果您使用的是 vue2,则使用事件总线
使用 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' ">