Как передать значение от одного дочернего компонента к другому в VueJS?

Полный исходный код: https://github.com/tenzan/menu-ui-tw

Демо: https://flamboyant-euclid-6fcb57.netlify.com/

Цель:

ItemsList и ItemImage являются дочерними компонентами Menu.vue. Мне нужно передать image_url от ItemsList до ItemImage, чтобы изменить изображение справа, после того, как элемент слева изменится автоматически по временным интервалам.

  • Левая сторона: компонент ItemsList.vue
  • Правая грань: компонент ItemImage.vue

введите здесь описание изображения

Компонент Menu.vue имеет 2 дочерних компонента:

<template>
  <div>
    <!-- Two columns -->
    <div class="flex mb-4">
      <div class="w-1/2 bg-gray-400">
        <ItemsList />
      </div>
      <div class="w-1/2 bg-gray-500">
        <ItemImage></ItemImage>
      </div>
    </div>
  </div>
</template>

<script>
import ItemsList from "./ItemsList";
import ItemImage from "./ItemImage";

export default {
  components: {
    ItemsList,
    ItemImage
  }
};
</script>

ItemsList.vue:

<template>
  <div>
    <div v-for="item in menuItems" :key="item.name">
      <ul
        class="flex justify-between bg-gray-200"
        :class="item.highlight ? 'highlight' : ''"
      >
        <p class="px-4 py-2 m-2">
          {{ item.name }}
        </p>
        <p class="px-4 py-2 m-2">
          {{ item.price }}
        </p>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      menuItems: [
        {
          name: "Apple",
          price: 20,
          image_url: "../assets/images/apple.jpg"
        },
        {
          name: "Orange",
          price: 21,
          image_url: "../assets/images/orange.jpg"
        },
        {
          name: "Banana",
          price: 22,
          image_url: "../assets/images/banana.jpg"
        },
        {
          name: "Grape",
          price: 23,
          image_url: "../assets/images/grape.jpg"
        }
      ]
    };
  },
  created() {
    var self = this;
    self.menuItems.map((x, i) => {
      self.$set(self.menuItems[i], "highlight", false);
    });
    var init = 0;
    setInterval(function() {
      if (init === self.menuItems.length) {
        init = 0;
      }
      self.menuItems[init].highlight = true;
      if (init === 0) {
        self.menuItems[self.menuItems.length - 1].highlight = false;
      } else {
        self.menuItems[init - 1].highlight = false;
      }
      init++;
    }, 2000);
  }
};
</script>

<style scoped>
.highlight {
  background-color: gray;
}
</style>

ItemImage.vue - почти пустой

<template>
  <div><p>Hello from ItemImage component</p></div>
</template>

<script>
export default {
  props: ["image_url"]
};
</script>

ItemsList просматривает каждый элемент и выделяет его. Мне понадобится компонент ItemImage, чтобы показать изображение для этого активного / выделенного элемента. URL-адрес изображения - item.image_url.


person Askar    schedule 22.01.2020    source источник


Ответы (2)


Вызвать событие в компоненте ItemsList с image_url, а в компоненте Menu передать image_url компоненту ItemImage в качестве опоры. Я сделал это в кодах ниже, и проверьте это.

https://codesandbox.io/s/wild-moon-mbto4

person Lucifer    schedule 22.01.2020

Вы можете попробовать создать событие из дочерний к родительскому компоненту.

В дочернем компоненте ItemsList.vue отправьте событие родительскому компоненту (где для свойства выделения установлено значение true):

created() {
    var self = this;
    self.menuItems.map((x, i) => {
      self.$set(self.menuItems[i], "highlight", false);
    });
    var init = 0;
    setInterval(function() {
      if (init === self.menuItems.length) {
        init = 0;
      }
      self.menuItems[init].highlight = true;

      //emit an event to trigger parent event
      this.$emit('itemIsHighlighted', menuItems[init].image_url)

      if (init === 0) {
        self.menuItems[self.menuItems.length - 1].highlight = false;
      } else {
        self.menuItems[init - 1].highlight = false;
      }
      init++;
    }, 2000);
  }

Затем в родительском компоненте Menu.vue:

<ItemsList @itemIsHighlighted="onItemHighlighted"/>
<ItemImage :image_url="this.selectedItem" ></ItemImage>

...

export default {
    data() {
        return {
            selectedItem: '' 
        } 
    }, 
    methods: {
        onItemHighlighted(value) {
            console.log(value) // someValue
            this.selectedItem = value
        }
    }
}

Я не мог проверить это, но надеюсь, что это поможет.

Вы также можете проверить это ответь здесь.

P.S. Использование Vuex значительно упростит эту задачу.

person nyagolova    schedule 22.01.2020
comment
Спасибо. В настоящий момент я не могу протестировать, но нажимать не буду. Я вижу, вы упомянули событие @click ... - person Askar; 22.01.2020
comment
Извините, я не понял, что строки выбираются по временным интервалам. Затем вам просто нужно поместить излучающее событие в функцию setInterval(), где свойство highlight установлено в true. Я обновил свой ответ. - person nyagolova; 22.01.2020