「facebookの通知エリアみたいなもの」と言われても漠然としていると思いますが表示でいうと次のようなものです。
文章で要件を書くと次の通りです。
- アイコンの右肩or左肩に未読件数のバッジが付いている
- アイコンにマウスオーバーで下にプルダウンで表示される
- メッセージ内容は動的に変更できる
- 一件一件選んで消せる
- 消したものは、既読フラグをつけて、もう未読エリアに表示しない
- 重要なメッセージは色を変更するなどでわかりやすくする
私の javascript に関する能力としては、Web関係の仕事を5.6年前までは結構一生懸命やっていたけれども、javascriptは結局必要に迫られたときにjQueryとか jQuery UIとかでなんとかしていて、そんなに深くはやっていない、という感じのスキルです。
今回は、ちょっと急ぎで上記のものを作らないといけなくって、
「はは!この秀吉が、一夜で城を建ててみまする!」
という感じで、サクッとやる感じでやりました。結局4日間ぐらいはかかりましたので、4日城ですね。
使っているのは
- Vue.js
- Vuetify.js(バッジのデザインをこれにしたかった)
- Semantic UI (メッセージのデザインをこれにしたかった)
- axios(閉じるボタンをクリックした時に何か実行するため)
びみょいところもありますが、載せちゃいます。
<!DOCTYPE html>
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.css"
rel="stylesheet">
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css">
</head>
<body>
<br>
<div id="app">
<div class="ui button"
style="background-color: #ffffff; margin-left: 100px;">
<!-- メールのアイコン -->
<v-app style="height:50px; background-color:#ffffff;">
<v-layout />
<a>
<v-badge color="red" left>
<template v-slot:badge>
<span v-if="messages > 0">{{ messages }}</span>
</template>
<bell v-on:showmenu="showMenuBelowBell()"
v-on:hidemenu="hideMenuBelowBell()">
</bell>
</v-badge>
</a>
</v-layout>
</v-app>
<!-- 通知 -->
<notification v-for="post in posts" v-bind:key="post.id"
v-bind:title="post.title" v-bind:content="post.content"
v-bind:type="post.type" v-if="show_messages"></notification>
</div>
</div>
<!-- 通知部分のテンプレート -->
<script type="text/x-template" id="notification-component">
<div class="ui message" :class="type" v-if="!hidden" style="width:300px; text-align:left">
<i class="close icon" @click="hide"></i>
<div class="header">{{ title }}</div>
<slot></slot>
<div v-html="content"></div>
</div>
</script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
Vue.component('bell', ({
template: '<span><i class="bell icon" v-on:mouseover="mouseover" ></i></span>',
methods: {
mouseover: function(){
console.log("マウスオーバーだよ");
this.$emit('showmenu')
},
mouseleave:function(){
console.log("マウスリーブだよ");
this.$emit('hidemenu')
},
}
}))
Vue.component('notification', {
props: {
title:{},
content:{},
type: {
type: String,
default: 'info'
},
header: {
}
},
data() {
return {
hidden: false,
}
},
methods: {
hide() {
this.hidden = true
axios.get(`https://api.github.com/users/AkikoGoto`)
.then(response => {
console.log(response.data)
})
},
},
template: '#notification-component'
})
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
// show: false,
posts: [
{ id: 1, title: 'せやかて' , content:'工藤', type:'info'},
{ id: 2, title: 'なんだと' , content:'服部!本当なのか?', type:'error'},
{ id: 3, title: 'お知らせ' , content:'ついに黒の組織のボスが判明'}
],
messages: 3,
show_messages:false,
}
},
methods: {
showMenuBelowBell: function () {
this.show_messages = true
},
hideMenuBelowBell: function () {
this.show_messages = false
}
}
})
</script>
</body>
</html>
一応、これを張り付けてhtmlファイルとしてブラウザで開けば、一番最初の画像のような挙動になるはずです。
注意点は次の通り。
- データはVueを生成しているところ(new Vueの箇所)のpostsというところに入っています。JSONだとかなんらかの形で、ここが動的に変わるようにしてください。
- バッジの件数は、その下のmessagesというオブジェクトになります。すみませんが、上記のpostsを自動的にカウントして入れるようになっていませんので、ここも別途やってくださいませ。
- 閉じる×ボタンをクリックした時の挙動は、私のGithubにつながって応答が返ってきてconsoleに出力されるようになってます…。もちろん、ここも皆様がカスタマイズされると思いますので、ただのサンプルです。
- プルダウンメニューが表示されるところはやってありますが、全体的に隠す処理はしていません。そちらもご自由に…。