Prologue
Slack のようなリアクション機能をNuxt.js(Vue.js) を使って実装してみました。
CSSの実装やカウント、リアクションをつけたユーザーの表示等に関しては割愛して、今回は Picker と絵文字の表示部分についてのみ説明します。
公式のドキュメントがかなりしっかり作られているので、そちらも確認してみてください。
参考:
- Emoji Mart: https://github.com/missive/emoji-mart
- Emoji Mart Vue: https://github.com/jm-david/emoji-mart-vue
環境
-
macOS: 10.15.4
-
terminal: iTerm
-
node.js: 10.16.0
-
エディタ: VS Code
-
使用言語: TypeScript, Nuxt.js, CompositionAPI(v0.5.0)
-
Project概要
- パッケージマネージャ:
yarn
- パッケージマネージャ:
インストール
emoji-mart-vue
をインストールします。
yarn add emoji-mart-vue
セットアップ
挙動を見たかった為、 Nuxt のプロジェクトを新しく作成し、必要最低限の code を書いていきます。
<template>
<div class="section">
<div>
<Picker />
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, reactive } from '@vue/composition-api'
// @ts-ignore
import { Picker } from 'emoji-mart-vue'
export default defineComponent({
name: 'EmojiPicker',
components: {
Picker,
},
})
</script>
最低限これだけでも emoji-picker は表示されました。
プロパティをセット
emoji-mart-vue
は様々なプロパティを用意してくれているので、必要なものを確認していきます。
<Picker />
component にプロパティを渡していきます。
参考: https://github.com/jm-david/emoji-mart-vue
<template>
<div class="section">
<div>
<Picker
title="pick emoji"
emoji="grinning"
set="twitter"
color="pink"
/>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, reactive } from '@vue/composition-api'
// @ts-ignore
import { Emoji, Picker } from 'emoji-mart-vue'
export default defineComponent({
name: 'EmojiPicker',
components: {
Picker
},
})
</script>
内容:
- title: フッターに表示されるテキスト
- emoji: フッターに表示される初期値の絵文字
- set: pickerに使われる絵文字のデザイン
- color: ヘッダーに使われるカテゴリ hover 時のカラー
個人的には Color を標準で簡単に切り替えられるのはすごい助かりました。CSSをいじればいいだけですが、バージョンアップ等を考えるといじらないに越したことはないので...
表示する内容(カテゴリ)を限定する
emoji-mart-vue
はデフォルトでたくさんの絵文字を提供してくれています。
ただ、プロジェクトによっては不要だったり制限したりする可能性もあるので、カテゴリの制限の仕方を確認しました。
余談ですが、実はここがなかなかうまくいかず、一番てこずりました。ドキュメントをよく読まなかったのが敗因です。
include
というプロパティが用意されています。
そこに l18n
と同じキーをセットします。複数使用する場合には配列で書くだけです。
<template>
<div class="section">
<div>
<Picker
title="pick emoji"
emoji="grinning"
set="twitter"
color="pink"
:include="cat"
/>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, reactive } from '@vue/composition-api'
// @ts-ignore
import { Emoji, Picker } from 'emoji-mart-vue'
export default defineComponent({
name: 'EmojiPicker',
components: {
Picker
},
setup(){
const cat = ['search', 'recent', 'people', 'objects']
return { cat }
}
})
</script>
選択した絵文字を任意の場所に表示する
-
Emoji
という component が用意されているので import します。 -
Picker
にselect
という event が用意されているため、そこから emoji object を取得します。 - Emoji component の
emoji
プロパティ に bind します。
<template>
<div class="section">
<div v-for="(item, index) in state.selectedItem" :key="index" class="emoji-wrapper">
<div>
<Emoji :emoji="item" :size="20" class="emoji-image" />
</div>
</div>
<div>
<Picker
title="pick emoji"
emoji="grinning"
set="twitter"
color="pink"
:include="cat"
@select="selectEmoji"
/>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, reactive } from '@vue/composition-api'
// @ts-ignore
import { Emoji, Picker } from 'emoji-mart-vue'
export default defineComponent({
name: 'EmojiPicker',
components: {
Picker,
Emoji
},
setup(props, context) {
const state = reactive({
selectedItem: ['grinning'],
})
const cat = ['search', 'recent', 'people', 'objects']
function selectEmoji(item: any) {
if (!state.selectedItem) {
state.selectedItem = item.unified
}
state.selectedItem.push(item)
}
return {
selectEmoji,
state,
cat,
}
}
})
</script>
これで表示されるはずです。
Emoji component を使わないパターンを検討する
ここまでで特に問題なく実装ができました。ただ今回はこの内容をデータとして、なるべくシンプルな形で保存しておく必要がありました。
Emoji Component を使わず、 string だけでやりとりができないものかと方法を探していたら、以下の記事を見つけました。
参考: https://medium.com/@allegra9/add-emoji-picker-to-your-react-chat-app-30d8cbe8d9a6
select
event で取得できる object の中にある unified
に接頭辞 0x
をつけて Unicode とし、それを String.fromCodePoint
で絵文字として表示します。
- String.fromCodePoint
参考: https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint
以下の code は 抜粋になります。
state.emoji
を template に置くと表示されます。
function selectEmoji(item: any) {
let splitCode = item.unified.split('-');
let codeArr = new Array()
splitCode.forEach((c, index) => {
splitCode[index] = `0x${c}`
})
state.emoji = String.fromCodePoint(...splitCode)
}
注意したいのは、 emoji-mart-vue
は肌の色なども変えることができるため、取得した unified
の中身は -
区切りの string になる場合があります。
その string 一つ一つの頭に 0x
をつけないと、望む形の絵文字は表示されません。
最終的にはこの形で渡せればOKです。
String.fromCodePoint('0x1f44d', '0x1f3fd')
unified
の中に -
がいくつ存在しうるのか、肌の色以外にもどのパターンでそうなるのか、は一つ一つ検証していないのですが、この形で大丈夫だと思います。
何かあればフィードバックして頂けると助かります。^^
Epilogue
絵文字を表示する、という一見するとたくさんやることがありそうな内容ですが、今回見つけた emoji-mart
は Vue.js
用に作られたもの(emoji-mart-vue
) があり、助かりました。
ドキュメントもわかりやすく、進めるのが楽しかったです。
最後の unified
の部分だけ、実装段階まで知らず、気付かずで焦りましたが... JSが素敵な関数用意してくれていてよかった^^ というJSの勉強にもなりました。
今回言及していませんが、この他にもSlack風にするためにカウントを増やしたり tooltip を実装したりしています。また、絵文字のサイズも任意で変えられたりするので、ぜひ実装する際には公式ドキュメントを見ながら進めてみてください。
何かおかしなところや、こういう方法もある、というものがありましたらお気軽にメンションしてください。