vue 实现双击编辑
双击编辑的实现思路
在Vue中实现双击编辑功能,通常需要结合事件监听和数据绑定。核心逻辑是:监听双击事件显示输入框,完成编辑后保存数据并隐藏输入框。
基础实现方案
创建可编辑的文本组件,默认显示文本内容,双击后切换为输入框:
<template>
<div>
<span v-if="!isEditing" @dblclick="startEditing">{{ content }}</span>
<input
v-else
ref="input"
v-model="tempContent"
@blur="saveEdit"
@keyup.enter="saveEdit"
/>
</div>
</template>
<script>
export default {
props: ['content'],
data() {
return {
isEditing: false,
tempContent: this.content
}
},
methods: {
startEditing() {
this.isEditing = true
this.$nextTick(() => {
this.$refs.input.focus()
})
},
saveEdit() {
this.isEditing = false
this.$emit('update:content', this.tempContent)
}
}
}
</script>
进阶优化方案
添加防抖处理和样式优化,提升用户体验:
<template>
<div class="editable-text">
<span
v-if="!isEditing"
@dblclick="startEditing"
class="text-display"
>{{ content }}</span>
<input
v-else
ref="input"
v-model="tempContent"
@blur="saveEdit"
@keyup.enter="saveEdit"
@keyup.esc="cancelEdit"
class="text-input"
/>
</div>
</template>
<script>
import { debounce } from 'lodash'
export default {
props: {
content: String,
delay: {
type: Number,
default: 300
}
},
data() {
return {
isEditing: false,
tempContent: this.content,
originalContent: this.content
}
},
methods: {
startEditing() {
this.isEditing = true
this.originalContent = this.tempContent
this.$nextTick(() => {
this.$refs.input.focus()
this.$refs.input.select()
})
},
saveEdit: debounce(function() {
this.isEditing = false
if (this.tempContent !== this.originalContent) {
this.$emit('update', this.tempContent)
}
}, 300),
cancelEdit() {
this.isEditing = false
this.tempContent = this.originalContent
}
}
}
</script>
<style>
.editable-text {
display: inline-block;
}
.text-display {
padding: 2px 5px;
cursor: text;
}
.text-display:hover {
background: #f0f0f0;
}
.text-input {
padding: 2px 5px;
border: 1px solid #ddd;
outline: none;
}
</style>
表格单元格双击编辑
针对表格场景的特殊处理方案:
<template>
<td @dblclick="startEditing">
<span v-if="!isEditing">{{ content }}</span>
<input
v-else
ref="input"
v-model="tempContent"
@blur="handleBlur"
@keyup.enter="handleBlur"
@keyup.esc="cancelEdit"
@click.stop
class="cell-input"
/>
</td>
</template>
<script>
export default {
props: ['content', 'rowIndex', 'colKey'],
data() {
return {
isEditing: false,
tempContent: this.content
}
},
methods: {
startEditing() {
this.isEditing = true
this.$nextTick(() => {
this.$refs.input.focus()
this.$refs.input.select()
})
},
handleBlur() {
this.isEditing = false
if (this.tempContent !== this.content) {
this.$emit('cell-update', {
rowIndex: this.rowIndex,
key: this.colKey,
value: this.tempContent
})
}
},
cancelEdit() {
this.isEditing = false
this.tempContent = this.content
}
}
}
</script>
<style>
.cell-input {
width: 100%;
height: 100%;
border: 2px solid #409eff;
box-sizing: border-box;
outline: none;
}
</style>
使用自定义指令实现
创建可复用的双击编辑指令:
Vue.directive('editable', {
bind(el, binding, vnode) {
let originalValue = binding.value
const input = document.createElement('input')
input.style.display = 'none'
input.value = originalValue
el.appendChild(input)
el.addEventListener('dblclick', () => {
el.firstChild.style.display = 'none'
input.style.display = 'inline'
input.focus()
})
input.addEventListener('blur', () => {
el.firstChild.style.display = 'inline'
input.style.display = 'none'
if (input.value !== originalValue) {
originalValue = input.value
el.firstChild.textContent = input.value
vnode.context[binding.expression] = input.value
}
})
input.addEventListener('keyup', (e) => {
if (e.key === 'Enter') input.blur()
})
},
update(el, binding) {
el.firstChild.textContent = binding.value
el.lastChild.value = binding.value
}
})
使用方式:
<span v-editable="textContent"></span>
注意事项
- 移动端适配需要考虑触摸事件替代双击事件
- 复杂数据结构编辑时需要深度拷贝原始值
- 性能优化时可考虑虚拟DOM和按需更新策略
- 表单验证场景需要结合编辑功能添加校验逻辑
- 无障碍访问需要添加适当的ARIA属性
以上方案可根据具体项目需求进行组合或调整,核心思想是通过状态管理切换显示模式,并处理好数据同步和事件冒泡问题。







