在vue开发需要使用div来做页面编辑器,跟另一个子组件的text相互联动起来,实现数据双向绑定,具体要求父组件下的两个子组件能实现数据绑定,不管是操作哪个组件,两个组件显示的值是一样的。
1、定义 DivEditable.vue组件,设置div添加contenteditable=true属性,实现可实时编辑,在父组件中调用DivEditable时添加v-model,用props接收父组件的值 ,并 watch 监听,通过@input事件把输入的值传递给父组件;
2、定义 SubText.vue组件,添加 input输入框,用 props绑定父组件传过来的值,并 watch 来监听修改值后,通过 this.$emit 把值传递给父组件;
3、两个子组件通过父组件可实现数据双向绑定。
在 DivEditable组件编辑时,发现每输入一次光标都会定位到最前面,并且输入不了中文。
(1)通过打断点可以看到,当你输入的时候触发input事件,提交值给父组件中的v-model;
(2)但因为在子组件中又监听了v-model的值,所以整体形成了闭环;
(3)还需要重点说明的是光标问题,contenteditable与v-html所在的元素值的改变如果不是通过输入而是通过赋值实现,光标就会跑到最前面;
所以以输入中文为例,你刚打了一个字母,立马就触发了监听与变动,光标移到最前面,自然无法完成整个正常的输入。
只有当blur的时候再做赋值操作(isChange为true),focus状态下不做赋值(isChange为false);至于初始为true的原因是在父组件中直接给绑定的变量赋值时子组件中还是需要触发赋值的(isChange为true)
<template>
<div class="edit-div"
v-text="innerText"
:contenteditable="canEdit"
@input="changeText"
@focus="isChange = false"
@blur="blurFunc">
</div>
</template>
<script>
export default{
name: 'editDiv',
props: {
value: {
type: String,
default: ''
},
canEdit: {
type: Boolean,
default: true
},
},
data(){
return {
innerText: filterXSS(this.value),
isChange: true
}
},
watch: {
value() {
if (this.isChange) {
this.innerText = this.value
}
}
},
methods: {
changeText() {
this.$emit('input', this.$el.innerText)
},
blurFunc() {
this.isChange = true
this.$emit('blurFunc')
}
}
}
</script>
<style>
.edit-div {
width: 100%;
height: 100%;
overflow: initial;
outline: none;
user-select: none;
cursor: text;
}
</style>