JSFiddle - React, Tailwind, and code Playground
by ChangJoo Park
HTML
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://unpkg.com/axios-mock-adapter/dist/axios-mock-adapter.js"></script>
<div id="app">
<div>
<message-wrapper :messages="messages" v-on:load-more="loadMore"></message-wrapper>
<button @click="startPolling">Start</button>
<button @click="stopPolling">Stop</button>
</div>
</div>
<template id="message-wrapper">
<div id="message-wrapper">
<message-item v-for="message in messages" :message="message"></message-item>
<div class="messageNotifier" :class="{active: hasNewMessage}">New Message</div>
</div>
</template>
<template id="message-item">
<div class="message">
{{message}}
</div>
</template>
CSS
#message-wrapper {
width: 400px;
height: 400px;
background-color: tomato;
overflow-y: auto;
overflow-x: hidden;
position: relative;
}
.messageNotifier {
position: relative;
width: 400px;
height: 20px;
background-color: white;
z-index: 100;
}
JavaScript
var polling;
var mockAxios = new AxiosMockAdapter(axios);
var mock = [];
for (var i = 0; i < 10; i++) {
mock.push('NEW TOP HELLO')
}
mockAxios.onGet('/api/msg').reply(200, mock)
var SCROLL_STATE = {
BOTTOM: 'BOTTOM',
MIDDLE: 'MIDDLE',
TOP: 'TOP'
};
Vue.component('message-wrapper', {
template: '#message-wrapper',
props: ['messages'],
data: function() {
return {
scrollState: '',
offset: 50,
hasNewMessage: false
}
},
mounted: function() {
console.log('[#message-wrapper] - mounted');
this.$el.addEventListener('scroll', this.updateScrollState)
this.scrollToBottom();
},
beforeUpdate: function() {
console.log('#beforeUpdate', this.scrollState);
this.updateScrollState();
},
updated: function () {
console.log('#update', this.scrollState, this.scrollState === SCROLL_STATE.BOTTOM);
if(this.scrollState === SCROLL_STATE.BOTTOM) {
this.scrollToBottom();
}
if(this.scrollState === SCROLL_STATE.MIDDLE) {
this.hasNewMessage = true;
}
},
watch: {
scrollState: function (newState, oldState) {
console.log(newState);
if(newState === SCROLL_STATE.TOP) {
axios.get('/api/msg').then(function (response) {
this.$emit('load-more', response.data);
}.bind(this));
}
}
},
methods: {
updateScrollState: function () {
var scrollHeight = this.$el.scrollHeight;
var boxHeight = this.$el.clientHeight;
var currentTop = this.$el.scrollTop;
var isInTop = currentTop < this.offset;
var isInBottom = currentTop + boxHeight >= scrollHeight - this.offset;
if (isInTop) {
this.scrollState = SCROLL_STATE.TOP;
} else if (isInBottom) {
this.scrollState = SCROLL_STATE.BOTTOM;
} else {
this.scrollState = SCROLL_STATE.MIDDLE;
}
console.log('#updateScrollState : ', this.scrollState)
},
scrollToBottom: function() {
console.log('[#message-wrapper] - scroll to bottom');
...