@aleksspectr
веб-программист, изучаю серверы и железо

Как при клике на кнопку в блоке открывать модальное окно/выезжающий сайдбар с данными того блока, в котором находиться кнопка?

Изучаю vuex, делаю интерфейс "как бы админки".

Прототип интерфейса:
5da9c392bd719875750002.jpeg

Vuex:
export default {
  actions: {
    fetchData(ctx) {
      const data = require('../../data')
      localStorage.setItem('blocks', JSON.stringify(data))
      const blocks = JSON.parse(localStorage.getItem('blocks'))

      ctx.commit('updateBlockConfig', blocks)
    },

    toggle(state) {
      return state.isNavOpen = !state.isNavOpen;
    },

    loadConfigToBlock() {

    }

  },
  mutations: {
    updateBlockConfig(state, blocks) {
      return state.block_config = blocks
    },

    setIsNavOpen(state) {
      return state.isNavOpen = true;
    },

    toggleNav(state, i) {
      state.block_config[i]

      return state.isNavOpen = !state.isNavOpen;
    },

    closeSidebarPanel(state) {
      return state.isNavOpen = !state.isNavOpen;
    }
  },
  state: {
    block_config: [],
    isNavOpen: false,
  },
  getters: {
    getBlockConfig(state) {
      return state.block_config
    },

    getBlockModal(state) {
      return state.block_config.settings
    },

    isPanelOpen(state) {
      return state.isNavOpen
    }
  },
}

Компонент, в котором выводиться список блоков:
<template>
  <div id="app">
    <div class="content">
      <div class="blocks">
        <div class="block" v-for="block in getBlockConfig" :key="block.blockID" v-bind:style="{ background: `${block.color}` }">
          <h2 class="block-title">{{block.bName}}</h2>
          <div class="block-text">{{block.bText}}</div>
          <div>{{block.settings}}</div>
          <Trigger></Trigger> <!-- Кнопка вызова модального окна -->
        </div>
      </div>
      <Sidebar>
        <div class="sidebar-panel-settings">
          <div class="setting-block">
             <!-- Тут вывод данных блока, из которого вызвано окно -->
          </div>
        </div>
      </Sidebar>
    </div>
  </div>
</template>

<script>
import {mapGetters, mapActions} from 'vuex'
import Sidebar from './components/Menu/Sidebar.vue'
import Trigger from './components/Menu/Trigger.vue'

export default {
  name: 'app',
  components: {
    Sidebar,
    Trigger
  },
  computed: mapGetters(['getBlockConfig', 'isPanelOpen']),
  methods: mapActions(['fetchData', 'toggle']),
  async mounted() {
    this.fetchData()
  },
}
</script>

фейковые данные из json:
[
  {
  "blockID": 1,
  "bName": "Желтый блок",
  "bText": "Любая компания-производитель связывает с каждой своей новой моделью определенные надежды. Зачастую в связи с этим звучат громкие и красивые заявления - прорыв, революция, законодатель моды на ближайшее десятилетие... Но время тут - единственный по-настоящему объективный эксперт.",
  "color": "#FFFF00",
  "isOpen": false,
  "settings": [
    {
      "ID": 34,
      "Name": "Ширина",
      "stringType": "int",
      "filedType": "input",
      "fieldValue": "600",
      "fieldSize": 4
    },
    {
      "ID": 35,
      "Name": "Высота",
      "stringType": "int",
      "filedType": "input",
      "fieldValue": "500",
      "fieldSize": 4
    }
  ]
  },
  {
    "blockID": 2,
    "bName": "Розовый блок",
    "bText": "Любая компания-производитель связывает с каждой своей новой моделью определенные надежды. Зачастую в связи с этим звучат громкие и красивые заявления - прорыв, революция, законодатель моды на ближайшее десятилетие... Но время тут - единственный по-настоящему объективный эксперт.",
    "isOpen": false,
    "color": "#ffc0cb",
    "settings": [
      {
        "ID": 39,
        "Name": "Скрытое",
        "stringType": "int",
        "filedType": "input",
        "fieldValue": "600",
        "fieldSize": 4
      }
    ]
  }
]

Компонент кнопки:
<template>
  <button class="button-config" :class="{ 'active' : isPanelOpen }" @click.prevent="toggleNav" >Настройки</button>
</template>

<script>
import {mapMutations, mapGetters} from 'vuex'

export default {
  name: 'Trigger',
  methods: mapMutations(['toggleNav']),
  computed: mapGetters(['fetchData', 'isPanelOpen']),
}
</script>

Компонент сайдбара:
<template>
    <div class="sidebar">
        <div class="sidebar-backdrop" @click="closeSidebarPanel" v-if="isPanelOpen"></div>
        <transition name="slide">
          <div v-if="isPanelOpen"
                class="sidebar-panel">
                <a href="#" class="close-button" @click="closeSidebarPanel"></a>
              <slot></slot>
          </div>
        </transition>
    </div>
</template>
<script>
import {mapMutations, mapGetters} from 'vuex'

export default {
    name: 'Sidebar',
    methods: mapMutations(['closeSidebarPanel']),
    computed: mapGetters(['isBurgerActive', 'isPanelOpen']),
}
</script>

Собственно вопрос, как по клику на кнопку "настройки" выводить попап с настройками блока (в json-файле подобъект "settings") в формате формы заголовок с названием конфига + input с исходными данными и кнопкой "сохранить"?

Подскажите, как лучше всего это реализовать.
  • Вопрос задан
  • 316 просмотров
Решения вопроса 1
0xD34F
@0xD34F Куратор тега Vue.js
Добавляете в стейт свойство, которое будет представлять выбранный блок:

state: {
  opened: null,
  ...

В экземпляры компонента Trigger передавайте соответствующие им блоки:

<Trigger :block="block">

props: [ 'block' ],

Также, Trigger должен знать, какой блок открыт:

computed: mapState([ 'opened' ]),

Чтобы можно было назначить класс кнопке:

:class="{ 'active' : block === opened }"

При клике на которую следует передавать блок в мутацию:

@click="toggleNav(block)"

Мутация же будет устанавливать значение выбранного блока:

toggleNav(state, block) {
  state.opened = state.opened === block ? null : block;
},

Это если оно действительно toggle. Если просто открытие - тогда достаточно state.opened = block (название мутации в этом случае конечно следует поменять).

Мутация, отвечающая за закрытие, будет выглядеть так:

closeSidebarPanel(state) {
  state.opened = null;
},

Геттер isNavOpen тоже изменится:

isPanelOpen(state) {
  return !!state.opened;
},

Ну и наконец, можно что-нибудь вывести в Sidebar, например:

<span v-if="isPanelOpen">{{ $store.state.opened.bName }}</span>

Но если Sidebar предназначен конкретно для этих блоков, наверное, разумнее будет, чтобы он сам знал, кто сейчас открыт. В Sidebar'е цепляете opened к слоту:

<slot :block="$store.state.opened"></slot>

Соответственно, в родительском компоненте:

<template #default="{ block }">
  <div class="sidebar-panel-settings">
    <div class="setting-block">
      {{ block.bName }}
    </div>
  </div>
</template>
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы