diff options
| author | Kana <[email protected]> | 2020-12-24 21:41:24 +0900 |
|---|---|---|
| committer | GitHub <[email protected]> | 2020-12-24 21:41:24 +0900 |
| commit | 2412a60bd4cb2364a477a3af79a8c6dcb6b0ddab (patch) | |
| tree | dbf2b2cad342f31849a62089dedd40165758af86 /src/site/components/grid/waterfall/Waterfall.vue | |
| parent | Enable deleting files with the API key (diff) | |
| parent | bug: fix showlist resetting itself every time the page is changed (diff) | |
| download | host.fuwn.me-2412a60bd4cb2364a477a3af79a8c6dcb6b0ddab.tar.xz host.fuwn.me-2412a60bd4cb2364a477a3af79a8c6dcb6b0ddab.zip | |
Merge pull request #228 from Zephyrrus/begone_trailing_commas
Merge own dev branch into main dev branch
Diffstat (limited to 'src/site/components/grid/waterfall/Waterfall.vue')
| -rw-r--r-- | src/site/components/grid/waterfall/Waterfall.vue | 254 |
1 files changed, 104 insertions, 150 deletions
diff --git a/src/site/components/grid/waterfall/Waterfall.vue b/src/site/components/grid/waterfall/Waterfall.vue index 8631ea5..af2af3f 100644 --- a/src/site/components/grid/waterfall/Waterfall.vue +++ b/src/site/components/grid/waterfall/Waterfall.vue @@ -1,180 +1,134 @@ -<style> - .waterfall { - position: relative; - } -</style> <template> - <div class="waterfall"> - <slot /> + <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 {quickSort, getMinIndex, _, sum} from './util' +import WaterfallItem from './WaterfallItem.vue'; -const quickSort = (arr, type) => { - const left = []; - const right = []; - if (arr.length <= 1) { - return arr; - } - const povis = arr[0]; - for (let i = 1; i < arr.length; i++) { - if (arr[i][type] < povis[type]) { - left.push(arr[i]); - } else { - right.push(arr[i]); - } - } - return quickSort(left, type).concat(povis, quickSort(right, type)) -}; +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; -const getMinIndex = arr => { - let pos = 0; - for (let i = 0; i < arr.length; i++) { - if (arr[pos] > arr[i]) { - pos = i; - } - } - return pos; -}; - -const _ = { - on(el, type, func, capture = false) { - el.addEventListener(type, func, capture); - }, - off(el, type, func, capture = false) { - el.removeEventListener(type, func, capture); - } -}; - -const sum = arr => arr.reduce((sum, val) => sum + val); export default { name: 'Waterfall', + components: { + WaterfallItem + }, props: { - gutterWidth: { - type: Number, - default: 0 - }, - gutterHeight: { - type: Number, - default: 0 - }, - resizable: { - type: Boolean, - default: true + options: { + type: Object, + default: () => {} }, - align: { - type: String, - default: 'center' + items: { + type: Array, + default: () => [] }, - fixWidth: { - type: Number - }, - minCol: { + itemWidth: { type: Number, - default: 1 + default: 150 }, - maxCol: { - type: Number + gutterWidth: { + type: Number, + default: 10 }, - percent: { - type: Array + gutterHeight: { + type: Number, + default: 4 } }, - data() { - return { - timer: null, - colNum: 0, - lastWidth: 0, - percentWidthArr: [] - }; + mounted() { + this.initializeMasonry(); + this.imagesLoaded(); }, - created() { - this.$on('itemRender', () => { - if (this.timer) { - clearTimeout(this.timer); - } - this.timer = setTimeout(() => { - this.render(); - }, 0); - }); + updated() { + this.performLayout(); + this.imagesLoaded(); }, - mounted() { - this.resizeHandle(); - this.$watch('resizable', this.resizeHandle); + unmounted() { + this.masonry.destroy(); }, methods: { - calulate(arr) { - let pageWidth = this.fixWidth ? this.fixWidth : this.$el.offsetWidth; - // 百分比布局计算 - if (this.percent) { - this.colNum = this.percent.length; - const total = sum(this.percent); - this.percentWidthArr = this.percent.map(value => (value / total) * pageWidth); - this.lastWidth = 0; - // 正常布局计算 - } else { - this.colNum = parseInt(pageWidth / (arr.width + this.gutterWidth)); - if (this.minCol && this.colNum < this.minCol) { - this.colNum = this.minCol; - this.lastWidth = 0; - } else if (this.maxCol && this.colNum > this.maxCol) { - this.colNum = this.maxCol; - this.lastWidth = pageWidth - (arr.width + this.gutterWidth) * this.colNum + this.gutterWidth; - } else { - this.lastWidth = pageWidth - (arr.width + this.gutterWidth) * this.colNum + this.gutterWidth; + 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(); }, - resizeHandle() { - if (this.resizable) { - _.on(window, 'resize', this.render, false); - } else { - _.off(window, 'resize', this.render, false); + diffDomChildren() { + const oldChildren = this.domChildren.filter((element) => !!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 + }; }, - render() { - // 重新排序 - let childArr = []; - childArr = this.$children.map(child => child.getMeta()); - childArr = quickSort(childArr, 'order'); - // 计算列数 - this.calulate(childArr[0]) - let offsetArr = Array(this.colNum).fill(0); - // 渲染 - childArr.forEach(child => { - let position = getMinIndex(offsetArr); - // 百分比布局渲染 - if (this.percent) { - let left = 0; - child.el.style.width = `${this.percentWidthArr[position]}px`; - if (position === 0) { - left = 0; - } else { - for (let i = 0; i < position; i++) { - left += this.percentWidthArr[i]; - } - } - child.el.style.left = `${left}px`; - // 正常布局渲染 - } else { - if (this.align === 'left') { // eslint-disable-line no-lonely-if - child.el.style.left = `${position * (child.width + this.gutterWidth)}px`; - } else if (this.align === 'right') { - child.el.style.left = `${position * (child.width + this.gutterWidth) + this.lastWidth}px`; - } else { - child.el.style.left = `${position * (child.width + this.gutterWidth) + this.lastWidth / 2}px`; + initializeMasonry() { + if (!this.masonry) { + this.masonry = new Masonry( + this.$refs.waterfall, + { + columnWidth: this.itemWidth, + gutter: this.gutterWidth, + ...this.options } - } - if (child.height === 0) { - return; - } - child.el.style.top = `${offsetArr[position]}px`; - offsetArr[position] += (child.height + this.gutterHeight); - this.$el.style.height = `${Math.max.apply(Math, offsetArr)}px`; - }); - this.$emit('rendered', this); + ); + 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> + +<style lang="scss" scoped> +.wfi { + +} +</style> |