You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
2.9 KiB
107 lines
2.9 KiB
|
3 years ago
|
<template>
|
||
|
|
<view :id="$sUid" class="s-waterfall" :class="custom_class" :style="custom_style">
|
||
|
|
<view v-for="(list, index) of columnList" :key="index" class="s-waterfall__column" :style="columnStyleList[index]">
|
||
|
|
<slot :scopeParams="scopeParams" :list="list" :index="index" />
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
import componentMixin from '../../mixins/componentMixin';
|
||
|
|
/**
|
||
|
|
* s-waterfall 瀑布流
|
||
|
|
* @description 瀑布流,自动分发各列数据,实现错位排列
|
||
|
|
* @property {Number|String} column 列数
|
||
|
|
* @property {Number|String} gutter 间距
|
||
|
|
* @property {Function} loadItem (item,callback) 自定义加载每个item,使用callback触发加载完毕
|
||
|
|
* @example <s-waterfall ref="waterfall"></s-waterfall>
|
||
|
|
*/
|
||
|
|
export default {
|
||
|
|
name: 'SWaterfall',
|
||
|
|
mixins: [componentMixin],
|
||
|
|
props: {
|
||
|
|
column: {
|
||
|
|
type: [Number, String],
|
||
|
|
default: 2,
|
||
|
|
},
|
||
|
|
gutter: {
|
||
|
|
type: [Number, String],
|
||
|
|
default: 20,
|
||
|
|
},
|
||
|
|
loadItem: Function,
|
||
|
|
},
|
||
|
|
data: () => ({
|
||
|
|
columnList: [],
|
||
|
|
}),
|
||
|
|
computed: {
|
||
|
|
columnStyleList() {
|
||
|
|
return this.columnList.map((_, index) => this.$mergeStyle({
|
||
|
|
marginLeft: index > 0 ? this.$addUnit(this.gutter) : '',
|
||
|
|
}));
|
||
|
|
},
|
||
|
|
},
|
||
|
|
watch: {
|
||
|
|
column() {
|
||
|
|
this.init();
|
||
|
|
},
|
||
|
|
},
|
||
|
|
created() {
|
||
|
|
this.list = [];
|
||
|
|
this.resetId = 0;
|
||
|
|
this.reset();
|
||
|
|
},
|
||
|
|
methods: {
|
||
|
|
init() {
|
||
|
|
const data = [...this.list];
|
||
|
|
this.reset();
|
||
|
|
this.push(data);
|
||
|
|
},
|
||
|
|
reset() {
|
||
|
|
const columnList = [];
|
||
|
|
const column = parseInt(this.column);
|
||
|
|
for (let i = 0; i < column; i++) {
|
||
|
|
columnList.push([]);
|
||
|
|
}
|
||
|
|
this.list = [];
|
||
|
|
this.columnList = columnList;
|
||
|
|
this.promise = Promise.resolve();
|
||
|
|
this.resetId++;
|
||
|
|
},
|
||
|
|
push(data) {
|
||
|
|
if (!this._isMounted || this._isDestroyed || !this.columnList.length) return;
|
||
|
|
const resetId = this.resetId;
|
||
|
|
const loadItem = this.$getPropsFn('loadItem');
|
||
|
|
this.list.push(...data);
|
||
|
|
this.$nextTick(() => {
|
||
|
|
if (resetId === this.resetId) {
|
||
|
|
data.forEach(item => {
|
||
|
|
this.promise = this.promise.then(() => new Promise(resolve => {
|
||
|
|
if (resetId === this.resetId) {
|
||
|
|
this.$getRect(`#${this.$sUid} .s-waterfall__column`, true).then(rects => {
|
||
|
|
if (resetId === this.resetId) {
|
||
|
|
const heights = rects.map(item => item.height);
|
||
|
|
const index = heights.indexOf(Math.min(...heights));
|
||
|
|
this.columnList[index].push(item);
|
||
|
|
if (loadItem) {
|
||
|
|
loadItem(item, resolve);
|
||
|
|
} else {
|
||
|
|
this.$nextTick(resolve);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
resolve();
|
||
|
|
}
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
resolve();
|
||
|
|
}
|
||
|
|
}));
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
},
|
||
|
|
},
|
||
|
|
};
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style lang="scss" src="./index.scss"></style>
|