gpt4 book ai didi

javascript - 如何使 focus() 在显示的 DOM 元素之前工作

转载 作者:搜寻专家 更新时间:2023-10-30 22:19:03 25 4
gpt4 key购买 nike

更新:事实证明在 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让focus工作吗?

谢谢

最佳答案

最好使用vm.$nextTickVue.nextTick(我们不需要关心nextTick 甚至实际上使用了 setTimeout,Vue 将保证 nextTick 会完成它的工作,即使将来 nextTick 可能会使用其他方法实现相同的目标)。

作为Vue API: nextTick说,

Defer the callback to be executed after the next DOM update cycle. Useit immediately after you’ve changed some data to wait for the DOMupdate.

你也可以查看Vue Guide: Async Update Queue

对于您的情况,当单击按钮显示输入时,它将执行 this.showtext=true,然后执行 element.focus。但实际上 Dom 元素仍然是不可见的(VNode 已更改,但 Vue 尚未重新渲染和修补)。

所以你必须使用 vm.$nextTickVue.nextTick 来执行 .focus after 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) 向任务队列添加了一个任务。但是它会在下一个事件循环执行,但是render会在当前事件循环执行微任务后执行。

检查 HTML SPEC: event loop processing model (请查看第7步),当前任务(包括this.showtext为true,数据 react 触发重新渲染)已经执行(将从任务队列中删除)后,系统将首先呈现,然后从队列中弹出一个任务(如果 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 ,它会比我的描述得更好。

关于javascript - 如何使 focus() 在显示的 DOM 元素之前工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52229976/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com