Vuejs — делегирование событий и контекстная ссылка v-for

Я использую следующий фрагмент для отображения списка:

<div @click.prevent="myhandler($event)"><!-- Delegated event handler-->
    <div class="tasks" v-for="(task, subName) in step.tasks">
        <button type="button">
            {{ task.caption }}
        </button>
        <span> {{ task.callableName }} </span>
    </div>
</div>
methods: {
    myhandler(e){
        // Event target may be a button element.
        let target = e.target;
        // …
        // Let's assume we know 'target' is a button element instance.
        // I wish I could have access to the v-for item ("task") which is associated in some ways to the button that was clicked.
        // let the_task_reference = ?;
    }…

Есть ли простой способ, чтобы я мог выполнить конкретную задачу v-for, связанную с этой кнопкой?
Спасибо.


person Stphane    schedule 11.05.2017    source источник


Ответы (2)


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

<div class="tasks" v-for="(task, index) in step.tasks">
    <button type="button" :data-index="index">
        {{ task.caption }}
    </button>
    <span> {{ task.callableName }} </span>
</div>

И в вашем обработчике получить задание с помощью индекса.

myhandler(evt){
  const task = this.step.tasks[evt.target.dataset.index]
  ...
}

Пример.

Если бы у вас было что-то более сильное, например id, было бы еще лучше.

Не рекомендуется

Существует скрытое свойство __vue__, которое добавляется к корневым элементам Vue и Component. Если бы вы перебирали компонент, вы могли бы сделать что-то как в этом примере< /а>.

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

person Bert    schedule 11.05.2017
comment
Вот о чем я думал. Я, вероятно, выберу его, так как другой хорошей альтернативы, похоже, нет. Я оставлю этот вопрос еще на один день и рассмотрю ваш ответ как решение. Спасибо. - person Stphane; 11.05.2017

Самым простым решением было бы поместить обработчик событий в тот же div, что и директива v-for, и просто передать переменную task:

<div 
  class="tasks" 
  v-for="(task, subName) in step.tasks"
  @click.prevent="myhandler(task, $event)"
>
  <button type="button">{{ task.caption }}</button>
  <span>{{ task.callableName }}</span>
</div>

Если вам действительно нужно использовать обработчик событий для родительского элемента, вы можете отслеживать задачу, на которую нажали, через свойство компонента и добавить дополнительный обработчик кликов в div с помощью директивы v-for:

<div @click.prevent="myhandler($event)"
  <div 
    class="tasks" 
    v-for="(task, subName) in step.tasks" 
    @click="clickedTask = task"
  >
    <button type="button">{{ task.caption }}</button>
    <span>{{ task.callableName }}</span>
  </div>
</div>

Вам нужно будет добавить свойство clickedTask:

data() {
  return {
    clickedTask: null,
  }
}

И тогда в обработчике можно было обратиться к задаче через this.clickedTask.

person thanksd    schedule 11.05.2017
comment
Спасибо, но я это знаю. Как я уже говорил, здесь мне нужно использовать делегирование событий. Другими словами, я хочу, чтобы первый общий предок обрабатывал событие, а это означает, что мне нужен способ сослаться на объект задачи, когда у меня есть доступ только к элементу кнопки, являющемуся целью события. - person Stphane; 11.05.2017
comment
@Stphane нет возможности напрямую получить доступ к переменной task из события за пределами его области. Вам нужно будет установить дополнительную ссылку. Смотрите мое обновление - person thanksd; 11.05.2017
comment
Я думал, что какое-то скрытое свойство экземпляра vue поможет, но оказалось, что такого не существует. Я боюсь, что ваше окончательное решение приведет к слишком большим накладным расходам. Во-первых, потому что обработчик кликов по-прежнему будет зарегистрирован на каждом элементе v-for div (чего я хотел избежать в первую очередь), во-вторых, потребуются новые проксированные данные. Я покопаюсь и дам вам знать, чем я закончил. Еще раз спасибо. - person Stphane; 11.05.2017