The project requirements are as follows: it is required to realize the "expression + text effect" similar to wechat chat 😀😀😀”
Three schemes of expression package
The implementation of expression package can be divided into the following three cases:
- Expression package: click expression - directly send a big expression (this scheme actually sends a defined picture)
- emoji icon expression: emoji icon expression that can be recognized by the system. This expression is relatively troublesome to implement. In fact, this method can be treated as a special 2-bit character
- Recommended emoji website: emojis
- Case: hefrog recruitment website
- Recommended emoji website: emojis
- Custom expression: the first version is designed and drawn. We need to send and echo text + expression
- Idea 1: when we click a single expression, we need to add an expression in the input box. This is the expression in the input box, which can be replaced by '[smile]'. Only when it is echoed, can we recognize the special expression and replace it with an expression
- Case: BOSS direct employment website
- Idea 2: the input box also needs to echo the expression. This method is relatively troublesome
- Case: wechat client
- Idea 1: when we click a single expression, we need to add an expression in the input box. This is the expression in the input box, which can be replaced by '[smile]'. Only when it is echoed, can we recognize the special expression and replace it with an expression
realization
Here, for the idea 2 of custom expression package, I think it is also the most troublesome implementation
Realization effect
Only the input box is implemented here. The echo of messages when data is transmitted to the back end is not described here. Presumably, everyone also has their own better design methods.
1. Layout
You may think that the input area can use input or textarea tags, but it is not suitable for 'text + custom image expression', but it is still feasible for other implementation schemes.
Realization idea
- Adopt div + contentitable = "true" attribute
- Example: '
This is an editable paragraph.
'
- Example: '
Contentditable attribute:
- Property specifies whether the element content is editable.
- All mainstream browsers support the contentable attribute
- Set true: the tag has @ fcous, @ input and other event functions by default
- Note: when the contenteditable attribute is not set in the element, the element will inherit from the parent element.
value | describe |
---|---|
true | Specifies that the element is editable |
false | The specified element is not editable |
<div id="emojiText" contenteditable="true" ref="edit" placeholder="Please enter the content" ></div>
2. Realize
The implementation idea here includes three directions:
- Add expression, add text
- Get the input message content and pass it to the back end
- Get the special message body '[smile]' and render the corresponding expression
Add expression, add text
Input text: simple input text is actually very simple. The idea is that the corresponding text content can be input in the editable area
Add expression: the implementation idea is that when clicking Add expression again, the expression address generation < img > label is inserted into the editable area
Problems with adding emoticons:
Question 1: when adding an expression, the cursor will not focus on the editable area
Problem 2: adding an expression cannot be added to the position where the cursor is positioned
Problem 1 solution
When adding an expression, check whether it is focused. If there is no focus, perform fcous forced focus
let obj = this.$refs.edit; // obj is an editable div let range, node; if (!obj.hasfocus) { obj.focus(); }
Problem 2 solution
window.getSelection: the selected text range or the current position of the cursor.
getRangeAt
Returns the Node at the beginning of the selection.
Generally, users can only select one range, so there is only one range. This method is generally getRangeAt(0)
range = window.getSelection().getRangeAt(0); range.collapse(false); //Move cursor to last node = range.createContextualFragment(Img); let c = node.lastChild; range.insertNode(node); if (c) { range.setEndAfter(c); range.setStartAfter(c); } let j = window.getSelection(); j.removeAllRanges(); j.addRange(range);
Complete code
<template> <div> <div id="emojiText" contenteditable="true" ref="edit" placeholder="Please enter the content" ></div> <ul> <li v-for="item in emojis" :key="item.name"> <img :src="item.path" alt="" @click="getEmojis" /> </li> </ul> <button @click="senMsg">send out</button> </div> </template> <script> export default { components: {}, data() { return { emojis: [ { name: "[emoji-1]", path: require("./assets/emojis/m1.png"), }, { name: "[smile]", path: require("./assets/emojis/m2.png"), }, { name: "[emoji-3]", path: require("./assets/emojis/m3.png"), }, ], }; }, mounted() {}, methods: { getEmojis(event) { let Img = `<img src="${event.target.src}" style='height:10px;'>`; let obj = this.$refs.edit; // obj is an editable div let range, node; if (!obj.hasfocus) { obj.focus(); } /* window.getSelection: The selected text range or the current position of the cursor. getRangeAt Returns the Node at the beginning of the selection. Generally, users can only select one range, so there is only one range. This method is generally getRangeAt(0) */ if (window.getSelection && window.getSelection().getRangeAt) { range = window.getSelection().getRangeAt(0); range.collapse(false); //Move cursor to last node = range.createContextualFragment(Img); let c = node.lastChild; range.insertNode(node); if (c) { range.setEndAfter(c); range.setStartAfter(c); } let j = window.getSelection(); j.removeAllRanges(); j.addRange(range); } else if (document.selection && document.selection.createRange) { document.selection.createRange().pasteHTML(Img); } }, senMsg() { console.log(this.$refs.edit.innerHTML); }, natchMsg() { let str = "such as'[smile]'asdtgsaghd[smile]ggg"; let newStr = str; this.emojis.forEach((item) => { console.log(str.indexOf(item.name)); if (str.indexOf(item.name) > -1) { let Img = `<img src="${item.path}" style='height:10px;'>`; newStr = str.replaceAll(item.name, Img); } }); console.log(newStr); }, }, }; </script> <style lang='scss' scoped> #emojiText { width: 600px; height: 300px; border: 1px solid #111; } ul { display: flex; list-style: none; } li img { width: 20px; height: 20px; } .msgicon { width: 10px; height: 10px; } </style>
Existing problem: the continuous expression in the input box is that you can't click the mouse to speak, the cursor can focus between the two expressions, and you can only focus with the left and right keys of the keyboard. (hope to provide a solution)