Совместное использование реактивного состояния localStorage между несколькими приложениями vue на одной странице

Я создаю панель инструментов с 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>

Возникающая проблема заключается в том, что в другом компоненте я создал навигационную панель с фиксированной шириной, и я хотел бы сделать так, чтобы при изменении размера моей боковой панели я хотел, чтобы моя навигационная панель также менялась, в другом компоненте у меня просто есть шаблон с навигация и импорт моей боковой панели.

ref предназначен для Composition API, если вы используете Options API с data, methods и т. д., он вам не нужен.
kissu 13.10.2022 20:25
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
1
62
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Этот код работает нормально

<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

эй, да, этот код работает нормально, но в другом компоненте у меня есть панель навигации с фиксированной шириной, и я хочу одновременно переключать ее ширину

furaxsme 13.10.2022 20:37

как вы можете видеть на этой гифке imgflip.com/gif/6wsrli

furaxsme 13.10.2022 20:40

@furaxsme смотреть некоторые localStorage в целом немного сложнее. Я предполагаю, что вы могли бы использовать этот или этот подход (немного более продвинутый), но нет дружественного способа получить к нему доступ, поскольку он сам по себе не является реактивным. Да и нужно ли оно здесь? Вы можете иметь более высокое состояние или даже использовать хранилище (Vuex, Pinia) для обработки глобального состояния, то есть замены вашего локального хранилища.

kissu 13.10.2022 20:46

Сделайте локальное хранилище реактивным, используя наблюдатель и установив для его свойства deep значение true. https://vuejs.org/guide/essentials/watchers.html#deep-watchers или если вы используете vue2, используйте шину событий

Наблюдатель может наблюдать только за реактивной опорой.

kissu 13.10.2022 21:30
Ответ принят как подходящий

Вы говорите, что используете laravel с vue. Непонятно, как интегрируются компоненты vue, но я предполагаю, что laravel внедряет отдельные компоненты vue, которые вы хотели бы сообщить. (в отличие от SPA на основе vue, который взаимодействует с laravel только с использованием API)

Два компонента не знают друг о друге. Несмотря на то, что они оба имеют доступ к одному и тому же локальному хранилищу, они не знают, когда значения там обновляются.

Есть несколько способов справиться с этим, вот один из способов

создать реактивный объект вне компонентов для управления общим состоянием

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 вычисляемый геттер запускал уведомления для своих слушателей.

Если вы загрузите это перед любым из компонентов, вы создадите вычисляемую (реактивную) переменную, доступную для любого скрипта на странице (кроме фреймов и теневого дома)

то вы можете использовать в своих компонентах, как это.

<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 вычисляется с помощью геттеров и сеттеров, вы можете установить значение прямо из шаблона или использовать this.is_expanded = !this.is_expanded в методах.

Как уже говорилось, это зависит от использования глобального объекта window. Это решение предлагается из-за его простоты. У использования объекта окна есть некоторые недостатки, и более надежное решение будет полагаться на внедрение такого общего состояния вместо того, чтобы полагаться на окно, но это связано с большими накладными расходами.

Другие вопросы по теме