Пользовательский v-focus не работает, когда в родительском узле много v-if

Я определяю пользовательскую директиву "focus" в моем компоненте:

<script>
    export default {
        name: 'demo',
        data () {
            return {
                show: true
            }
        },
        methods: {
            showInput () {
                this.show = false
            }
        },
        directives: {
            focus: {
                inserted: function (el) {
                    el.focus()
                }
            }
        }
    }

И это мой HTML-шаблон:

<template>
    <div>
        <input type="number" id="readonly" v-if="show">
        <button type="button" @click="showInput" v-if="show">show</button>
        <input type="number" id="timing" v-model="timing" v-if="!show" v-focus>
   </div>
</template>

Но когда я нажимаю button, input#timing не могу автофокусироваться.

Когда я положил input#readonly а также button в div и использовать только один V-если, input#timing может быть автофокус:

<template>
    <div>
        <div v-if="show">
            <input type="number" id="readonly">
            <button type="button" @click="showInput">show</button>
        </div>
        <input type="number" id="timing" v-model="timing" v-if="!show" v-focus>
   </div>
</template>

Вот почему???

1 ответ

Решение

Код директивы действительно работает и фокусируется <input>,

Но это удаляется из DOM! Когда это происходит, оно теряет фокус. Проверьте консоль скрипки ниже: https://jsfiddle.net/acdcjunior/srfse9oe/21/

Другим важным моментом является то, что, когда inserted называется, <input id="timing"> находится в DOM (как упоминалось выше), но находится в DOM в неправильном месте (между <p>a</p> а также <p>b</p> где это никогда не должно было быть). Это происходит потому, что Vue пытается повторно использовать элементы.

И когда nextTick триггеры (см. скрипку), он находится в правильном положении (между <p>c</p> а также <p>d</p>), потому что Vue переместил его в правильное место. И это движение, которое фокусируется.

И потому что nextTick запускается после того, как DOM перемещается, фокусировка сохраняется (см. ниже).

С помощью Vue.nextTick():

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

new Vue({
  el: '#app',
  data() {
    return {
      show: true,
      timing: 123
    }
  },
  methods: {
    showInput() {
      this.show = false
    }
  },
  directives: {
    focus: {
      inserted: function(el) {
        Vue.nextTick(() => el.focus());               // <======== changed this line
      }
    }
  }
})
<script src="https://unpkg.com/vue"></script>

<div id="app">
  <div>
    <input type="number" id="readonly" v-if="show">
    <button type="button" @click="showInput" v-if="show">show</button>
    <input type="number" id="timing" v-model="timing" v-if="!show" v-focus>
  </div>
</div>

Другие вопросы по тегам