最近一直在学习 electron,基于 Electron-vue 实现 div 可编辑 contenteditable 插入表情及截图功能。
https://github.com/SimulatedGREG/electron-vue
为了避免使用 vue 手动建立起 electron 应用程序。electron-vue 充分利用 vue-cli 作为脚手架工具,加上拥有 vue-loader 的 webpack、electron-packager 或是 electron-builder,以及一些最常用的插件,如 vue-router、vuex 等等。
通过如下代码就行实现效果
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link href="https://cdn.bootcss.com/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="https://cdn.bootcss.com/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 = document.selection.createRange();
sel.text = 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>
</body>
</html>
可是上面方法只能插入表情符,而且还需要解析处理,有些麻烦,如果能通过直接插入表情图片实现就更好,如是就想到了 html5 中 div 有可编辑功能 contenteditable="true"
运用 div 模拟 设置 contenteditable="true" 实现富文本编辑器效果,这种方法可以在可编辑区插入表情图片,由于在 vue 中 div 不能绑定 v-model,需要另外处理。
如上图:就是通过设置 div 的 contenteditable="true" 来实现的效果就比较完美。
新建一个可编辑组件,chatInput.vue ,通过监听数据变化并返回父组件。
<template>
...
<chatInput ref="chatInput" v-model="editorText" />
</template>
...
export default {
data () {
return {
editorText: '',
...
}
},
...
}
export default {
props: {
value: { type: String, default: '' }
},
data () {
return {
editorText: this.value,
...
}
},
watch: {
value() {
...
}
},
}
vue 中,contenteditable=true 的组件作为文本输入框,在非手动输入值后, 如点击表情后,光标会丢失,可通过如下代码实现将光标定位到最后
function setLastAtCaret(obj) {
console.log(obj)
console.log(window.getSelection)
console.log(document.selection)
if (window.getSelection) { //ie11 10 9 ff safari
obj.focus(); //解决 ff 不获取焦点无法定位问题
var range = window.getSelection(); //创建 range
range.selectAllChildren(obj); //range 选择 obj 下所有子内容
range.collapseToEnd(); //光标移至最后
} else if (document.selection) { //ie10 9 8 7 6 5
var range = document.selection.createRange(); //创建选择对象
//var range = document.body.createTextRange();
range.moveToElementText(obj); //range 定位到 obj
range.collapse(false); //光标移至最后
range.select();
}
}
上面这种方法,每次都是定位到输入最后,也不是完美,最后通过下面这种方法即可完美解决了 vue 中 div 可编辑框光标处插入表情效果
/**
* 光标处插入内容
* @param html 需要插入的内容
*/
insertHtmlAtCaret(html) {
let sel, range;
if(!this.$refs.editor.childNodes.length) {
this.$refs.editor.focus()
}
if (window.getSelection) {
// IE9 and non-IE
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
let el = document.createElement("div");
el.appendChild(html)
var frag = document.createDocumentFragment(), node, lastNode;
while ((node = el.firstChild)) {
lastNode = frag.appendChild(node);
}
range.insertNode(frag);
if (lastNode) {
range = range.cloneRange();
range.setStartAfter(lastNode);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
}
} else if (document.selection && document.selection.type != "Control") {
// IE < 9
document.selection.createRange().pasteHTML(html);
}
this.handleInput()
}
<!-- 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() {
this.isChange = true
this.$emit('blurFn')
},
/**
* 光标处插入内容
* @param html 需要插入的内容
*/
insertHtmlAtCaret(html) {
let sel, range;
if(!this.$refs.editor.childNodes.length) {
this.$refs.editor.focus()
}
if (window.getSelection) {
// IE9 and non-IE
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
let el = document.createElement("div");
el.appendChild(html)
var frag = document.createDocumentFragment(), node, lastNode;
while ((node = el.firstChild)) {
lastNode = frag.appendChild(node);
}
range.insertNode(frag);
if (lastNode) {
range = range.cloneRange();
range.setStartAfter(lastNode);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
}
} else if (document.selection && document.selection.type != "Control") {
// IE < 9
document.selection.createRange().pasteHTML(html);
}
this.handleInput()
}
}
}
</script>
<style>
</style>
nodejs 中通过的 execFile 方法去执行 exe 文件,exe 调用同级目录下的 dll,调出截图工具
将 exe 和 dll 文件打包到 static 目录下,通过绝对路径去执行。exe 和 dll 可网上找。
screenShot() {
return new Promise((resolve) => {
const { execFile } = require('child_process')
var screenWin = execFile('./static/PrintScr.exe')
screenWin.on('exit', function(code) {
let pngs = require('electron').clipboard.readImage().toPNG()
let imgData = new Buffer.from(pngs, 'base64')
let imgs = 'data:image/png;base64,' + btoa(new Uint8Array(imgData).reduce((data, byte) => data + String.fromCharCode(byte), ''))
resolve(imgs)
})
})
},
okay~~ 以上就是基于 electron+vue 实现聊天编辑器插入表情、截图小功能分享。
最后附上 uniapp 案例项目:uniapp+vue+nvue 仿抖音短视频|直播 app
作者:xiaoyan2017
链接: https://juejin.im/post/5e141ffc5188253a57049a63
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
1
haocity 2020-01-07 16:30:08 +08:00
不错 感谢分享 昨天才遇到的问题 今天就解决了
聊天框插入表情光标移动到最后 本来是这样写的 ```javascript let range = window.getSelection().getRangeAt(0) range.setStartAfter(that.$refs.editor.lastChild); range.setEndAfter(that.$refs.editor.lastChild) ``` 结果 android 上面没问题 ios 光标雷打不动 |
2
SSREX 2020-01-07 16:30:12 +08:00 via iPhone
大佬!
|
3
Lucoie 2020-01-07 16:36:23 +08:00
有手机端模拟的吗?
|