123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- <template>
- <view class="waterfalls-flow">
- <view v-for="(item,index) in data.column" :key="index" class="waterfalls-flow-column"
- :id="`waterfalls_flow_column_${index+1}`" :msg="msg" :style="{'width':w,'margin-left':index==0?0:m}">
- <view :class="['column-value',{'column-value-show':item2.o}]" v-for="(item2,index2) in columnValue(index)"
- :key="index2" :style="[s1]" @click.stop="wapperClick(item2)">
- <view class="inner" v-if="data.seat==1">
- <!-- #ifdef MP-WEIXIN -->
- <!-- #ifdef VUE2 -->
- <slot name="slot{{item2.index}}"></slot>
- <!-- #endif -->
- <!-- #ifdef VUE3 -->
- <slot :name="`slot${item2.index}`"></slot>
- <!-- #endif -->
- <!-- #endif -->
- <!-- #ifndef MP-WEIXIN -->
- <slot v-bind="item2"></slot>
- <!-- #endif -->
- </view>
- <image
- :class="['img',{'img-hide':item2[hideImageKey]==true||item2[hideImageKey]==1},{'img-error':!item2[data.imageKey]}]"
- :src="item2[data.imageKey]" mode="widthFix" @load="imgLoad(item2,index+1)"
- @error="imgError(item2,index+1)" @click.stop="imageClick(item2)"></image>
- <view class="inner" v-if="data.seat==2">
- <!-- #ifdef MP-WEIXIN -->
- <!-- #ifdef VUE2 -->
- <slot name="slot{{item2.index}}"></slot>
- <!-- #endif -->
- <!-- #ifdef VUE3 -->
- <slot :name="`slot${item2.index}`"></slot>
- <!-- #endif -->
- <!-- #endif -->
- <!-- #ifndef MP-WEIXIN -->
- <slot v-bind="item2"></slot>
- <!-- #endif -->
- </view>
- </view>
- </view>
- </view>
- </template>
- <script>
- export default {
- props: {
- value: Array,
- column: { // 列的数量
- type: [String, Number],
- default: 2
- },
- maxColumn: { // 最大列数
- type: [String, Number],
- default: 5
- },
- columnSpace: { // 列之间的间距 百分比
- type: [String, Number],
- default: 2
- },
- imageKey: { // 图片key
- type: [String],
- default: 'image'
- },
- hideImageKey: { // 隐藏图片key
- type: [String],
- default: 'hide'
- },
- seat: { // 文本的位置,1图片之上 2图片之下
- type: [String, Number],
- default: 2
- },
- listStyle: { // 单个展示项的样式:eg:{'background':'red'}
- type: Object
- }
- },
- data() {
- return {
- data: {
- list: this.value ? this.value : [],
- column: this.column < 2 ? 2 : this.column,
- columnSpace: this.columnSpace <= 5 ? this.columnSpace : 5,
- imageKey: this.imageKey,
- seat: this.seat
- },
- msg: 0,
- listInitStyle: {
- 'border-radius': '12rpx',
- 'margin-bottom': '20rpx',
- 'background-color': '#fff'
- },
- adds: [], //预置数据
- isLoaded: true,
- curIndex: 0,
- isRefresh: true,
- flag: false,
- refreshDatas: []
- }
- },
- computed: {
- // 计算列宽
- w() {
- const column_rate = `${100 / this.data.column - (+this.data.columnSpace)}%`;
- return column_rate;
- },
- // 计算margin
- m() {
- const column_margin =
- `${(100-(100 / this.data.column - (+this.data.columnSpace)).toFixed(5)*this.data.column)/(this.data.column-1)}%`;
- return column_margin;
- },
- // list样式
- s1() {
- return {
- ...this.listInitStyle,
- ...this.listStyle
- };
- }
- },
- created() {
- // 初始化
- this.refresh();
- },
- methods: {
- // 预加载图片
- loadImages(idx = 0) {
- let count = 0;
- const newList = this.data.list.filter((item, index) => index >= idx);
- for (let i = 0; i < newList.length; i++) {
- // #ifndef APP-PLUS
- uni.getImageInfo({
- src: `${newList[i][this.imageKey]}.jpg`,
- complete: res => {
- count++;
- if (count == newList.length) this.initValue(idx);
- }
- })
- // #endif
- // #ifdef APP-PLUS
- plus.io.getImageInfo({
- src: `${newList[i][this.imageKey]}.jpg`,
- complete: res => {
- count++;
- if (count == newList.length) this.initValue(idx);
- }
- })
- // #endif
- }
- },
- // 刷新
- refresh() {
- if (!this.isLoaded) {
- this.refreshDatas = this.value;
- return false;
- };
- setTimeout(() => {
- this.refreshDatas = [];
- this.isRefresh = true;
- this.adds = [];
- this.data.list = this.value ? this.value : [];
- this.data.column = this.column < 2 ? 2 : this.column >= this.maxColumn ? this.maxColumn : this
- .column;
- this.data.columnSpace = this.columnSpace <= 5 ? this.columnSpace : 5;
- this.data.imageKey = this.imageKey;
- this.data.seat = this.seat;
- this.curIndex = 0;
- // 每列的数据初始化
- for (let i = 1; i <= this.data.column; i++) {
- this.data[`column_${i}_values`] = [];
- this.msg++;
- }
- this.$nextTick(() => {
- this.initValue(this.curIndex, 'refresh==>');
- })
- }, 1)
- },
- columnValue(index) {
- return this.data[`column_${index+1}_values`];
- },
- change(newValue) {
- for (let i = 0; i < this.data.list.length; i++) {
- const cv = this.data[`column_${this.data.list[i].column}_values`];
- for (let j = 0; j < cv.length; j++) {
- if (newValue[i] && i === cv[j].index) {
- this.data[`column_${this.data.list[i].column}_values`][j] = Object.assign(cv[j], newValue[i]);
- this.msg++;
- break;
- }
- }
- }
- },
- getMin(a, s) {
- let m = a[0][s];
- let mo = a[0];
- for (var i = a.length - 1; i >= 0; i--) {
- if (a[i][s] < m) {
- m = a[i][s];
- }
- }
- mo = a.filter(i => i[s] == m);
- return mo[0];
- },
- // 计算每列的高度
- getMinColumnHeight() {
- return new Promise(resolve => {
- const heightArr = [];
- for (let i = 1; i <= this.data.column; i++) {
- const query = uni.createSelectorQuery().in(this);
- query.select(`#waterfalls_flow_column_${i}`).boundingClientRect(data => {
- heightArr.push({
- column: i,
- height: data.height
- });
- }).exec(() => {
- if (this.data.column <= heightArr.length) {
- resolve(this.getMin(heightArr, 'height'));
- }
- });
- }
- })
- },
- async initValue(i, from) {
- this.isLoaded = false;
- if (i >= this.data.list.length || this.refreshDatas.length) {
- this.msg++;
- this.loaded();
- return false;
- }
- const minHeightRes = await this.getMinColumnHeight();
- const c = this.data[`column_${minHeightRes.column}_values`];
- this.data.list[i].column = minHeightRes.column;
- c.push({
- ...this.data.list[i],
- cIndex: c.length,
- index: i,
- o: 0
- });
- this.msg++;
- },
- // 图片加载完成
- imgLoad(item, c) {
- const i = item.index;
- item.o = 1;
- this.$set(this.data[`column_${c}_values`], item.cIndex, JSON.parse(JSON.stringify(item)));
- this.initValue(i + 1);
- },
- // 图片加载失败
- imgError(item, c) {
- const i = item.index;
- item.o = 1;
- item[this.data.imageKey] = null;
- this.$set(this.data[`column_${c}_values`], item.cIndex, JSON.parse(JSON.stringify(item)));
- this.initValue(i + 1);
- },
- // 渲染结束
- loaded() {
- if (this.refreshDatas.length) {
- this.isLoaded = true;
- this.refresh();
- return false;
- }
- this.curIndex = this.data.list.length;
- if (this.adds.length) {
- this.data.list = this.adds[0];
- this.adds.splice(0, 1);
- this.initValue(this.curIndex);
- } else {
- if (this.data.list.length) this.$emit('loaded');
- this.isLoaded = true;
- this.isRefresh = false;
- }
- },
- // 单项点击事件
- wapperClick(item) {
- this.$emit('wapperClick', item);
- },
- // 图片点击事件
- imageClick(item) {
- this.$emit('imageClick', item);
- }
- },
- watch: {
- value: {
- deep: true,
- handler(newValue, oldValue) {
- setTimeout(() => {
- this.$nextTick(() => {
- if (this.isRefresh) return false;
- if (this.isLoaded) {
- // if (newValue.length <= this.curIndex) return this.refresh();
- if (newValue.length <= this.curIndex) return this.change(newValue);
- this.data.list = newValue;
- this.$nextTick(() => {
- this.initValue(this.curIndex, 'watch==>');
- })
- } else {
- this.adds.push(newValue);
- }
- })
- }, 10)
- }
- },
- column(newValue) {
- this.refresh();
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .waterfalls-flow {
- overflow: hidden;
- &-column {
- float: left;
- }
- }
- .column-value {
- width: 100%;
- font-size: 0;
- overflow: hidden;
- transition: opacity .4s;
- opacity: 0;
- position: relative;
- &-show {
- opacity: 1;
- }
- .inner {
- font-size: 30rpx;
- }
- .img {
- width: 100%;
- &-hide {
- display: none;
- }
- &-error {
- background: #f2f2f2 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAAAiAQMAAAAatXkPAAAABlBMVEUAAADMzMzIT8AyAAAAAXRSTlMAQObYZgAAAIZJREFUCNdlzjEKwkAUBNAfEGyCuYBkLyLuxRYW2SKlV1JSeA2tUiZg4YrLjv9PGsHqNTPMSAQuyAJgRDHSyvBPwtZoSJXakeJI9iuRLGDygdl6V0yKDtyMAeMPZySj8yfD+UapvRPj2JOwkyAooSV5IwdDjPdCPspe8LyTl9IKJvDETKKRv6vnlUasgg0fAAAAAElFTkSuQmCC) no-repeat center center;
- }
- }
- }
- </style>
|