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...