├── README.md
├── package.json
└── stickyScroll.js
/README.md:
--------------------------------------------------------------------------------
1 | # vue-sticky-scroll
2 | #### update: this directive is for vue 1.x. a vue 2.0 compatible version is available by theomessin [here](https://github.com/theomessin/vue-chat-scroll).
3 | ## a vue.js directive that keeps an element scrolled to the bottom
4 |
5 |
6 | vue-sticky-scroll keeps an eye on your element and whenever content is added inside of it, it scrolls down so that the viewer can remain focused on the newest content!
7 |
8 |
9 | ### install
10 |
11 | NPM:
12 | note: vue-sticky-scroll requires vue 1.x; check your version by running `npm list vue`; a 2.0 compatible version is available [here](https://github.com/theomessin/vue-chat-scroll)
13 | ```bash
14 | npm i --save vue-sticky-scroll
15 | ```
16 | Require it in your vue.js component file:
17 |
18 | ```javascript
19 | // ES5
20 | var stickyScroll = require('vue-sticky-scroll');
21 | // ES6
22 | import 'vue-sticky-scroll';
23 | ```
24 |
25 | ### usage instructions
26 |
27 | Add `v-sticky-scroll` as an attribute on the element you wish to always scroll to the bottom of:
28 |
29 | ```html
30 |
31 | ```
32 |
33 | ### options: animate
34 |
35 | the scrolling will jump to the bottom by default.
36 | if you prefer a smooth scroll, add:
37 | - argument 'animate'
38 | - optional: expression (default is 300)
39 |
40 | ```html
41 |
42 |
43 |
44 | ```
45 |
46 |
47 | ### how it works
48 |
49 | vue-sticky-scroll uses a wonderful, highly underrated browser feature: [mutation observers](https://developer.mozilla.org/en/docs/Web/API/MutationObserver). By creating a `new MutationObserver` and telling it which events to `.observe()`, you can do wonderful things!
50 | This method is much simpler than some implementations of sticky scrolling that use requestAnimationFrame.
51 |
52 | ### license
53 |
54 | WTFPL
55 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-sticky-scroll",
3 | "version": "0.1.0",
4 | "description": "a vue.js directive that keeps an element scrolled to the bottom as new content is added",
5 | "main": "stickyScroll.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/heatherbooker/vue-sticky-scroll.git"
12 | },
13 | "keywords": [
14 | "vue",
15 | "vue-directive",
16 | "scroll",
17 | "autoscroll"
18 | ],
19 | "author": "Heather Booker",
20 | "license": "WTFPL",
21 | "bugs": {
22 | "url": "https://github.com/heatherbooker/vue-sticky-scroll/issues"
23 | },
24 | "homepage": "https://github.com/heatherbooker/vue-sticky-scroll#readme"
25 | }
26 |
--------------------------------------------------------------------------------
/stickyScroll.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | // if we are in node.js enviro, require vue
4 | try {
5 | var Vue = require('vue');
6 | } catch (e) {
7 | // no worries, in browser enviro Vue should already be global
8 | }
9 |
10 | var vueStickyScroll = Vue.directive('sticky-scroll', {
11 | bind: function() {
12 |
13 | //use browser MutationObserver object
14 | var observer = new MutationObserver(scrollToBottom);
15 | //looking for new children that will change the height
16 | var config = { childList: true };
17 | observer.observe(this.el, config);
18 |
19 | //need reference to this, otherwise 'this'=MutationObserver
20 | var me = this;
21 |
22 | function animateScroll(duration) {
23 |
24 | var start = me.el.scrollTop;
25 | var end = me.el.scrollHeight;
26 | var change = end - start;
27 | var increment = 20;
28 |
29 | function easeInOut(currentTime, start, change, duration) {
30 | //by Robert Penner
31 | currentTime /= duration / 2;
32 | if (currentTime < 1) {
33 | return change / 2 * currentTime * currentTime + start;
34 | }
35 | currentTime -= 1;
36 | return -change / 2 * (currentTime * (currentTime - 2) - 1) + start;
37 | }
38 |
39 | function animate(elapsedTime) {
40 |
41 | elapsedTime += increment;
42 | var position = easeInOut(elapsedTime, start, change, duration);
43 | me.el.scrollTop = position;
44 |
45 | if (elapsedTime < duration) {
46 | setTimeout(function() {
47 | animate(elapsedTime);
48 | }, increment)
49 | }
50 | }
51 | animate(0);
52 | }
53 |
54 | function scrollToBottom() {
55 | if (me.arg === 'animate') {
56 | //default is 300
57 | var duration = Number(me.expression) || 300;
58 | animateScroll(duration);
59 | } else {
60 | //default is jump to bottom
61 | me.el.scrollTop = me.el.scrollHeight;
62 | }
63 | }
64 | }
65 | });
66 |
67 | // check whether we are in node.js enviro
68 | try {
69 | module.exports = vueStickyScroll;
70 | } catch (e) {
71 | // no worries, our directive will just be registered in browser
72 | }
73 |
74 | })();
75 |
--------------------------------------------------------------------------------