Динамические компоненты VueJS с динамическими событиями - PullRequest
0 голосов
/ 07 марта 2019

Из внешнего источника (например, API) я получаю определение компонента:

{
    "component": "b-btn",
    "content": "Button",
    "attr": {
        "title": "Edit"
    },
    "events": {
        "click": "doSomething"
    }
}

Это определение используется с динамическим компонентом:

<component :is="item.component" v-bind="item.attr">
    {{ item.content }}
</component>

и работает должным образом (показана кнопка vue-bootstrap с заголовком «Редактировать» и текстом кнопки «Кнопка»).

Теперь я хочу добавить события. Начиная с VueJS 2.4 (https://vuejs.org/v2/api/#v-on), вы можете определять события в синтаксисе объекта, например <button v-on="{ mousedown: doThis, mouseup: doThat }"></button>, я думал, что простое добавление v-on="item.events" может работать:

<component :is="item.component" v-bind="item.attr" v-on="item.events">
    {{ item.content }}
</component>

Но это не так, поскольку значение свойства объекта click является строкой ("doSomething") и не может быть вызвано.

// Just to make it clear
{"click": "doSomething"} != {"click": doSomething}

Есть ли способ привязать динамические события (из JSON) к компоненту?

1 Ответ

1 голос
/ 07 марта 2019

Да, это возможно. Вы должны программно проверить, существует ли функция с заданным именем в вашем компоненте, и если это так, используйте эту функцию вместо строки. Поэтому вам нужно манипулировать вашим JSON. Я создал тестовый пример в CodeSandbox, где я использую вычисляемое поле, которое обновляет свойство events, проверяя, существует ли функция с заданным именем для каждого ключа в events объекте, и заменяет значение функцией.

Скажем, у моего дочернего компонента есть событие clicked, которое срабатывает при нажатии на кнопку.

Мой родительский компонент выглядит так:

data() {
return {
  item: {
    component: "TestComponent",
    content: "Button",
    attr: {
      title: "Edit"
    },
    events: {
      clicked: "alertText"
    }
  }
};
},
computed: {
  componentItem() {
    let item = this.item;
    if (item.hasOwnProperty("events")) {
      let events = item.events;
      for (let i in events) {
        if (events.hasOwnProperty(i)) {
          let functionName = events[i];
          if (
            this.hasOwnProperty(functionName) &&
            typeof this[functionName] === "function"
          ) {
            // function exists
            item.events[i] = this[functionName];
          }
        }
      }
    }
    return item;
  }
},

methods: {
  alertText() {
    console.log("I was clicked");
  }
}

Смотрите рабочий пример здесь: https://codesandbox.io/s/oo9zj8qy9y

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...