Last active
January 10, 2017 06:08
-
-
Save shar0/7c29947f9c03a3201997389eb7a3222c to your computer and use it in GitHub Desktop.
Chat Room : Firebase + VueJS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<title>Firebase + VueJS</title> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> | |
<script src="//www.gstatic.cn/firebasejs/3.6.4/firebase.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.js"></script> | |
<script src="//unpkg.com/[email protected]"></script> | |
<style> | |
* { | |
padding: 0; | |
margin: 0; | |
} | |
body { | |
font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif; | |
font-size: 15px; | |
-webkit-font-smoothing: antialiased; | |
-moz-osx-font-smoothing: grayscale; | |
background-color: #fff; | |
color: #0D2C54; | |
} | |
ul, li { | |
list-style: none; | |
} | |
label { | |
color: #7FB800; | |
} | |
input[type="text"], | |
textarea { | |
width: 250px; | |
border: none; | |
background: #ededed; | |
border-radius: 4px; | |
color: #666; | |
padding: 5px; | |
font-size: 1em; | |
resize: none; | |
outline: none; | |
} | |
textarea { | |
height: 90px; | |
} | |
input[type="text"]:focus, | |
textarea:focus { | |
border-color: #00A6ED; | |
} | |
input[type=submit] { | |
border-radius: 4px; | |
border: 0; | |
width: 80px; | |
height: 25px; | |
background: #00A6ED; | |
color: white; | |
} | |
.form-row { | |
margin-top: 10px; | |
} | |
.room-selector { | |
position: fixed; | |
left: 0; | |
right: 0; | |
color: white; | |
padding: 10px 20px; | |
background-color: #7FB800; | |
} | |
.room-selector label { | |
color: white; | |
} | |
.room-selector label + label { | |
margin-left: 10px; | |
} | |
.message-list { | |
padding: 10px 20px; | |
} | |
.message-list li { | |
font-size: 1.2em; | |
} | |
.message-list li + li { | |
margin-top: 10px; | |
} | |
.message-list .status { | |
color: #999; | |
font-size: .8em; | |
} | |
.chat-form { | |
padding: 80px 20px 10px; | |
} | |
footer { | |
padding: 10px 20px; | |
background: #FFB400; | |
color: white; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="app"> | |
<div is="room-selector" @selected="changeRoom"></div> | |
<div is="chat-form" :room-id="currentRoomId"></div> | |
<div is="message-list" :room-id="currentRoomId"></div> | |
</div> | |
<footer>基于 Firebase & VueJS</footer> | |
<script type="text/x-template" id="room-selector-template"> | |
<div class="room-selector"> | |
<h2> | |
<strong>聊天室</strong> | |
</h2> | |
<label v-for="item, key in roomNames"> | |
<input type="radio" v-model="currentRoomId" :value="item['.key']"> | |
<span>{{item[".value"]}}</span> | |
</label> | |
</div> | |
</script> | |
<script type="text/x-template" id="message-list-template"> | |
<div class="message-list"> | |
<ul> | |
<li class="item" v-for="item in sortedList"> | |
<div class="message"> | |
<span>{{item["message"]}}</span> | |
</div> | |
<div class="status"><b>{{item["name"]}}</b> {{item["timestamp"] | date}}</div> | |
</li> | |
</ul> | |
</div> | |
</script> | |
<script type="text/x-template" id="chat-form-template"> | |
<div class="chat-form"> | |
<div class="form-row"> | |
<input id="name" type="text" v-model="name" placeholder="昵称"/> | |
</div> | |
<div class="form-row"> | |
<textarea v-model="message" cols="30" rows="10" placeholder="信息"></textarea> | |
</div> | |
<div class="form-row"> | |
<input type="submit" @click="newMessage" value="发送"> | |
</div> | |
</div> | |
</script> | |
<script> | |
// Setup Firebase | |
var config = { | |
apiKey: "AIzaSyDdVuy8ffXw0ql3crasRcczy82YeVtC7fU", | |
authDomain: "frontend-chatroom.firebaseapp.com", | |
databaseURL: "https://frontend-chatroom.firebaseio.com" | |
}; | |
var fb = firebase.initializeApp(config); | |
var roomNamesRef = firebase.database().ref('room_names'); | |
var messagesRef = firebase.database().ref('messages'); | |
Vue.component('room-selector', { | |
template: '#room-selector-template', | |
data: function () { | |
return { | |
currentRoomId: null | |
} | |
}, | |
watch: { | |
roomNames: function (val, oldVal) { | |
// Pick up first chat room | |
if (typeof val !== "undefined" && val.length > 0) { | |
this.currentRoomId = val[0]['.key']; | |
} | |
}, | |
currentRoomId: function (val, oldVal) { | |
this.$emit("selected", val); | |
} | |
}, | |
firebase: { | |
roomNames: roomNamesRef | |
} | |
}); | |
Vue.component('message-list', { | |
template: '#message-list-template', | |
props: ["roomId"], | |
firebase: { | |
list: messagesRef.child(0) | |
}, | |
filters: { | |
date: function (time) { | |
var theDate = new Date(time); | |
return theDate.toGMTString(); | |
} | |
}, | |
computed: { | |
sortedList: function () { | |
return this.list.reverse() | |
} | |
}, | |
watch: { | |
roomId: function () { | |
this.$bindAsArray('list', messagesRef.child(this.roomId).orderByChild("timestamp").limitToLast(25)); | |
} | |
} | |
}); | |
Vue.component('chat-form', { | |
template: '#chat-form-template', | |
props: ["roomId"], | |
data: function () { | |
return { | |
"message": null, | |
"name": null | |
} | |
}, | |
methods: { | |
newMessage: function () { | |
messagesRef.child(this.roomId).push({ | |
message: this.message, | |
name: this.name, | |
timestamp: firebase.database.ServerValue.TIMESTAMP | |
}); | |
this.message = null; | |
} | |
} | |
}); | |
var App = new Vue({ | |
el: '#app', | |
data: function () { | |
return { | |
currentRoomId: null | |
} | |
}, | |
methods: { | |
changeRoom: function (roomId) { | |
this.currentRoomId = roomId; | |
} | |
} | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment