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">
  <message-wrapper :messages="messages"></message-wrapper>
</div>


<template id="message-wrapper">
  <div id="message-wrapper">
    <message-item v-for="message in messages" :message="message"></message-item>
  </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;
}

JavaScript

var SCROLL_STATE = {
	BOTTOM: 'BOTTOM',
  MIDDLE: 'MIDDLE',
  TOP: 'TOP'
};

Vue.component('message-wrapper', {
  template: '#message-wrapper',
  props: ['messages'],
  data: function() {
    return {
    	scrollState: '',
      offset: 50,
    }
  },
  mounted: function() {
    console.log('[#message-wrapper] - mounted');
    this.$el.addEventListener('scroll', this.updateScrollState)
    this.scrollToBottom();
  },
  updated: function() {
  	this.updateScrollState();
  },
  watch: {
    scrollState: function (newState, oldState) {
    	console.log(newState);
    }
	},
  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');
      this.$el.scrollTop = this.$el.scrollHeight;
    }
  }
});

Vue.component('message-item', {
  template: '#message-item',
  props: ['message'],
  mounted: function() {
    console.log('[#message-item] - mounted');
  }
});

var dummyMessages = [];
for (var i = 0; i < 100; i++) {
  dummyMessages.push('hello')
}


var vm = new Vue({
  el: '#app',
  data: function() {
    return {
      messages: dummyMessages
    }
  }
})

/*
setInterval(function () {
	vm.$data.messages.push('new Hello :) ');
}, 1000);
*/