electron+vue实现divcontenteditable截图功能
最近在学习基于electron + electron-vue开发聊天客户端项⽬时,需要⽤到编辑器插⼊表情功能。⼀般通过input或textarea也能实现,通过插⼊[笑脸]、(:12 这些标签,展⽰的时候解析标签就⾏。
如下图效果:
在⽹上到的jq插件实现在textarea光标处插⼊表情符标签
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link href="cdn.bootcss/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row">
<div class="col col-sm-12">
<button class="btn btn-success" data-emoj="[笑脸]">[笑脸]</button>
<button class="btn btn-success" data-emoj="[奋⽃]">[奋⽃]</button>
<button class="btn btn-success" data-emoj="[:17]">[:17]</button>
</div>
<div class="col col-sm-12">
<textarea class="form-control" id="content" rows="10"></textarea>
</div>
</div>
</div>
<script src="cdn.bootcss/jquery/3.3.1/jquery.min.js"></script>
<script>
(function ($) {
$.fn.extend({
insertEmojAtCaret: function (myValue) {
var $t = $(this)[0];
if (document.selection) {
this.focus();
sel = ateRange();
< = myValue;
this.focus();
} else if ($t.selectionStart || $t.selectionStart == '0') {
var startPos = $t.selectionStart;
var endPos = $t.selectionEnd;
var scrollTop = $t.scrollTop;
$t.value = $t.value.substring(0, startPos) + myValue + $t.value.substring(endPos, $t.value.length);
this.focus();
$t.selectionStart = startPos + myValue.length;
$t.selectionEnd = startPos + myValue.length;
$t.scrollTop = scrollTop;
} else {
this.value += myValue;
this.focus();
}
}
});
})(jQuery);
$("button").on("click", function() {
$("#content").insertEmojAtCaret($(this).attr("data-emoj"));
});
</script>
可是这种⽅法并不是我想要的类似编辑框插⼊表情效果。
如是就想到了div模拟设置contenteditable="true" 实现富⽂本编辑器效果,这种⽅法是可以实现,不过在vue中不能绑定v-model,最后参考⼀些技术贴实现了这个功能,⼀顿操作下来采坑不少,于是就做⼀些分享记录吧。
vue中通过给div添加contenteditable=true属性实现富⽂本功能
实现⽅式:
单独声明⼀个vue组件,chatInput.vue,通过监听数据变化并返回⽗组件。
1、⽗组件添加v-model
<template>
...
<chatInput ref="chatInput" v-model="editorText" @focusFn="handleEditorFocus" @blurFn="handleEditorBlur" />
</template>
import chatInput from './chatInput'
export default {
data () {
return {
editorText: '',
...
}
},
components: {
chatInput,
},
...
}
2、v-model中传⼊的值在⼦组件prop中获取
props: {
value: { type: String, default: '' }
},
data () {
return {
editorText: this.value,
...
}
},
watch: {
value() {
...
}
},
}
3、通过监听获取到的prop值,并将该值赋值给⼦组件中的v-html参数,双向绑定就ok了。chatInput.vue组件
<!-- vue实现contenteditable功能 -->
<template>
<div
ref="editor"
class="editor"
contenteditable="true"
v-html="editorText"
@input="handleInput"
@focus="handleFocus"
@blur="handleBlur">
</div>
</template>
<script>
export default {
props: {
value: { type: String, default: '' }
},
data () {
return {
editorText: this.value,
isChange: true,
}
},
watch: {
value() {
if(this.isChange) {
this.editorText = this.value
}
}
},
methods: {
handleInput() {
this.$emit('input', this.$el.innerHTML)
},
// 清空编辑器
handleClear() {
this.$refs.editor.innerHTML = ''
this.$refs.editor.focus()
},
// 获取焦点
handleFocus() {
this.isChange = false
this.$emit('focusFn')
},
// 失去焦点
handleBlur() {
electron vue教程this.isChange = true
this.$emit('blurFn')
},
/**
* @param html 需要插⼊的内容
*/
insertHtmlAtCaret(html) {
let sel, range;
if(!this.$refs.editor.childNodes.length) {
this.$refs.editor.focus()
}
if (Selection) {
// IE9 and non-IE
sel = Selection();
if (RangeAt && sel.rangeCount) {
range = RangeAt(0);
range.deleteContents();
let el = ateElement("div");
el.appendChild(html)
var frag = ateDocumentFragment(), node, lastNode;
while ((node = el.firstChild)) {
lastNode = frag.appendChild(node);
}
range.insertNode(frag);
if (lastNode) {
range = range.cloneRange();
range.setStartAfter(lastNode);
sel.addRange(range);
}
}
} else if (document.selection && pe != "Control") {
// IE < 9
ateRange().pasteHTML(html);
}
this.handleInput()
}
}
}
</script>
<style>
</style>
组件功能已经亲测,直接⼀次性拿⾛使⽤。
以下是⼀些参考:
1、vue官⽅描叙,⾃定义组件的v-model:
⼀个组件上的 v-model 默认会利⽤名为 value 的 prop 和名为 input 的事件,v-model的值将会传⼊⼦组件中的prop
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论