文章目录
- 普通实现的一个问题
- 解决问题
- nextTick
上一篇:(三十三)Vue之消息订阅与发布
首先先看这一个需求,给每个任务项新增一个编辑按钮
当编辑按钮点击时,任务项就会变成文本框,并且自动获取焦点
普通实现的一个问题
首先在Item组件定义元素
<li>
<label>
<input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)"/>
<span v-show="!todo.isEdit">{{todo.title}}</span>
<input v-show="todo.isEdit" type="text" :value="todo.title" @blur="handleBlur(todo,$event)" ref="inputTitle">
</label>
<button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
<button v-show="!todo.isEdit" class="btn btn-edit" @click="handleEdit(todo)">编辑</button>
</li>
回调实现
handleEdit(todo){
//查看每项是否有编辑标志属性,没有则加一个isEdit编辑属性
if (todo.isEdit !== undefined){//todo.hasOwnProperty('isEdit')
todo.isEdit = true
}else {
this.$set(todo,'isEdit',true)
}
this.$refs.inputTitle.focus()
},
//当文本框失去焦点
handleBlur(todo,e){
todo.isEdit = false
if (!e.target.value) return alert('输入不能为空')
this.$bus.$emit('updateTodo',todo.id,e.target.value)
}
App组件定义回调及利用全局事件总线绑定
回调
updateTodo(id,title){
this.todos.forEach((todo)=>{
if (todo.id === id) todo.title = title
})
}
在mounted钩子绑定事件
this.$bus.$on('updateTodo',this.updateTodo)
在beforeDestroy解绑事件
this.$bus.$off('updateTodo')
效果:当我们点击编辑按钮时,会变成文本框,但是不会自动获取焦点,原因是,vue在执行this.$set(todo,'isEdit',true)
这行代码,vue不会去重新解析模板,它会继续往下走,直到走完这个回调,当走到获取焦点的代码的时候,文本框还没有到页面中,这时一个顺序问题
解决问题
上面说到的问题是一个顺序问题,最简单的方法,把获取焦点的代码变成异步操作即可
setTimeout(()=>{
this.$refs.inputTitle.focus()
},200)
nextTick
要是很多次出现这个问题,就需要开很多定时器,我们知道,开定时器是有代价的,所以官方设计了一个API,用于异步更新操作
语法:this.$nextTick(回调函数)
作用:在下一次 DOM 更新结束后执行其指定的回调。
使用时机:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。
所以,获取焦点的操作就可以使用nextTick进行操作
this.$nextTick(function () {
this.$refs.inputTitle.focus()
})