背景
产品要做一个类似豆瓣那样的发布功能,需要在文章插入图片,类似富文本编辑器,但其实又用不到那么多功能,于是决定自己开发
问题分析
- 如何让普通div可以编辑;
- 点击选择图片后如何记住光标的位置;
- 选择图片后如何插入到对应位置。
<template>
<div>
<editor v-model="content" ref="myEditor"></editor>
</div>
</template>
<script>
import editor from '@/components/editor/index.vue';
export default {
name: "CommentPublish",
components: {
editor
},
data() {
return {
content: '',
}
},
methods: {
// 插入图片,实际中应该是上传完图片然后插入
insertImg() {
const HTML = `<div><img src="yourImage.png"></div>`
this.$refs.myEditor.insert(HTML)
}
}
}
</script>
/**
* editor/index.vue
*/
<template>
<div class="editor-wrap"
v-html="editorHtml"
ref="editor"
contenteditable="true"
@focus="isLocked = true"
@blur="isLocked = false"
@click="saveRange"
@input="changeText">
</div>
</template>
<script>
export default {
name: "editor",
props: ['value'],
data() {
return {
editorHtml: this.value,
isLocked: false,
range: ''
}
},
watch: {
'value'(val){
if (!this.isLocked && !this.editorHtml) { // 解决光标错位的问题
this.editorHtml = val;
}
}
},
methods: {
changeText() {
this.$emit('input', this.$el.innerHTML);
this.saveRange()
},
// 记录光标位置,本来是放在@blur里的,即失焦时记录光标位置;后面发现IOS下blur不能记录到,所以现在的做法是点击或者输入的时候记录
saveRange() {
const selection = window.getSelection ? window.getSelection() : document.getSelection()
this.range = selection.getRangeAt(0)
},
// 设置焦点位置
setRange() {
const selection = window.getSelection ? window.getSelection() : document.getSelection()
selection.removeAllRanges()
if (this.range) {
selection.addRange(this.range)
} else {
this.$refs.editor.focus()
}
},
insert(html) {
this.setRange()
document.execCommand("insertHTML", false, html);
}
}
</script>