aboutsummaryrefslogtreecommitdiff
path: root/src/site/components/grid/waterfall
diff options
context:
space:
mode:
authorPitu <[email protected]>2021-01-04 01:04:20 +0900
committerPitu <[email protected]>2021-01-04 01:04:20 +0900
commitfcd39dc550dec8dbcb8325e07e938c5024cbc33d (patch)
treef41acb4e0d5fd3c3b1236fe4324b3fef9ec6eafe /src/site/components/grid/waterfall
parentCreate FUNDING.yml (diff)
parentchore: update todo (diff)
downloadhost.fuwn.me-fcd39dc550dec8dbcb8325e07e938c5024cbc33d.tar.xz
host.fuwn.me-fcd39dc550dec8dbcb8325e07e938c5024cbc33d.zip
Merge branch 'dev'
Diffstat (limited to 'src/site/components/grid/waterfall')
-rw-r--r--src/site/components/grid/waterfall/Waterfall.vue129
-rw-r--r--src/site/components/grid/waterfall/WaterfallItem.vue10
2 files changed, 139 insertions, 0 deletions
diff --git a/src/site/components/grid/waterfall/Waterfall.vue b/src/site/components/grid/waterfall/Waterfall.vue
new file mode 100644
index 0000000..5a4c569
--- /dev/null
+++ b/src/site/components/grid/waterfall/Waterfall.vue
@@ -0,0 +1,129 @@
+<template>
+ <div ref="waterfall" class="waterfall">
+ <WaterfallItem
+ v-for="item in items"
+ :key="item.id"
+ :style="{ width: `${itemWidth}px`, marginBottom: `${gutterHeight}px` }"
+ :width="itemWidth">
+ <slot :item="item" />
+ </WaterfallItem>
+ </div>
+</template>
+<script>
+import WaterfallItem from './WaterfallItem.vue';
+
+const isBrowser = typeof window !== 'undefined';
+// eslint-disable-next-line global-require
+const Masonry = isBrowser ? window.Masonry || require('masonry-layout') : null;
+const imagesloaded = isBrowser ? require('imagesloaded') : null;
+
+export default {
+ name: 'Waterfall',
+ components: {
+ WaterfallItem
+ },
+ props: {
+ options: {
+ 'type': Object,
+ 'default': () => {}
+ },
+ items: {
+ 'type': Array,
+ 'default': () => []
+ },
+ itemWidth: {
+ 'type': Number,
+ 'default': 150
+ },
+ gutterWidth: {
+ 'type': Number,
+ 'default': 10
+ },
+ gutterHeight: {
+ 'type': Number,
+ 'default': 4
+ }
+ },
+ mounted() {
+ this.initializeMasonry();
+ this.imagesLoaded();
+ },
+ updated() {
+ this.performLayout();
+ this.imagesLoaded();
+ },
+ unmounted() {
+ this.masonry.destroy();
+ },
+ methods: {
+ imagesLoaded() {
+ const node = this.$refs.waterfall;
+ imagesloaded(
+ node,
+ () => {
+ this.masonry.layout();
+ }
+ );
+ },
+ performLayout() {
+ const diff = this.diffDomChildren();
+ if (diff.removed.length > 0) {
+ this.masonry.remove(diff.removed);
+ this.masonry.reloadItems();
+ }
+ if (diff.appended.length > 0) {
+ this.masonry.appended(diff.appended);
+ this.masonry.reloadItems();
+ }
+ if (diff.prepended.length > 0) {
+ this.masonry.prepended(diff.prepended);
+ }
+ if (diff.moved.length > 0) {
+ this.masonry.reloadItems();
+ }
+ this.masonry.layout();
+ },
+ diffDomChildren() {
+ const oldChildren = this.domChildren.filter(element => Boolean(element.parentNode));
+ const newChildren = this.getNewDomChildren();
+ const removed = oldChildren.filter(oldChild => !newChildren.includes(oldChild));
+ const domDiff = newChildren.filter(newChild => !oldChildren.includes(newChild));
+ const prepended = domDiff.filter((newChild, index) => newChildren[index] === newChild);
+ const appended = domDiff.filter(el => !prepended.includes(el));
+ let moved = [];
+ if (removed.length === 0) {
+ moved = oldChildren.filter((child, index) => index !== newChildren.indexOf(child));
+ }
+ this.domChildren = newChildren;
+ return {
+ 'old': oldChildren,
+ 'new': newChildren,
+ removed,
+ appended,
+ prepended,
+ moved
+ };
+ },
+ initializeMasonry() {
+ if (!this.masonry) {
+ this.masonry = new Masonry(
+ this.$refs.waterfall,
+ {
+ columnWidth: this.itemWidth,
+ gutter: this.gutterWidth,
+ ...this.options
+ }
+ );
+ this.domChildren = this.getNewDomChildren();
+ }
+ },
+ getNewDomChildren() {
+ const node = this.$refs.waterfall;
+ const children = this.options && this.options.itemSelector
+ ? node.querySelectorAll(this.options.itemSelector)
+ : node.children;
+ return Array.prototype.slice.call(children);
+ }
+ }
+};
+</script>
diff --git a/src/site/components/grid/waterfall/WaterfallItem.vue b/src/site/components/grid/waterfall/WaterfallItem.vue
new file mode 100644
index 0000000..2a18606
--- /dev/null
+++ b/src/site/components/grid/waterfall/WaterfallItem.vue
@@ -0,0 +1,10 @@
+<template>
+ <div class="waterfall-item">
+ <slot />
+ </div>
+</template>
+<script>
+export default {
+ name: 'WaterfallItem'
+};
+</script>