Передача свойств из родительского компонента во все включенные дочерние компоненты в Vue

1

Я хотел бы передать некоторые свойства родительского элемента всем своим дочерним элементам, когда они передаются (синтаксис распространения контента). В этом случае родитель не знает (насколько я знаю) своих детей, поэтому я не знаю, как действовать.

В частности, мне нужен способ написать это:

<my-parent prop1="foo" prop2="bar">
    <my-children></my-children> <!-- Must know content of prop1 and prop2 -->
    <my-children></my-children> <!-- Must know content of prop1 and prop2 -->
</my-parent>

Вместо того, чтобы писать это:

<my-parent prop1="foo" prop2="bar">
    <my-children prop1="foo" prop2="bar"></my-children>
    <my-children prop1="foo" prop2="bar"></my-children>
</my-parent>

Возможно ли это? Спасибо.

  • 0
    Вы рассматривали Vuex?
  • 1
    @ AldoRomo88 Пожалуйста, нет, я хочу передать глупый аргумент всем детям, а не управлять полным состоянием Redux. Плюс ко всему, это компоненты многократного использования, поэтому чем меньше у них зависимостей, тем лучше.
Теги:
vue.js
vue-component

3 ответа

1
Лучший ответ

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

Vue.component('my-children', {
    props: ["prop1", "prop2"],
    template: "<div>{{_prop1}} - {{_prop2}}</div>",
    computed: {
        _prop1: function() {
            return this.prop1 || this.$parent.prop1;
        },
        _prop2: function() {
            return this.prop2 || this.$parent.prop2;
        }
    }
});

Вот генератор mixin, который делает это более элегантным способом и, возможно, с несколькими уровнями:

function passDown(...passDownProperties) {
    const computed = {};
    passDownProperties.forEach((prop) => {
        computed["_" + prop] = function() {
            return this[prop] || this.$parent[prop] || this.$parent["_" + prop];
        };
    });
    return { computed };
}

Vue.component('my-children', {
    props: ["prop1", "prop2"],
    template: "<div>{{_prop1}} - {{_prop2}}</div>",
    mixins: [passDown("prop1", "prop2")]
});
  • 0
    Мне нравится! Ваше решение чище моего и работает очень хорошо
1

В этот момент (я не эксперт vue) я просто мог бы подумать в этом решении.

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

// Create a global mixin
Vue.mixin({
  mounted() { // each component will execute this function after mounted
    if (!this.$children) {
      return;
    }

    for (const child of this.$children) { // iterate each child component
      if (child.$options._propKeys) {
        for (const propKey of child.$options._propKeys) { // iterate each child props
          // if current component has a property named equal to child prop key
          if (Object.prototype.hasOwnProperty.call(this, propKey)) {
            // update child prop value
            this.$set(child, propKey, this[propKey]);

            // create a watch to update value again every time that parent property changes
            this.$watch(propKey, (newValue) => {
              this.$set(child, propKey, newValue);
            });
          }
        }
      }
    }
  },
});

Это работает, но вы получите сообщение об уродливом предупреждении vue:

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop value.

Я не уверен, что это хорошее решение, но оно работает, поэтому, если вы решите использовать, просто имейте в виду Global-Mixin рекомендации:

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

Пожалуйста, смотрите полный пример в https://github.com/aldoromo88/PropsConvention

Надеюсь, что это поможет

  • 0
    Спасибо за ваш ответ: я вхожу во что-то похожее на это, но предупреждение и необходимость явного наблюдения за каждой опорой были для меня немного отталкивающими. Я также представлю свое собственное решение, основанное на обратном подходе.
0

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

Проинсталлировать шину событий с пустым экземпляром Vue в основном файле.

var bus = new Vue();

Затем в своем родителе испускаем событие с передаваемыми данными

 bus.$emit('myEvent', dataToBePassed);

Слушайте myEvent в любом месте, где хотите получить данные. В вашем случае это делается в ваших дочерних компонентах

bus.$on('myEvent', function(data) {
     .....
});

Ещё вопросы

Сообщество Overcoder
Наверх
Меню