用户登录
用户注册

分享至

electron+vue实现div contenteditable截图功能

  • 作者: 管你看不看
  • 来源: 51数据库
  • 2021-09-21

最近在学习基于electron + electron-vue开发聊天客户端项目时,需要用到编辑器插入表情功能。一般通过input或textarea也能实现,通过插入[笑脸]、(:12 这些标签,展示的时候解析标签就行。

如下图效果:

 

在网上找到的jq插件实现在textarea光标处插入表情符标签

<!doctype html>
<html>
 <head>
 <meta charset="utf-8">
 <title></title>
 <link  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="http://www.51sjk.com/Upload/Articles/1/0/288/288899_20210728110137393.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>

可是这种方法并不是我想要的类似微信编辑框插入表情效果。

如是就想到了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中获取

export default {
 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() {
 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>

组件功能已经亲测,直接一次性拿走使用。

以下是一些参考:
1、vue官方描叙, 自定义组件的v-model:

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,v-model的值将会传入子组件中的prop

#自定义组件的-v-model
2、vue中div可编辑光标处插入内容

electron+vue中实现截图功能

主要使用的是微信截图dll,通过node执行即可

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)
 })
 })
},

总结

以上所述是小编给大家介绍的electron+vue实现div contenteditable截图功能,希望对大家有所帮助

软件
前端设计
程序设计
Java相关