Study background

In the daily use of social software such as Qiuqiu and wechat, we can often use their expression function, which is very convenient and quick. A good set of emojis can give users a good experience, like this screenshot of QQ emojis. Recently there has been a need to add this little expression to small programs, after trying and learning various methods, here is a summary.



The implementation process

  1. Storage and acquisition of facial expressions
  2. Make the marquee box
  3. rendering

1. Storage and acquisition of facial expressions

Premise: The emoticons mentioned in this article are mainly pictures in common formats such as.jpg.png.

This part is relatively simple, about the image storage, either locally or on the network. Although the ordinary little yellow face facial expressions 2x@png format is up to 1KB or so, but if you want to increase the different facial expressions later set of words also have dozens or even hundreds of KB, for the small program is still some unbearable.

So how do you get the web image to show up on the selection page? For example, [haha] is displayed as 😄 on the selection panel. We can use a function to generate the corresponding network address or create a mapping table to map the identifier to the corresponding image network address.

Function form implementation reference:

/ * * *@param {string[]} BaseUrl Header of the network address *@param {string[]} Sign Specifies the image identifier *@param {string[]} Ext image format *@return {string[]} * /
const imgAddMap = (baseUrl, sign, ext) = > {
  // Here you can further customize the sign.slice result to get the desired path
  return baseUrl + sign.slice(1, -1) + ext;
};

console.log(
    imgAddMap('http://localhost:8080/abc/'.'[haha]'.'.png'));// http://localhost:8080/abc/haha.png

Copy the code

Table implementation form reference:

// Implement an img util
const baseUrl = 'http://localhost:8080/abc';
const imgName = ['[haha]'.'[wuwu]' /*more ... * /];
const imgMap = {
  '[haha]': 'lalala.png'.'[wuwu]': 'yingyingying.png'.// more ...
};

/ * * *@param {string[]} ImgSign Identifies the image *@return {string[]}* /
const imgDisplay = (imgSign) = > {
  const _img = imgMap[imgSign];
  return _img ? baseUrl + _img : ' ';
};

console.log(imgDisplay('[haha]'));
// http://localhost:8080/abclalala.png

// export { imgName, imgMap, imgDisplay }; Finally, export the module

Copy the code

A brief comparison:

  • Function implementations do not need to declare other related variables or objects to store, but they need to be evaluated each time.
  • Table implementations are more efficient at lookups, but require additional objects to store addresses, formats, and so on.

2. Make a selection box

Before we use emojis we have to have a display page, a layout that you can easily think of and you just have to draw a square and put emojis in it.

// My personal habits are as follows#outer {
    position: relative;
    width: 12.5%;
    height: 0;
    padding-top: 12.5%;
}
// aspect-ratio: 1/1; inh5In the normal use, there seems to be a compatibility problem in wechat small program.inner {
    position: absolute;
    width: 100%;
    height: 100%;
    left: 0;
    top: 0;
}

Copy the code

The expression chooses the display part (here the expression is repeated several times in order to show the effect, which is actually lazy)

    <div id="outer">
      <div class="inner" v-for="item in imgName">
        <span class="img">
          <img
            :src="_imgDisplay(item)"
            alt=""
            style="width: 60%; height: 60%"
          />
        </span>
      </div>
    </div>
    
Copy the code

Sample picture: (12.5% / picture)

Here we add an input box and add the specified click event to the emoticon to add the emoticon identifier to the input box for later rendering.

Here, input value = current value + expression identifier is directly used for simple addition. No insert operation is implemented. H5, all kinds of small procedures to achieve different methods, you can try to insert in the cursor.

At this point, we are halfway there, and now we have to do the main rendering.

3. Rendering method

Now that we have the message, we need to consider how to render it into the message. Here are two reference methods:

  1. Use regular expressions to replace the contents in parentheses with images that are displayed with innerHTML
  2. Encapsulate a function to generate a string into a virtual DOM node

A. Regular expression replacement

/ * * *@param {string[]} MSG Content to be replaced *@return {string[]}* /
const imgTextReplacer = (msg) = > {
  return msg.replace(/\[([a-z0-9]+?)\]/g.(name) = > {
    // The regular expression replaces ~ according to its own needs
    if (imgDisplay(name)) {
      return `<img src="${imgDisplay(name)}" 
          class="imgText"></img>`;ImgText is the style of the final image
    } else {
      returnname; }}); };Copy the code

Display in HTML:

<div v-html="_imgTextReplace(inputContent)" class="_display"></div>

You can add imgText as mentioned earlier, or you can replace it with style, but don’t forget to align the image with the text. You can add the vertically centered align-items:baseline to the parent element._display, or you can add the style vertical-align: text-bottom to the image.imgText.

The updated hook adds the corresponding secondary processing to the element or removes the scoped attribute in the style

B.r ender function

/ * * *@param {string[]} MSG The message to render@return {string[]}* /
const imgTextParser = (msg) = > {
  const res = [];
  let left = -1;
  let right = -1;
  while (msg.length) {
    left = msg.indexOf('[');
    right = msg.indexOf('] ');
    if (left === 0) {
      if (right === -1) {
        res.push({ tag: 'text'.text: msg });
        break;
      }
      // find img in the table
      const _img = imgMap[msg.slice(0, right + 1)];
      if (_img) {
        res.push({
          tag: 'image'.src: baseUrl + _img,
        });
        msg = msg.slice(right + 1);
      } else {
        res.push({
          tag: 'text'.text: '['}); msg = msg.slice(1); }}else {
      // Check if left is found
      constifFindLeft = left ! = = -1;
      res.push({
        tag: 'text'.text: ifFindLeft ? msg.slice(0, left) : msg,
      });
      msg = ifFindLeft ? msg.slice(left) : ' '; }}return res;
};

Copy the code

Code in the page structure (H5):

// A message<div class="_display">
  <div class="" v-for="_d in msg">
    <span v-if="_d.tag === 'text'"> {{ _d.text }} </span>
    <img :src="_d.src" alt="bq" style=""
        class="_img" v-if="msg.tag === 'image'" 
    />
  </div>
</div>

Copy the code

Final display effect

Sometimes it’s better to be centered

Regardless of which method you choose, pay attention to the timing of the rendering. Don’t call functions on the HTML like the one above, as frequent DOM manipulation can cause pages to get jammed. You should replace what you need in advance.

conclusion

Here we have achieved a simple expression selector, we can strengthen the function according to their preferences or needs, shortcomings or mistakes welcome to point out 🤗🤗🤗~