Скрытие элементов списка

144
15 ноября 2020, 21:40

Подскажите пожалуйста как реализовать такую возможность: Чтобы когда нажималась кнопка Войти в комнату, уже открытая комната закрывалась? Либо когда нажималась кнопка Войти в комнату, весь список скрывался, кроме выбранной комнаты?

Answer 1

Постарался в комментариях кода объяснить каким образом можно реализовать передачу свойств между компонентами. Это как один из вариантов.

Vue.component('rooms-list', { 
  template: `<div> 
      <h1 v-if="currentRoom">Вы в комнате  {{ currentRoom }}</h1> 
      <h1 v-else>Выберите комнату</h1> 
      <template v-for="room in rooms"> 
        <room-row 
          v-bind="room" 
          :current.sync="currentRoom" 
          @update-room="onUpdateRoom" /> 
      </template> 
    </div>`, 
  /** 
   * Эти свойства были переданы в этот компонент как v-bind="rooms". 
   */ 
  props: { 
    // Список всех комнат. 
    list: Array, 
    // Поле с номером текущей комнаты. 
    current: Number 
  }, 
  data() { 
    return { 
      // Для работы с переданными свойствами задаём им локальный статус. 
      rooms: this.$props.list, 
      currentRoom: this.$props.current, 
    } 
  }, 
  methods: { 
    /** 
     * Обновляем данные о комнатах. 
     * Данный метод вызывается из дочернего путем 
     * this.$emit('update-room', {...}) 
     */ 
    onUpdateRoom(room) { 
      // Ищем индекс переданной `room` комнаты в списке. 
      const roomIndex = this.rooms 
        .findIndex(item => item.id === room.id) 
 
      // Обновляем информацию о комнатах. 
      this.rooms.splice(roomIndex, 1, room) 
    } 
  }, 
}) 
 
Vue.component('room-row', { 
  template: `<div> 
      <div v-if="isActiveRoom"> 
        <button type="button" @click="cameOut">Выйти из комнаты №{{ id }}</button><br/> 
        <label><input type="checkbox" v-model="active" /> Лампочка {{ active | humanValue }}</label> 
      </div> 
      <div v-else-if="nonSelectedRoom"> 
        <button type="button" @click="comeIn">Войти в комнату №{{ id }}</button> 
      </div> 
    </div>`, 
  props: { 
    id: Number, 
    activeLamp: Boolean, 
    // Поле с номером текущей комнаты, переданный с модификатором `.sync` 
    // Модификатор обеспечит двустороннюю привязку. 
    // При изменении его в одном из компонентов, остальные компоненты, 
    // через родительский будут об этом знать незамедлительно. 
    current: Number, 
  }, 
  data() { 
    return { 
      // Определяем модель для состояния лампочки. 
      active: this.$props.activeLamp 
    } 
  }, 
  computed: { 
    /** 
     * Мы находимся в этой комнате. 
     * Отобразим лампочку и создадим возможность выйти из комнаты. 
     */ 
    isActiveRoom() { 
      return this.current === this.id 
    }, 
    /** 
     * Мы не в одной из комнат. 
     * Отобразим весь список комнат. 
     */ 
    nonSelectedRoom() { 
      return !this.current 
    } 
  }, 
  filters: { 
    humanValue(value) { 
      return !!value ? 'включена' : 'выключена' 
    } 
  }, 
  methods: { 
    /** 
     * Заходим в комнату. 
     */ 
    comeIn() { 
      // Оповещаем родительский компонент о том, 
      // что необходимо обновить данные о номере текущей комнаты. 
      this.$emit('update:current', this.id) 
    }, 
    /** 
     * Выходим из комнаты. 
     */ 
    cameOut() { 
      // Хлопаем дверью. 
      this.$emit('update:current', 0) 
      // Обновляем данные о текущей комнате в родительском компоненте. 
      // Родительский элемент в свою очередь вызовет метод, 
      // записанный как `@update-room="onUpdateRoom"` 
      this.$emit('update-room', { 
        id: this.id, 
        activeLamp: this.active 
      }) 
    }, 
  } 
}) 
 
