Пользовательский 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>