vue.jsvuejs2emojiemojionetwemoji

Implementing Emojis in a VueJs App


I am looking to setup emojis to my chat-app project. I really liked the emojis in slack / tweeter and I would like to have something similar.

I found the following libraries: (if anyone can suggest a better library I would love to hear)

emojionearea

wdt-emoji-bundle

I am not sure how to load these libraries and use them in a VueJS app. Could anyone please assist with how to load and use them?

I would like to mention I tried to use emoji-mart-vue but not sure how to add the the component to the template at run time.

Thanks a lot


Solution

  • tldr; Checkout demo and code on JSFiddle


    This answer is divided into two parts. First part deals with how to import all the stuff into the environment while the second part deals with how to use it Vue.

    This solution uses EmojiOne as the emoji provider and EmojioneArea to provide emoji autocomplete behavior.


    Part 1: Adding the libraries

    There are three ways in which you can do this.

    BONUS: Using webpack with require.js and offloading network and caching loads to CDN!
    I often use this setup for my projects and this improves reliability and performance of your site. You can use webpack.externals to instruct webpack to not bundle any vendor dependencies and instead you provide them yourself, either by manually adding <script> tags or using require.js.

    Start by adding this to your webpack.<whatever>.js

    //...
    output: {
      libraryTarget: 'umd'   // export app as a library
    },
    //...
    externals: {
      'jquery': 'jquery',
      'vue': 'Vue',
      'emojione': 'emojione'
    },
    //...
    

    Then, in your require.js entry, add this

    //...
    map: {
      // any module requesting jquery should get shield
      "*": {
        "jquery": "jquery-shield"
      },
      // shield should get original jquery
      "jquery-shield": {
        "jquery": "jquery"
      },
      // patch plugins
      "jquery.textcomplete": {
        "jquery": "jquery"
      },
      "emojionearea": {
        "jquery": "jquery"
      }
    }
    //...
    // define shield, require all the plugins here
    define('jquery-shield', ['jquery', 'jquery-textcomplete', 'emojionearea'], function($){ return $ })
    

    and then add require(...) your webpack bundle


    Part 2: Using EmojiOne with Vue

    As the OP mentioned his/her case is to use emojis in a chat app, I would also explain the solution with that case, though this can (and should) be modified for other use cases too!

    The solution focuses on two aspects. First is to simply display the emoji in a message component, i.e., no need to display an emoji picker dialog and second is to display a emoji picker dialog whilst the user is typing into (say) a textarea.

    To achieve the first goal, you can use a message component like,

    Vue.component('message', {
      props: ['content'],
      render: function(h){
        return h('div', {
          class: { 'message': true }
        }, [
          h('div', {
            class: { 'bubble': true },
            domProps: {
              innerHTML: emojione.toImage(this.content)
            }
          })
        ])
      }
    })
    

    This would create a <message /> component which you can use as

    <message content="Hey :hugging:!!" />
    

    which will render

    <div class="message">
      <div class="bubble">
        Hey <img class="emojione" alt="🤗" title=":hugging:" src="...">!!
      </div>
    </div>
    

    Now, to create a <message-box /> component that will display an emoji picker to assist in autocomplete, do as follows

    Vue.component('message-box', {
      template: `<div class="message-box"><textarea></textarea></div>`,
      mounted(){
        // find the input
        $(this.$el).find('textarea').emojioneArea()
      }
    })
    

    And that's it! Although it may seem like a lot, the crux of the solution is quiet simple! Just use emojione.toImage(str) to get a DOM string and apply it to the Vue component (you can also use v-html to do this but IMO render() is a bit more sleek!). And for the displaying the picker, you just call $(...).emojioneArea() on the <textarea /> once the component is mounted.

    Make sure to checkout full code example at https://jsfiddle.net/riyaz_ali/5Lhex13n