最近一直在学习 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 ShenZhen 2020-01-07 16:36:23 +08:00 有手机端模拟的吗? |