diff options
| author | Pitu <[email protected]> | 2018-09-16 01:09:02 -0300 |
|---|---|---|
| committer | Pitu <[email protected]> | 2018-09-16 01:09:02 -0300 |
| commit | fe10a00ba9a3c30d8718ca004ccd19518466f5bd (patch) | |
| tree | 369752f59a88dd03df1e9752be0ba166bf93c933 /src/site/components/grid/waterfall/Waterfall.vue | |
| parent | First version of start script (diff) | |
| download | host.fuwn.me-fe10a00ba9a3c30d8718ca004ccd19518466f5bd.tar.xz host.fuwn.me-fe10a00ba9a3c30d8718ca004ccd19518466f5bd.zip | |
Site
Diffstat (limited to 'src/site/components/grid/waterfall/Waterfall.vue')
| -rw-r--r-- | src/site/components/grid/waterfall/Waterfall.vue | 181 |
1 files changed, 181 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..9827075 --- /dev/null +++ b/src/site/components/grid/waterfall/Waterfall.vue @@ -0,0 +1,181 @@ +<style> + .waterfall { + position: relative; + } +</style> +<template> + <div class="waterfall"> + <slot/> + </div> +</template> +<script> +// import {quickSort, getMinIndex, _, sum} from './util' + +const quickSort = (arr, type) => { + let left = []; + let right = []; + let povis; + if (arr.length <= 1) { + return arr; + } + 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 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', + props: { + gutterWidth: { + type: Number, + default: 0 + }, + gutterHeight: { + type: Number, + default: 0 + }, + resizable: { + type: Boolean, + default: true + }, + align: { + type: String, + default: 'center' + }, + fixWidth: { + type: Number + }, + minCol: { + type: Number, + default: 1 + }, + maxCol: { + type: Number + }, + percent: { + type: Array + } + }, + data() { + return { + timer: null, + colNum: 0, + lastWidth: 0, + percentWidthArr: [] + }; + }, + created() { + this.$on('itemRender', () => { + if (this.timer) { + clearTimeout(this.timer); + } + this.timer = setTimeout(() => { + this.render(); + }, 0); + }); + }, + mounted() { + this.resizeHandle(); + this.$watch('resizable', this.resizeHandle); + }, + 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; + } + } + }, + resizeHandle() { + if (this.resizable) { + _.on(window, 'resize', this.render, false); + } else { + _.off(window, 'resize', this.render, false); + } + }, + 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`; + } + } + 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); + } + } +}; +</script> |