更新:事实证明,在DOM渲染完成之前无法将焦点直接应用于文本框
我想知道为什么focus()函数不能在隐藏元素上起作用。
例如(我正在使用Vue.js):
var vm = new Vue({
el: "#app",
data:{
showtext: false
},
methods: {
showTxt(ev){
this.showtext = true
var vm = this;
// if I uncomment setTimeout, then the textbox can set focus
//setTimeout(function(){
vm.$refs.textbox.focus()
//}, 0)
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<button @click="showTxt">
Show Textbox and SetFocus on it
</button>
<div v-show="showtext">
<input ref="textbox" type="text" />
</div>
</div>
我想做的是单击该按钮并显示文本框并将焦点放在文本框中,但是当前,如果我直接调用.focus(),则文本框无法获得焦点。它仅在将setTimeout包裹起来时才起作用(我猜它会在下一个事件循环中运行)。我想知道是否有任何方法可以使焦点在没有setTimeout的情况下工作?
谢谢
答案 0 :(得分:4)
首选以使用vm.$nextTick
或Vue.nextTick
(即使实际使用nextTick
,我们也不必担心setTimeout
,Vue会保证nextTick
会继续努力,甚至将来nextTick
可能会使用其他实现相同目标的方法。
正如Vue API: nextTick所说,
推迟下一个DOM更新周期后执行的回调。采用 在您更改了一些数据以等待DOM之后 更新。
您还可以检查Vue Guide: Async Update Queue
对于您的情况,单击按钮显示输入时,它将执行this.showtext=true
,然后执行element.focus
。但是实际上Dom元素仍然不可见( VNode已更改,但Vue尚未重新渲染并修补)。
因此,您必须使用vm.$nextTick
或Vue.nextTick
来执行.focus
之后,Vue会重新渲染输入内容。
查看以下演示:
Vue.config.productionTip = false
var vm = new Vue({
el: "#app",
data:{
showtext: false
},
methods: {
showTxt(ev){
this.showtext = true
var vm = this;
console.log('Current:', this.$el.innerHTML)
this.$nextTick(()=>{
vm.$refs.textbox.focus()
console.log('Nexttick:', this.$el.innerHTML)
})
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<button @click="showTxt">
Show Textbox and SetFocus on it
</button>
<div v-show="showtext">
<input ref="textbox" type="text" />
</div>
</div>
setTimeout 为何起作用:
因为setTimeout(,0)
将一个任务添加到任务队列。但是它将在下一个事件循环中执行,但是在当前事件循环中执行微任务后,将执行渲染。
检查HTML SPEC: event loop processing model (请查看第7步),在当前任务(包括this.showtext为true,数据反应性触发器重新呈现)执行后(将从任务队列),系统将先渲染,然后再从队列中弹出一个任务(如果setTimeout(,0)
任务是最早的任务,则可能是setTimeout(,0)
。
但是 Promise是微任务,它将不起作用,因为它将在渲染之前执行(请在上方查看)事件循环处理模型:第6步)。
Vue.config.productionTip = false
var vm = new Vue({
el: "#app",
data:{
showtext: false
},
methods: {
showTxt(ev){
this.showtext = true
var vm = this;
new Promise((resolve, reject)=>{
vm.$refs.textbox.focus()
resolve()
}).then(()=>{
vm.$refs.textbox.focus()
})
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<button @click="showTxt">
Show Textbox and SetFocus on it
</button>
<div v-show="showtext">
<input ref="textbox" type="text" />
</div>
</div>
或者您可以查看此Youtube Video,它会比我的描述更好。
答案 1 :(得分:2)
仅当您使用其他设置焦点的方法(例如setTimeout
属性)时,才能摆脱autofocus
。没有它,您将不得不单独设置showtext
标志,并要求focus
进入单独的事件“滴答声”。
var vm = new Vue({
el: "#app",
data:{
showtext: false
},
methods: {
showTxt(ev){
this.showtext = true
this.$refs.textbox.focus()
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<button @click="showTxt">
Show Textbox and SetFocus on it
</button>
<div v-show="showtext">
<input ref="textbox" autofocus type="text" />
</div>
</div>
答案 2 :(得分:2)
隐藏元素无法通过焦点实体概念的性质来获得焦点。仅可见的和启用的。在任何UI系统中,都包含HTML / CSS DOM。