const APP = new Vue({ 
  el: '#app', 
  data: { 
    // Наша модель. Так сказать общага ) 
    rooms: { 
      // Поле с номером текущей комнаты. 
      // По умолчанию мы никуда еще не вошли. 
      current: 0, 
      // Список всех комнат. 
      // Первое поле - это номер. 
      // Второе - отображает состояние выключателя 
      list: [{ 
          id: 1, 
          activeLamp: false 
        }, 
        { 
          id: 2, 
          activeLamp: false 
        }, 
        { 
          id: 3, 
          activeLamp: false 
        }, 
        { 
          id: 4, 
          activeLamp: false 
        }, 
        { 
          id: 5, 
          activeLamp: false 
        }, 
      ] 
    } 
  }, 
})
<div id="app"> 
  <!-- 
    Передаём данные о комнатах - v-bind="rooms" как объект. 
    Эти данные определены при инициализации App в поле `data: {...}`. 
    Эта запись равнозначна записи 
      :current="rooms.current" :list="rooms.list" 
    НО: изменение объекта или массива внутри дочернего компонента 
    будет влиять на состояние родителя. 
  --> 
  <rooms-list v-bind="rooms"></rooms-list> 
  <pre>{{ rooms }}</pre> 
</div> 
 
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

Answer 2

Ваша проблема в том, что вы описываете лампочку только одной переменной - id, при этом никак не озвучивая, что ещё у лампы есть состояние. Как только вы введёте состояние в виде реактивной переменной ваша жизнь многократно упростится:

<template>
  <div>
    <div>лампа # {{ this.lamp.id }}, состояние: {{ lamp.light ? 'включена' : 'выключена' }}</div>
    <div>
      <button v-on:click="changeState">CLICKME</button>
    </div>
    <div v-if="lamp.light">ещё какой-то блок для включенной лампы</div>
    <div v-else>ещё какой-то блок для выключенной лампы</div>
  </div>
</template>
<script>
export default {
  name: "Lamp",
  props: {
    lamp: {
      id: 0,
      light: false
    }
  },
  methods: {
    changeState: function() {
      this.lamp.light = !this.lamp.light;
    }
  }
};
</script>

Теперь в списке ламп можно указывать их начальное состояние:

<template>
  <div>
    <h1>Hello lampls</h1>
    <lamp v-for="item in lamps" :key="item.id" :lamp="item"/>
  </div>
</template>
<script>
import Lamp from "@/components/Lamp";
export default {
  name: "Lamps",
  components: { Lamp },
  data() {
    return {
      lamps: [{ id: 1, light: false }, { id: 2, light: true }]
    };
  }
};
</script>

Проверяем работу:

<template>
  <div>
    <h1>Hello lampls</h1>
    <lamps></lamps>
  </div>
</template>
<script>
import Lamps from "@/components/Lamps";
export default {
  name: "HelloWorld",
  components: { Lamps }
};
</script>

Всё выводится, всё кликается:

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

Я пытался понять логику, у меня получалось, что вам нужно описывать состояние на уровне комнаты, но дальше начались сплошные предположения и я решил, что это вам лучше самому разобрать.

Вероятнее всего (но это чисто мои предположения), вы хотели логику "только одна из комнат может быть в состоянии Open. При нажатии на кнопку войти в комнату все остальные должны закрываться". Если так, то вам на уровне блока rooms нужна одна реактивная переменная selected_room_id и отрисовка room в зависимости от значения этой переменной (в самом простом случае можно обойтись только навешиванием/скрыванием css класса selected и описанием css правил типа display:none)

И вот ещё. Вы сейчас думаете об этой функциональности, как о размещённой на одной странице, но вполне возможно, что стоило бы рассмотреть это как два разных url: на одной есть список всех комнат и напротив каждой комнаты ссылка на переход к странице управления выбранной комнатой, где отображать название комнаты, списки её лампочек и т.п. В этом случае скрытие всех других комнат у вас будет "из коробки".

Подумайте, возможно у вас сформулируется на основании этого новый вопрос с новыми правилами что и как переключать.

READ ALSO
Как буквально перевести Class.prototype = Object.prototype

Как буквально перевести Class.prototype = Object.prototype

интересуют два меленьких вопроса, которые не хочется расписывать в двух разных вопросах!

144
Laravel vue cors - выдает ошибку

Laravel vue cors - выдает ошибку

Использую за основу этот проект: https://githubcom/cretueusebiu/laravel-vue-spa Так вот через axios нужно получить в виде json данные с другого сайта

120
Книги для изучения Javascript [дубликат]

Книги для изучения Javascript [дубликат]

Посоветуйте пожалуйста хорошую(-ие) книгу(-и) по JavascriptЯ новичок

120
Отображать месяц и год в datetimepicker?

Отображать месяц и год в datetimepicker?

На странице бутстраповский datetimepickerВ первый раз когда кликаю - все корректно

131