Skip to content

Commit

Permalink
feat(carousel): replace dirty check with mutation observer (SSENSE#16)
Browse files Browse the repository at this point in the history
* feat(carousel): replace dirty check with mutation observer

* feat(carousel): rebuild with mutation observer
  • Loading branch information
toddlawton authored Jan 31, 2017
1 parent 33304ec commit 9c327c5
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 50 deletions.
4 changes: 2 additions & 2 deletions dist/vue-carousel.min.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/themes/vue/source/js/vue-carousel.min.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vue-carousel",
"version": "0.5.1",
"version": "0.5.2",
"description": "A flexible, responsive, touch-friendly carousel for Vue.js",
"main": "dist/vue-carousel.min.js",
"scripts": {
Expand Down Expand Up @@ -40,6 +40,7 @@
"babel-plugin-transform-runtime": "^6.15.0",
"babel-plugin-webpack-alias": "^2.1.2",
"babel-preset-es2015": "^6.18.0",
"babel-preset-stage-1": "^6.22.0",
"babel-preset-stage-2": "^6.18.0",
"babel-register": "^6.18.0",
"chai": "^3.5.0",
Expand Down
62 changes: 36 additions & 26 deletions src/Carousel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,27 @@
this.goToPage(this.currentPage + 1)
}
},
/**
* A mutation observer is used to detect changes to the containing node
* in order to keep the magnet container in sync with the height its reference node.
*/
attachMutationObserver() {
const MutationObserver = window.MutationObserver
|| window.WebKitMutationObserver
|| window.MozMutationObserver
if (MutationObserver) {
const config = { attributes: true, data: true }
this.mutationObserver = new MutationObserver(() => {
this.$nextTick(() => {
this.computeCarouselWidth()
})
})
if (this.$parent.$el) {
this.mutationObserver.observe(this.$parent.$el, config)
}
}
},
/**
* Calculate the width of each slide
* @return {Number} Slide width
Expand All @@ -241,6 +262,14 @@
return this.slideWidth
},
/**
* Stop listening to mutation changes
*/
detachMutationObserver() {
if (this.mutationObserver) {
this.mutationObserver.disconnect()
}
},
/**
* Given a viewport width, find the number of slides to display
* @param {Number} width Current viewport width in pixels
Expand Down Expand Up @@ -343,28 +372,14 @@
* Trigger actions caused by window resizing
*/
handleResize() {
this.getBrowserWidth()
this.recomputeCarouselWidth()
},
/**
* If the carousel is hidden on init, slide widths cannot be calculated.
* Dirty checking is applied in this case.
* Once a width is found, the polling is stopped and the carousel is recalculated.
*/
pollForWidth() {
if (!this.pollInterval) {
this.pollInterval = setInterval(() => {
if (this.getCarouselWidth() > 0) {
this.recomputeCarouselWidth()
clearInterval(this.pollInterval)
}
}, 50)
}
this.computeCarouselWidth()
},
/**
* Re-compute the width of the carousel and its slides
*/
recomputeCarouselWidth() {
computeCarouselWidth() {
this.slideCount = this.getSlideCount()
this.getBrowserWidth()
this.getCarouselWidth()
this.calculateSlideWidth()
this.setCurrentPageInBounds()
Expand Down Expand Up @@ -395,8 +410,6 @@
},
mounted() {
if (!this.$isServer) {
this.getBrowserWidth()
window.addEventListener("resize", debounce(this.handleResize, 16))
if ("ontouchstart" in window) {
Expand All @@ -410,15 +423,12 @@
}
}
this.slideCount = this.getSlideCount()
this.recomputeCarouselWidth()
if (this.isHidden) {
this.pollForWidth()
}
this.attachMutationObserver()
this.computeCarouselWidth()
},
destroyed() {
if (!this.$isServer) {
this.detachMutationObserver()
window.removeEventListener("resize", this.getBrowserWidth)
if ("ontouchstart" in window) {
this.$el.removeEventListener("touchmove", this.handleMousemove)
Expand Down
2 changes: 1 addition & 1 deletion src/Pagination.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div class="pagination">
<div v-show="parentContainer.pageCount > 1" class="pagination">
<div class="dot-container">
<div
class="dot"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ exports[`Carousel should fall back to default slides per page when no responsive
.slide(style=\'width: 0px;\')
.slide(style=\'width: 0px;\')
//
.pagination
.pagination(style=\'\')
.dot-container
.dot(style=\'margin-top: 20px; padding: 10px;\')
.dot-inner(style=\'width: 10px; height: 10px; background: rgb(0, 0, 0);\')
Expand Down
17 changes: 0 additions & 17 deletions tests/client/components/carousel.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,21 +198,4 @@ describe('Carousel', () => {
expect(carouselInstance.autoplayInterval).toBe(undefined);
return utils.expectToMatchSnapshot(vm);
});

// it('should apply dirty checking when carousel is initialized in a hidden state', () => {
// const vm = new Vue({
// el: document.createElement('div'),
// render: (h) => h(Carousel, {}, [h(Slide), h(Slide)]),
// });

// const carouselInstance = vm.$children[0];

// expect(carouselInstance.pollInterval).toBeDefined();

// return carouselInstance.$nextTick().then(() => {
// expect(carouselInstance.getCarouselWidth()).toBe(200);

// return utils.expectToMatchSnapshot(vm);
// });
// });
});

0 comments on commit 9c327c5

Please sign in to comment.