我正在尝试制作一个类似于 Medium 的文本编辑器。我正在使用一个内容可编辑的段落标记,并将每个项目存储在一个数组中,并使用 v-for 呈现每个项目。但是,我在使用 v-model 将文本与数组绑定(bind)时遇到了问题。似乎与 v-model 和 contenteditable 属性存在冲突。这是我的代码:
<div id="editbar">
<button class="toolbar" v-on:click.prevent="stylize('bold')">Bold</button>
</div>
<div v-for="(value, index) in content">
<p v-bind:id="'content-'+index" v-bind:ref="'content-'+index" v-model="content[index].value" v-on:keyup="emit_content($event)" v-on:keyup.delete="remove_content(index)" contenteditable></p>
</div>
在我的脚本中:
export default {
data() {
return {
content: [{ value: ''}]
}
},
methods: {
stylize(style) {
document.execCommand(style, false, null);
},
remove_content(index) {
if(this.content.length > 1 && this.content[index].value.length == 0) {
this.content.splice(index, 1);
}
}
}
}
我还没有在网上找到任何答案。
最佳答案
我试了一个例子,eslint-plugin-vue报告 v-model
在 p
元素上不受支持。查看valid-v-model规则。
截至撰写本文时,Vue 似乎并未直接支持您想要的内容。我将介绍两个通用解决方案:
直接在可编辑元素上使用输入事件
<template>
<p
contenteditable
@input="onInput"
>
{{ content }}
</p>
</template>
<script>
export default {
data() {
return { content: 'hello world' };
},
methods: {
onInput(e) {
console.log(e.target.innerText);
},
},
};
</script>
创建可重用的可编辑组件
Editable.vue
<template>
<p
ref="editable"
contenteditable
v-on="listeners"
/>
</template>
<script>
export default {
props: {
value: {
type: String,
default: '',
},
},
computed: {
listeners() {
return { ...this.$listeners, input: this.onInput };
},
},
mounted() {
this.$refs.editable.innerText = this.value;
},
methods: {
onInput(e) {
this.$emit('input', e.target.innerText);
},
},
};
</script>
index.vue
<template>
<Editable v-model="content" />
</template>
<script>
import Editable from '~/components/Editable';
export default {
components: { Editable },
data() {
return { content: 'hello world' };
},
};
</script>
为您的特定问题定制解决方案
经过多次迭代,我发现对于您的用例,通过不使用单独的组件更容易获得可行的解决方案。 contenteditable
元素似乎非常棘手 - 特别是在列表中呈现时。我发现我必须在删除后手动更新每个 p
的 innerText
才能使其正常工作。我还发现使用 id 有效,但使用 refs 无效。
可能有一种方法可以在模型和内容之间实现完整的双向绑定(bind),但我认为这需要在每次更改后操纵光标位置。
<template>
<div>
<p
v-for="(value, index) in content"
:id="`content-${index}`"
:key="index"
contenteditable
@input="event => onInput(event, index)"
@keyup.delete="onRemove(index)"
/>
</div>
</template>
<script>
export default {
data() {
return {
content: [
{ value: 'paragraph 1' },
{ value: 'paragraph 2' },
{ value: 'paragraph 3' },
],
};
},
mounted() {
this.updateAllContent();
},
methods: {
onInput(event, index) {
const value = event.target.innerText;
this.content[index].value = value;
},
onRemove(index) {
if (this.content.length > 1 && this.content[index].value.length === 0) {
this.$delete(this.content, index);
this.updateAllContent();
}
},
updateAllContent() {
this.content.forEach((c, index) => {
const el = document.getElementById(`content-${index}`);
el.innerText = c.value;
});
},
},
};
</script>
关于javascript - Vue 2 contentEditable with v-model,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53899676/