F7-V5 + Vue + V-chat-scroll

by Maiki Nahara

HTML

<link rel="stylesheet" href="https://unpkg.com/framework7/css/framework7.bundle.min.css">
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://unpkg.com/framework7/js/framework7.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/framework7-vue.bundle.min.js"></script>
<div id="app">
  <f7-app :params="f7params">
    <f7-statusbar></f7-statusbar>

    <!-- Main View -->
    <f7-view id="main-view" main class="safe-areas">
    
    <div class="page">
  <div class="navbar">
    <div class="navbar-bg"></div>
    <div class="navbar-inner">
      <div class="title">Messages</div>
    </div>
  </div>
  <div class="toolbar messagebar">
    <div class="toolbar-inner">
      <div class="messagebar-area">
        <textarea class="resizable" placeholder="Message"></textarea>
      </div><a class="link send-link" href="#">Send</a>
    </div>
  </div>
  <div class="page-content messages-content">
    <ul class="messages" v-chat-scroll="{always: true, smooth: true}">
      <!-- Messages title -->
      <div class="messages-title"><b>Sunday, Feb 9,</b> 12:58</div>
      <!-- Full layout sent message -->
      <div class="message message-sent">
        <div class="message-avatar" style="background-image:url(https://cdn.framework7.io/placeholder/people-100x100-7.jpg);"></div>
        <div class="message-content">
          <div class="message-name">John Doe</div>
          <div class="message-header">Message header</div>
          <div class="message-bubble">
            <div class="message-text-header">Text header</div>
            <div class="message-text">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</div>
            <div class="message-text-footer">Text footer</div>
          </div>
          <div class="message-footer">Message footer</div>
        </div>
      </div>
      <!-- Full layout received message -->
      <div class="message message-received">
        <div class="message-avatar"...

CSS

.messages {
  height: calc(100vh - (var(--f7-navbar-height) + var(--f7-safe-area-top) + var(--f7-messagebar-height)));
  overflow-y: scroll;
}

JavaScript

(function (global, factory) {
	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
	typeof define === 'function' && define.amd ? define(factory) :
	(global['vue-chat-scroll'] = factory());
}(this, (function () { 'use strict';

/**
* @name VueJS vChatScroll (vue-chat-scroll)
* @description Monitors an element and scrolls to the bottom if a new child is added
* @author Theodore Messinezis <[email protected]>
* @file v-chat-scroll  directive definition
*/
var scrollToBottom = function scrollToBottom(el, smooth) {
  if (typeof el.scroll === "function") {
    el.scroll({
      top: el.scrollHeight,
      behavior: smooth ? 'smooth' : 'instant'
    });
  } else {
    el.scrollTop = el.scrollHeight;
  }
};

var vChatScroll = {
  bind: function bind(el, binding) {
    var scrolled = false;

    el.addEventListener('scroll', function (e) {
      scrolled = el.scrollTop + el.clientHeight + 1 < el.scrollHeight;
    });
    new MutationObserver(function (e) {
      var config = binding.value || {};
      var pause = config.always === false && scrolled;
      var addedNodes = e[e.length - 1].addedNodes.length;
      var removedNodes = e[e.length - 1].removedNodes.length;

      if (config.scrollonremoved) {
        if (pause || addedNodes != 1 && removedNodes != 1) return;
      } else {
        if (pause || addedNodes != 1) return;
      }

      var smooth = config.smooth;
      var loadingRemoved = !addedNodes && removedNodes === 1;
      if (loadingRemoved && config.scrollonremoved && 'smoothonremoved' in config) {
        smooth = config.smoothonremoved;
      }
      scrollToBottom(el, smooth);
    }).observe(el, { childList: true, subtree: true });
  },
  inserted: function inserted(el, binding) {
    var config = binding.value || {};
    scrollToBottom(el, config.smooth);
  }
};

/**
* @name VueJS vChatScroll (vue-chat-scroll)
* @description Monitors an element and scrolls to the bottom if a new child is added
* @author...