Я попробовал пример, и 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>
Создание повторно используемого редактируемого компонента
Редактируемый.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
чрезвычайно сложны, особенно при отображении в списке.Я обнаружил, что мне пришлось вручную обновлять innerText
каждого p
после удаления, чтобы он работал правильно.Я также обнаружил, что использование идентификаторов работало, но использование ссылок не помогло.
Возможно, существует способ получить полную двустороннюю привязку между моделью и содержимым, но я думаю, что для этого потребуется манипулировать расположением курсора.после каждого изменения.
<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>