Редактируемое поле Electron/vue contenteditable|Имитация скриншота WeChat

Electron
Электронно Vue Screenshot Функция | Электрон + Vue Достичь Div Editable Contabletable Вставить Smiley на основе

Чтобы не использовать vue для ручной сборки электронных приложений. электрон-вью использует все преимуществаvue-cliв качестве инструмента для строительных лесов, а также наличиеvue-loaderизwebpack,electron-packagerилиelectron-builder, а также некоторые из наиболее часто используемых плагинов, такие какvue-router,vuexи т.п.

Имитация редактора чата WeChat для вставки смайликов

Как реализовать клиент WeChat для вставки смайликов в курсор редактора? Обычно есть две идеи реализации:

  • общий метод (реализация ввода/текстовой области)

Реализовано через входную или текстуру, вставьте [Smiley], (: 12 тегов Emoji в текстовом поле, а также анализируют теги при отображении


Как на рисунке: эффект может быть достигнут следующим кодом

<!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>

Но описанный выше метод - это не то, что я хочу, чтобы вставить эффект изображения смайлика в поле редактирования.

  • редактируемые атрибуты div (настраиватьcontenteditable="true" выполнить)

Используйте div для имитации настроекcontenteditable="true"Реализуйте влияние богатого текстового редактора. Этот метод может вставить смазочные изображения в редактируемой области. Поскольку DIV не может быть связан с V-образностью в Vue, она должна быть транспонирована.


Как показано выше: установив divcontenteditable="true"Для достижения функции про-тест прошел.

Реализовать идеи

Создайте новый редактируемый компонент chatInput.vue, который прослушивает изменения данных и возвращается к родительскому компоненту.

1. Вызовите компонент chatInput.vue и привяжите к нему v-model

<template>
    ...
    <chatInput ref="chatInput" v-model="editorText" />
</template>

...

export default {
    data () {
        return {
            editorText: '',
            
            ...
        }
    },
    ...
}

2. Значение editorText, переданное в v-model, получается и отслеживается на предмет изменений в реквизите дочернего компонента.

Официальное описание Vue:
v-модель в компоненте по умолчанию будет использовать свойство с именем value и событие с именем input , а значение v-model будет передано в свойство в дочернем компоненте.

Talent.v UE JS.org/V2/expensive/co…

export default {
    props: {
        value: { type: String, default: '' }
    },
    data () {
        return {
            editorText: this.value,
            ...
        }
    },
    watch: {
        value() {
            ...
        }
    },
}

3. Отслеживая полученное значение prop и присваивая значение параметру v-html в подкомпоненте, реализуется двусторонняя привязка.

В vue компонент div[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();
	}
}

Но этот метод каждый раз, когда он позиционируется в конец ввода, не идеален~~

В этом случае благодаря этому совместному использованию прекрасно решается эффект вставки смайликов в курсор редактируемого поля div в vue.

blog.CSDN.net/WeChat_4391…

/**
 * 光标处插入内容
 * @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()
}

Компонент chatInput.vue

Ниже приведена реализация возможности редактирования в vue+electron.contenteditable="true"Вставить полный код выражения в месте курсора

<!-- 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>

div в vuecontenteditable = 'true'Также поддерживает событие вставки

Изображения чата можно отправлять, вставляя скриншоты в редактируемые поля.

// 可编辑div contenteditable中粘贴发送图片
handlePastImage {
	let that = this
	this.$refs.editor.addEventListener('paste', function(e) {
		let cbd = e.clipboardData
		let ua = window.navigator.userAgent
		if(!(e.clipboardData && e.clipboardData.items)) return
		
		if(cbd.items && cbd.items.length === 2 && cbd.items[0].kind === "string" && cbd.items[1].kind === "file" &&
			cbd.types && cbd.types.length === 2 && cbd.types[0] === "text/plain" && cbd.types[1] === "Files" &&
			ua.match(/Macintosh/i) && Number(ua.match(/Chrome\/(\d{2})/i)[1]) < 49){
			return;
		}
		for(var i = 0; i < cbd.items.length; i++){
			var item = cbd.items[i];
			console.log(item);
			console.log(item.kind);
			if(item.kind == "file"){
				var blob = item.getAsFile();
				if(blob.size === 0){
					return;
				}
				// 插入图片记录
				var reader = new FileReader();
				reader.readAsDataURL(blob);
				reader.onload = function(){
					var _img = this.result;

					// ***返回图片给父组件
					that.$emit('pasteFn', _img)
				}
			}
		}
	})
},

electronic-vue реализует функцию скриншота



1. Вызвать собственный API снимков экрана модуля через поддержку Electron: desktopCapturer

Для этого метода перейдите на официальный сайт api Ниже приводится подробное описание второго метода.

2. Запустите файл .exe через командную строку, чтобы вызвать dll

передано в nodejsexecFileМетод заключается в выполнении исполняемого файла, исполняемый файл вызывает 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)
		})
	})
},

Что ж, вышеизложенное основано на electro + vue, чтобы реализовать небольшой обмен записями редактора чата, вставляющего выражения и скриншоты, и мы продолжим делиться некоторыми электронными боевыми проектами в будущем.

Чат таро | реакция + имитация таро Интерфейс приложения чата WeChat | экземпляр чата таро