fix: 首页和我的应用排序按 seq 排列

This commit is contained in:
2026-07-29 20:27:36 +08:00
parent 8c9613044c
commit ec6a5dd956
35 changed files with 18361 additions and 17013 deletions

View File

@@ -1,414 +1,414 @@
<template>
<view class="t-wrap">
<!-- 虚拟view用于计算,计算完成则消失 -->
<view class="t-txt-hide" :id="hid" v-if="!isCompute" :style="[computeStyle(0),{'text-align':oneRowTextAlign}]">
<text space="nbsp">{{testContent?testContent:content}}{{showSymbol?'...':''}}</text><text
v-if="expandText && collapseText && showSymbol" class="t-button">
{{expandText}}
</text><text></text>
</view>
<!-- 真实显示的内容 -->
<view class="t-ellipsis" :id="id"
:style="[!isCompute?computeStyle(1):computeStyle(2),{'text-align':oneRowTextAlign}]" @click="contentClick">
<text space="nbsp">{{(!isCompute || expand)?content:(actualContent+(showSymbol?'...':''))}}</text><text
v-if="expandText && collapseText && showSymbol" class="t-button" @click.stop="changeCollapse"
:style="{'color':actionFontColor}">{{!expand?expandText:collapseText}}</text><text></text>
</view>
<!-- 这里加入了自定义的动态骨架屏友好反馈 -->
<view v-if="!isCompute && rows>0" class="t-skeleton">
<view class="skeletons" v-for="(item,index) in rows" :key="index">
<view class="empty"></view>
</view>
</view>
</view>
</template>
<script>
//为了兼容部分老机型,增加扰动因子参数
const factor = 5;
export default {
name: "KevyEllipsis",
props: {
/**
* 文本唯一标识符,非必填
*/
textId: {
type: [String, Number],
default: ''
},
/**
* 文本内容,默认''
*/
content: {
type: String,
default: ''
},
/**
* 字体大小,单位rpx,默认28
*/
fontSize: {
type: [String, Number],
default: 28
},
/**
* 字体颜色,默认#666666
*/
fontColor: {
color: String,
default: '#666666'
},
/**
* 收起操作的文案,默认''
*/
collapseText: {
type: String,
default: ''
},
/**
* 展开操作的文案,默认''
*/
expandText: {
type: String,
default: ''
},
/**
* 收起、展开操作文字颜色,默认'#007aff'
*/
actionFontColor: {
color: String,
default: '#007aff'
},
/**
* 展示行数,默认1
*/
rows: {
type: Number,
default: 1
},
/**
* 只有一行时文本对齐方式,支持left、right、justify
*/
oneRowTextAlign: {
type: String,
default: "justify"
},
},
data() {
return {
//是否展开
expand: false,
//是否已计算
isCompute: false,
//内容高度
h: undefined,
//内容宽度
w: undefined,
//实际显示内容
actualContent: '',
//高度探测内容
testContent: undefined,
//是否显示省略号
showSymbol: false,
//hid和id,唯一标识符
hid: 'hid' + Math.random().toString(36).substr(2),
id: 'id' + Math.random().toString(36).substr(2),
};
},
mounted() {
this.$nextTick(() => {
this.initEllipsis();
})
},
computed: {
//动态计算组件样式
computeStyle() {
return b => {
let lines = this.rows > 0 ? this.rows : 1;
let obj = {};
if (b == 1) {
obj = {
'-webkit-line-clamp': lines,
'display': '-webkit-box',
'text-overflow': 'ellipsis',
'overflow': 'hidden',
'-webkit-box-orient': 'vertical'
};
} else if (b == 2) {
obj = {
'position': 'relative',
'left': '0rpx',
...obj
};
}
return {
'font-size': this.fontSize + 'rpx',
'color': this.fontColor,
...obj
}
}
}
},
watch: {
content(newVal, oldVal) {
this.expand=false;
this.isCompute=false;
this.h=undefined;
this.w=undefined;
this.actualContent='';
this.showSymbol=false;
this.initEllipsis();
}
},
methods: {
//初始化
initEllipsis() {
if (this.content?.length > 0) {
this.$nextTick(() => {
this.init(this, () => {
this.compute(this);
})
})
}
},
//收起展开状态切换
changeCollapse() {
this.expand = !this.expand;
},
//文本点击事件
contentClick() {
this.$emit('contentClick', this.textId);
},
//组件参数初始化
init($this, callback, isali) {
if (isali) {
uni.createSelectorQuery().in().select('#' + $this.id).boundingClientRect(d => {
$this.h = Number(d.height.toFixed(1));
$this.w = Number(d.width.toFixed(1));
if (callback) {
callback()
}
}).exec();
} else {
uni.createSelectorQuery().in($this).select('#' + $this.id).boundingClientRect(d => {
$this.h = Number(d.height.toFixed(1));
$this.w = Number(d.width.toFixed(1));
if (callback) {
callback()
}
}).exec();
}
},
//动态计算组件内容
computeContent($this, isali, dr) {
$this.$nextTick(() => {
$this.getH($this, isali, (ch) => {
if (ch - factor > $this.h) {
if (dr === -1) {
$this.testContent = $this.content.substring(0, $this.testContent.length -
1);
$this.computeContent($this, isali, dr);
} else {
$this.actualContent = $this.content.substring(0, $this.testContent.length -
1);
$this.isCompute = true;
}
} else {
if (dr === -1) {
$this.actualContent = $this.testContent;
$this.isCompute = true;
} else {
$this.testContent = $this.content.substring(0, $this.testContent.length +
1);
$this.computeContent($this, isali, dr);
}
}
})
});
},
//计算工具方法
compute($this, isali) {
let {
rows,
fontSize,
content,
h,
w
} = $this;
$this.testContent = content;
$this.$nextTick(() => {
$this.getH($this, isali, (ch) => {
if (ch - factor > h) {
let lh = h / rows;
let fn = Math.floor(w / $this.rpx2px(fontSize));
let sfn = fn * rows;
let i = $this.fontNum(content, sfn * 2 - ($this.expandText ? $this.fontNum(
$this.expandText) :
0) - 3);
$this.showSymbol = true;
$this.testContent = content.substring(0, i);
$this.$nextTick(() => {
$this.getH($this, isali, (ch1) => {
if (ch1 - factor > h) {
$this.testContent = content.substring(0, $this
.testContent.length - 1);
$this.computeContent($this, isali, -1);
} else {
$this.testContent = content.substring(0, $this
.testContent.length + 1);
$this.computeContent($this, isali, 1);
}
});
});
} else {
$this.isCompute = true;
$this.actualContent = content;
}
})
});
},
//动态计算字符数
fontNum(val, limit) {
let c = 0;
for (let i = 0; i < val.length; i++) {
let a = val.charAt(i);
if (a.match(/[^\x00-\xff]/ig) != null) {
if (limit) {
if (c + 2 > limit) {
return i;
} else {
c += 2;
}
} else {
c += 2;
}
} else {
if (limit) {
if (c + 1 > limit) {
return i;
} else {
c += 1;
}
} else {
c += 1;
}
}
}
if (!limit) {
return c;
}
},
rpx2px(rpx) {
return uni.getWindowInfo().windowWidth * Number(rpx) / 750;
},
getH($, isali, callback) {
if (isali) {
uni.createSelectorQuery().in().select('#' + $.hid).fields({
size: true
}, d => {
if(d && d.height){
callback(Number(d.height.toFixed(1)));
}
}).exec();
} else {
uni.createSelectorQuery().in($).select('#' + $.hid).fields({
size: true
}, d => {
if(d && d.height){
callback(Number(d.height.toFixed(1)));
}
}).exec();
}
}
}
}
</script>
<style lang="scss" scoped>
.t-wrap {
width: 100%;
box-sizing: border-box;
position: relative;
}
.t-txt-hide {
box-sizing: border-box;
word-break: break-all;
position: absolute;
top: 999999px;
left: 999999px;
z-index: -1000;
top: 0rpx;
width: 100%;
margin: 0rpx;
text-align: justify;
white-space: pre-line;
line-height: 1.5 !important;
.t-button {
float: right;
<template>
<view class="t-wrap">
<!-- 虚拟view用于计算,计算完成则消失 -->
<view class="t-txt-hide" :id="hid" v-if="!isCompute" :style="[computeStyle(0),{'text-align':oneRowTextAlign}]">
<text space="nbsp">{{testContent?testContent:content}}{{showSymbol?'...':''}}</text><text
v-if="expandText && collapseText && showSymbol" class="t-button">
{{expandText}}
</text><text></text>
</view>
<!-- 真实显示的内容 -->
<view class="t-ellipsis" :id="id"
:style="[!isCompute?computeStyle(1):computeStyle(2),{'text-align':oneRowTextAlign}]" @click="contentClick">
<text space="nbsp">{{(!isCompute || expand)?content:(actualContent+(showSymbol?'...':''))}}</text><text
v-if="expandText && collapseText && showSymbol" class="t-button" @click.stop="changeCollapse"
:style="{'color':actionFontColor}">{{!expand?expandText:collapseText}}</text><text></text>
</view>
<!-- 这里加入了自定义的动态骨架屏友好反馈 -->
<view v-if="!isCompute && rows>0" class="t-skeleton">
<view class="skeletons" v-for="(item,index) in rows" :key="index">
<view class="empty"></view>
</view>
</view>
</view>
</template>
<script>
//为了兼容部分老机型,增加扰动因子参数
const factor = 5;
export default {
name: "KevyEllipsis",
props: {
/**
* 文本唯一标识符,非必填
*/
textId: {
type: [String, Number],
default: ''
},
/**
* 文本内容,默认''
*/
content: {
type: String,
default: ''
},
/**
* 字体大小,单位rpx,默认28
*/
fontSize: {
type: [String, Number],
default: 28
},
/**
* 字体颜色,默认#666666
*/
fontColor: {
color: String,
default: '#666666'
},
/**
* 收起操作的文案,默认''
*/
collapseText: {
type: String,
default: ''
},
/**
* 展开操作的文案,默认''
*/
expandText: {
type: String,
default: ''
},
/**
* 收起、展开操作文字颜色,默认'#007aff'
*/
actionFontColor: {
color: String,
default: '#007aff'
},
/**
* 展示行数,默认1
*/
rows: {
type: Number,
default: 1
},
/**
* 只有一行时文本对齐方式,支持left、right、justify
*/
oneRowTextAlign: {
type: String,
default: "justify"
},
},
data() {
return {
//是否展开
expand: false,
//是否已计算
isCompute: false,
//内容高度
h: undefined,
//内容宽度
w: undefined,
//实际显示内容
actualContent: '',
//高度探测内容
testContent: undefined,
//是否显示省略号
showSymbol: false,
//hid和id,唯一标识符
hid: 'hid' + Math.random().toString(36).substr(2),
id: 'id' + Math.random().toString(36).substr(2),
};
},
mounted() {
this.$nextTick(() => {
this.initEllipsis();
})
},
computed: {
//动态计算组件样式
computeStyle() {
return b => {
let lines = this.rows > 0 ? this.rows : 1;
let obj = {};
if (b == 1) {
obj = {
'-webkit-line-clamp': lines,
'display': '-webkit-box',
'text-overflow': 'ellipsis',
'overflow': 'hidden',
'-webkit-box-orient': 'vertical'
};
} else if (b == 2) {
obj = {
'position': 'relative',
'left': '0rpx',
...obj
};
}
return {
'font-size': this.fontSize + 'rpx',
'color': this.fontColor,
...obj
}
}
}
},
watch: {
content(newVal, oldVal) {
this.expand=false;
this.isCompute=false;
this.h=undefined;
this.w=undefined;
this.actualContent='';
this.showSymbol=false;
this.initEllipsis();
}
},
methods: {
//初始化
initEllipsis() {
if (this.content?.length > 0) {
this.$nextTick(() => {
this.init(this, () => {
this.compute(this);
})
})
}
},
//收起展开状态切换
changeCollapse() {
this.expand = !this.expand;
},
//文本点击事件
contentClick() {
this.$emit('contentClick', this.textId);
},
//组件参数初始化
init($this, callback, isali) {
if (isali) {
uni.createSelectorQuery().in().select('#' + $this.id).boundingClientRect(d => {
$this.h = Number(d.height.toFixed(1));
$this.w = Number(d.width.toFixed(1));
if (callback) {
callback()
}
}).exec();
} else {
uni.createSelectorQuery().in($this).select('#' + $this.id).boundingClientRect(d => {
$this.h = Number(d.height.toFixed(1));
$this.w = Number(d.width.toFixed(1));
if (callback) {
callback()
}
}).exec();
}
},
//动态计算组件内容
computeContent($this, isali, dr) {
$this.$nextTick(() => {
$this.getH($this, isali, (ch) => {
if (ch - factor > $this.h) {
if (dr === -1) {
$this.testContent = $this.content.substring(0, $this.testContent.length -
1);
$this.computeContent($this, isali, dr);
} else {
$this.actualContent = $this.content.substring(0, $this.testContent.length -
1);
$this.isCompute = true;
}
} else {
if (dr === -1) {
$this.actualContent = $this.testContent;
$this.isCompute = true;
} else {
$this.testContent = $this.content.substring(0, $this.testContent.length +
1);
$this.computeContent($this, isali, dr);
}
}
})
});
},
//计算工具方法
compute($this, isali) {
let {
rows,
fontSize,
content,
h,
w
} = $this;
$this.testContent = content;
$this.$nextTick(() => {
$this.getH($this, isali, (ch) => {
if (ch - factor > h) {
let lh = h / rows;
let fn = Math.floor(w / $this.rpx2px(fontSize));
let sfn = fn * rows;
let i = $this.fontNum(content, sfn * 2 - ($this.expandText ? $this.fontNum(
$this.expandText) :
0) - 3);
$this.showSymbol = true;
$this.testContent = content.substring(0, i);
$this.$nextTick(() => {
$this.getH($this, isali, (ch1) => {
if (ch1 - factor > h) {
$this.testContent = content.substring(0, $this
.testContent.length - 1);
$this.computeContent($this, isali, -1);
} else {
$this.testContent = content.substring(0, $this
.testContent.length + 1);
$this.computeContent($this, isali, 1);
}
});
});
} else {
$this.isCompute = true;
$this.actualContent = content;
}
})
});
},
//动态计算字符数
fontNum(val, limit) {
let c = 0;
for (let i = 0; i < val.length; i++) {
let a = val.charAt(i);
if (a.match(/[^\x00-\xff]/ig) != null) {
if (limit) {
if (c + 2 > limit) {
return i;
} else {
c += 2;
}
} else {
c += 2;
}
} else {
if (limit) {
if (c + 1 > limit) {
return i;
} else {
c += 1;
}
} else {
c += 1;
}
}
}
if (!limit) {
return c;
}
},
rpx2px(rpx) {
return uni.getWindowInfo().windowWidth * Number(rpx) / 750;
},
getH($, isali, callback) {
if (isali) {
uni.createSelectorQuery().in().select('#' + $.hid).fields({
size: true
}, d => {
if(d && d.height){
callback(Number(d.height.toFixed(1)));
}
}).exec();
} else {
uni.createSelectorQuery().in($).select('#' + $.hid).fields({
size: true
}, d => {
if(d && d.height){
callback(Number(d.height.toFixed(1)));
}
}).exec();
}
}
}
}
</script>
<style lang="scss" scoped>
.t-wrap {
width: 100%;
box-sizing: border-box;
position: relative;
}
.t-txt-hide {
box-sizing: border-box;
word-break: break-all;
position: absolute;
top: 999999px;
left: 999999px;
z-index: -1000;
top: 0rpx;
width: 100%;
margin: 0rpx;
text-align: justify;
white-space: pre-line;
line-height: 1.5 !important;
.t-button {
float: right;
clear: both;
}
}
.t-ellipsis {
text-align: justify;
box-sizing: border-box;
width: 100%;
word-break: break-all;
position: relative;
left: 99999px;
white-space: pre-line;
line-height: 1.5 !important;
.t-button {
float: right;
clear: both;
}
}
.t-ellipsis {
text-align: justify;
box-sizing: border-box;
width: 100%;
word-break: break-all;
position: relative;
left: 99999px;
white-space: pre-line;
line-height: 1.5 !important;
.t-button {
float: right;
clear: both;
font-weight: 500;
}
}
.t-skeleton {
width: 100%;
height: 100%;
box-sizing: border-box;
position: absolute;
top: 0rpx;
left: 0rpx;
}
.skeletons:first-child {
margin-top: 0rpx !important;
}
.skeletons {
position: relative;
display: block;
overflow: hidden;
width: 100%;
height: 32rpx;
margin-top: 12rpx;
background-color: rgba(0, 0, 0, 0.06);
box-sizing: border-box;
}
.skeletons .empty {
display: block;
position: absolute;
width: 100%;
height: 100%;
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
background: linear-gradient(90deg, transparent, rgba(216, 216, 216, 0.753), transparent);
-webkit-animation: loading .8s infinite;
animation: loading .8s infinite;
}
@keyframes loading {
100% {
-webkit-transform: translateX(100%);
transform: translateX(100%);
}
}
font-weight: 500;
}
}
.t-skeleton {
width: 100%;
height: 100%;
box-sizing: border-box;
position: absolute;
top: 0rpx;
left: 0rpx;
}
.skeletons:first-child {
margin-top: 0rpx !important;
}
.skeletons {
position: relative;
display: block;
overflow: hidden;
width: 100%;
height: 32rpx;
margin-top: 12rpx;
background-color: rgba(0, 0, 0, 0.06);
box-sizing: border-box;
}
.skeletons .empty {
display: block;
position: absolute;
width: 100%;
height: 100%;
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
background: linear-gradient(90deg, transparent, rgba(216, 216, 216, 0.753), transparent);
-webkit-animation: loading .8s infinite;
animation: loading .8s infinite;
}
@keyframes loading {
100% {
-webkit-transform: translateX(100%);
transform: translateX(100%);
}
}
</style>

View File

@@ -1,218 +1,218 @@
<template>
<view :class="'wf-page wf-page'+type">
<!-- left -->
<view>
<view id="left" v-if="leftList.length">
<view v-for="(item,index) in leftList" :key="index"
class="wf-item" @tap="itemTap(item)">
<WaterfallsFlowItem
:item="item"
:isStore="isStore"
:type="type"
:isMerchant="isMerchant"
:recommend="recommend"
:showCart="showCart"/>
</view>
</view>
</view>
<!-- right -->
<view>
<view id="right" v-if="rightList.length">
<view v-for="(item,index) in rightList" :key="index"
class="wf-item" @tap="itemTap(item)">
<WaterfallsFlowItem
:item="item"
:isStore="isStore"
:type="type"
:isMerchant="isMerchant"
:recommend="recommend"
:showCart="showCart"/>
</view>
</view>
</view>
</view>
</template>
<script>
import WaterfallsFlowItem from './WaterfallsFlowItem.vue'
export default {
components: {
WaterfallsFlowItem
},
props: {
// 瀑布流列表
wfList: {
type: Array,
require: true
},
updateNum: {
type: Number,
default: 10
},
type: {
type: Number,
default: 0
},
isStore: {
type: [String, Number],
default: '1'
},
recommend:{
type: Boolean,
default: false
},
showCart:{
type: Boolean,
default: true
},
isMerchant:{
type: Boolean,
default: false
}
},
data() {
return {
allList: [], // 全部列表
leftList: [], // 左边列表
rightList: [], // 右边列表
mark: 0, // 列表标记
boxHeight: [], // 下标0和1分别为左列和右列高度
};
},
watch: {
// 监听列表数据变化
wfList: {
handler(nVal,oVal){
// 如果数据为空或新的列表数据少于旧的列表数据(通常为下拉刷新或切换排序或使用筛选器),初始化变量
if (!this.wfList.length ||
(this.wfList.length === this.updateNum && this.wfList.length <= this.allList.length)) {
this.allList = [];
this.leftList = [];
this.rightList = [];
this.boxHeight = [];
this.mark = 0;
}
// 如果列表有值,调用waterfall方法
if (this.wfList.length) {
this.allList = this.wfList;
this.leftList = [];
this.rightList = [];
this.boxHeight = [];
this.allList.forEach((v, i) => {
if(this.allList.length < 3 || (this.allList.length <= 7 && this.allList.length - i > 1) || (this.allList.length > 7 && this.allList.length - i > 2)) {
if(i % 2){
this.rightList.push(v);
}else{
this.leftList.push(v);
}
}
});
if(this.allList.length < 3){
this.mark = this.allList.length+1;
}else if(this.allList.length <= 7){
this.mark = this.allList.length - 1;
}else{
this.mark = this.allList.length - 2;
}
if(this.mark < this.allList.length){
this.waterFall()
}
}
},
immediate: true,
deep:true
},
mounted(){
},
// 监听标记,当标记发生变化,则执行下一个item排序
mark() {
const len = this.allList.length;
if (this.mark < len && this.mark !== 0 && this.boxHeight.length) {
this.waterFall();
}
}
},
methods: {
// 瀑布流排序
waterFall() {
const i = this.mark;
if (i == 0) {
// 初始化,从左边开始插入
this.leftList.push(this.allList[i]);
// 更新左边列表高度
this.getViewHeight(0);
} else if (i == 1) {
// 第二个item插入,默认为右边插入
this.rightList.push(this.allList[i]);
// 更新右边列表高度
this.getViewHeight(1);
} else {
// 根据左右列表高度判断下一个item应该插入哪边
if(!this.boxHeight.length){
this.rightList.length < this.leftList.length
? this.rightList.push(this.allList[i])
: this.leftList.push(this.allList[i]);
} else {
const leftOrRight = this.boxHeight[0] > this.boxHeight[1] ? 1 : 0;
if (leftOrRight) {
this.rightList.push(this.allList[i])
} else {
this.leftList.push(this.allList[i])
}
}
// 更新插入列表高度
this.getViewHeight();
}
},
// 获取列表高度
getViewHeight() {
// 使用nextTick,确保页面更新结束后,再请求高度
this.$nextTick(() => {
setTimeout(()=>{
uni.createSelectorQuery().in(this).select('#right').boundingClientRect(res => {
res ? this.boxHeight[1] = res.height : '';
uni.createSelectorQuery().in(this).select('#left').boundingClientRect(res => {
res ? this.boxHeight[0] = res.height : '';
this.mark = this.mark + 1;
}).exec();
}).exec();
},100)
})
},
// item点击
itemTap(item) {
this.$emit('itemTap', item)
},
// item点击
goShop(item) {
this.$emit('goShop', item)
}
}
}
</script>
<style lang="scss" scoped>
$page-padding: 10px;
$grid-gap: 10px;
.wf-page {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: $grid-gap;
}
.wf-item {
width: calc((100vw - 2 * #{$page-padding} - #{$grid-gap}) / 2);
padding-bottom: $grid-gap;
}
.wf-page1 .wf-item{
margin-top: 20rpx;
background-color: #fff;
border-radius: 20rpx;
padding-bottom: 0;
}
<template>
<view :class="'wf-page wf-page'+type">
<!-- left -->
<view>
<view id="left" v-if="leftList.length">
<view v-for="(item,index) in leftList" :key="index"
class="wf-item" @tap="itemTap(item)">
<WaterfallsFlowItem
:item="item"
:isStore="isStore"
:type="type"
:isMerchant="isMerchant"
:recommend="recommend"
:showCart="showCart"/>
</view>
</view>
</view>
<!-- right -->
<view>
<view id="right" v-if="rightList.length">
<view v-for="(item,index) in rightList" :key="index"
class="wf-item" @tap="itemTap(item)">
<WaterfallsFlowItem
:item="item"
:isStore="isStore"
:type="type"
:isMerchant="isMerchant"
:recommend="recommend"
:showCart="showCart"/>
</view>
</view>
</view>
</view>
</template>
<script>
import WaterfallsFlowItem from './WaterfallsFlowItem.vue'
export default {
components: {
WaterfallsFlowItem
},
props: {
// 瀑布流列表
wfList: {
type: Array,
require: true
},
updateNum: {
type: Number,
default: 10
},
type: {
type: Number,
default: 0
},
isStore: {
type: [String, Number],
default: '1'
},
recommend:{
type: Boolean,
default: false
},
showCart:{
type: Boolean,
default: true
},
isMerchant:{
type: Boolean,
default: false
}
},
data() {
return {
allList: [], // 全部列表
leftList: [], // 左边列表
rightList: [], // 右边列表
mark: 0, // 列表标记
boxHeight: [], // 下标0和1分别为左列和右列高度
};
},
watch: {
// 监听列表数据变化
wfList: {
handler(nVal,oVal){
// 如果数据为空或新的列表数据少于旧的列表数据(通常为下拉刷新或切换排序或使用筛选器),初始化变量
if (!this.wfList.length ||
(this.wfList.length === this.updateNum && this.wfList.length <= this.allList.length)) {
this.allList = [];
this.leftList = [];
this.rightList = [];
this.boxHeight = [];
this.mark = 0;
}
// 如果列表有值,调用waterfall方法
if (this.wfList.length) {
this.allList = this.wfList;
this.leftList = [];
this.rightList = [];
this.boxHeight = [];
this.allList.forEach((v, i) => {
if(this.allList.length < 3 || (this.allList.length <= 7 && this.allList.length - i > 1) || (this.allList.length > 7 && this.allList.length - i > 2)) {
if(i % 2){
this.rightList.push(v);
}else{
this.leftList.push(v);
}
}
});
if(this.allList.length < 3){
this.mark = this.allList.length+1;
}else if(this.allList.length <= 7){
this.mark = this.allList.length - 1;
}else{
this.mark = this.allList.length - 2;
}
if(this.mark < this.allList.length){
this.waterFall()
}
}
},
immediate: true,
deep:true
},
mounted(){
},
// 监听标记,当标记发生变化,则执行下一个item排序
mark() {
const len = this.allList.length;
if (this.mark < len && this.mark !== 0 && this.boxHeight.length) {
this.waterFall();
}
}
},
methods: {
// 瀑布流排序
waterFall() {
const i = this.mark;
if (i == 0) {
// 初始化,从左边开始插入
this.leftList.push(this.allList[i]);
// 更新左边列表高度
this.getViewHeight(0);
} else if (i == 1) {
// 第二个item插入,默认为右边插入
this.rightList.push(this.allList[i]);
// 更新右边列表高度
this.getViewHeight(1);
} else {
// 根据左右列表高度判断下一个item应该插入哪边
if(!this.boxHeight.length){
this.rightList.length < this.leftList.length
? this.rightList.push(this.allList[i])
: this.leftList.push(this.allList[i]);
} else {
const leftOrRight = this.boxHeight[0] > this.boxHeight[1] ? 1 : 0;
if (leftOrRight) {
this.rightList.push(this.allList[i])
} else {
this.leftList.push(this.allList[i])
}
}
// 更新插入列表高度
this.getViewHeight();
}
},
// 获取列表高度
getViewHeight() {
// 使用nextTick,确保页面更新结束后,再请求高度
this.$nextTick(() => {
setTimeout(()=>{
uni.createSelectorQuery().in(this).select('#right').boundingClientRect(res => {
res ? this.boxHeight[1] = res.height : '';
uni.createSelectorQuery().in(this).select('#left').boundingClientRect(res => {
res ? this.boxHeight[0] = res.height : '';
this.mark = this.mark + 1;
}).exec();
}).exec();
},100)
})
},
// item点击
itemTap(item) {
this.$emit('itemTap', item)
},
// item点击
goShop(item) {
this.$emit('goShop', item)
}
}
}
</script>
<style lang="scss" scoped>
$page-padding: 10px;
$grid-gap: 10px;
.wf-page {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: $grid-gap;
}
.wf-item {
width: calc((100vw - 2 * #{$page-padding} - #{$grid-gap}) / 2);
padding-bottom: $grid-gap;
}
.wf-page1 .wf-item{
margin-top: 20rpx;
background-color: #fff;
border-radius: 20rpx;
padding-bottom: 0;
}
</style>

View File

@@ -1,225 +1,225 @@
<template>
<view :class="'wf-page wf-page'+type">
<!-- left -->
<view>
<view id="left" v-if="leftList.length">
<view v-for="(item,index) in leftList" :key="index"
class="wf-item" @tap="itemTap(item)">
<WaterfallsFlowItem :item="item" :border="border" />
</view>
</view>
</view>
<!-- right -->
<view>
<view id="right" v-if="rightList.length">
<view v-for="(item,index) in rightList" :key="index"
class="wf-item" @tap="itemTap(item)">
<WaterfallsFlowItem :item="item" :border="border" />
</view>
</view>
</view>
</view>
</template>
<script>
import WaterfallsFlowItem from './WaterfallsFlowItem.vue';
import {LOGIN_STATUS} from '@/config/cache';
import { HTTP_REQUEST_URL } from '@/config/app';
export default {
components: {
WaterfallsFlowItem
},
props: {
// 瀑布流列表
wfList: {
type: Array,
require: true
},
type: {
type: Number,
default: 0
},
updateNum: {
type: Number,
default: 10
},
border:{
type:Boolean,
default: false
},
isSelf:{
type:Boolean,
default: false
}
},
data() {
return {
allList: [], // 全部列表
leftList: [], // 左边列表
rightList: [], // 右边列表
mark: 0, // 列表标记
boxHeight: [], // 下标0和1分别为左列和右列高度
};
},
watch: {
// 监听列表数据变化
wfList: {
handler(nVal,oVal){
// 如果数据为空或新的列表数据少于旧的列表数据(通常为下拉刷新或切换排序或使用筛选器),初始化变量
if (!this.wfList.length ||
(this.wfList.length === this.updateNum && this.wfList.length <= this.allList.length)) {
this.allList = [];
this.leftList = [];
this.rightList = [];
this.boxHeight = [];
this.mark = 0;
}
// 如果列表有值,调用waterfall方法
if (this.wfList.length) {
this.allList = this.wfList;
this.leftList = [];
this.rightList = [];
this.boxHeight = [];
this.allList.forEach((v, i) => {
if(this.allList.length < 3 || (this.allList.length <= 7 && this.allList.length - i > 1) || (this.allList.length > 7 && this.allList.length - i > 2)) {
if(i % 2){
this.rightList.push(v);
}else{
this.leftList.push(v);
}
}
});
if(this.allList.length < 3){
this.mark = this.allList.length+1;
}else if(this.allList.length <= 7){
this.mark = this.allList.length - 1;
}else{
this.mark = this.allList.length - 2;
}
if(this.mark < this.allList.length){
this.waterFall()
}
}
},
immediate: true,
deep:true
},
mounted(){
},
// 监听标记,当标记发生变化,则执行下一个item排序
mark() {
const len = this.allList.length;
if (this.mark < len && this.mark !== 0 && this.boxHeight.length) {
this.waterFall();
}
}
},
methods: {
// 瀑布流排序
waterFall() {
const i = this.mark;
if (i == 0) {
// 初始化,从左边开始插入
this.leftList.push(this.allList[i]);
// 更新左边列表高度
this.getViewHeight(0);
} else if (i == 1) {
// 第二个item插入,默认为右边插入
this.rightList.push(this.allList[i]);
// 更新右边列表高度
this.getViewHeight(1);
} else {
// 根据左右列表高度判断下一个item应该插入哪边
if(!this.boxHeight.length){
this.rightList.length < this.leftList.length
? this.rightList.push(this.allList[i])
: this.leftList.push(this.allList[i]);
} else {
const leftOrRight = this.boxHeight[0] > this.boxHeight[1] ? 1 : 0;
if (leftOrRight) {
this.rightList.push(this.allList[i])
} else {
this.leftList.push(this.allList[i])
}
}
// 更新插入列表高度
this.getViewHeight();
}
},
// 获取列表高度
getViewHeight() {
// 使用nextTick,确保页面更新结束后,再请求高度
this.$nextTick(() => {
setTimeout(()=>{
uni.createSelectorQuery().in(this).select('#right').boundingClientRect(res => {
res ? this.boxHeight[1] = res.height : '';
uni.createSelectorQuery().in(this).select('#left').boundingClientRect(res => {
res ? this.boxHeight[0] = res.height : '';
this.mark = this.mark + 1;
}).exec();
}).exec();
},100)
})
},
// item点击
itemTap(item) {
if(item.content_type == 1){
uni.navigateTo({
url: '/pages/discover/discoverDetails/index?id=' + item.id
})
}else{
let that = this;
if(this.isSelf){
uni.navigateTo({
// #ifdef MP || H5
url: '/pages/discover/discoverVideo/index?id=' + item.id + '&relation_id=' + item.relation_id
// #endif
// #ifdef APP-PLUS
url: `/pages/discover/discoverVideo/app?url=${HTTP_REQUEST_URL}/pages/discover/discoverVideo/index?content_type=2&token=${that.$Cache.get(LOGIN_STATUS)}&relation_id=${item.relation_id}`
// #endif
})
}else{
// #ifdef MP || H5
uni.navigateTo({
url: '/pages/discover/discoverVideo/index?id=' + item.id
})
// #endif
// #ifdef APP-PLUS
let href = encodeURIComponent(`${HTTP_REQUEST_URL}/pages/discover/discoverVideo/index?content_type=2&id=${item.id}&token=${that.$Cache.get(LOGIN_STATUS)}`)
uni.navigateTo({
url: `/pages/discover/discoverVideo/app?url=${href}`
})
// #endif
}
}
},
}
}
</script>
<style lang="scss" scoped>
$page-padding: 10px;
$grid-gap: 10px;
.wf-page {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: $grid-gap;
}
.wf-item {
width: calc((100vw - 2 * #{$page-padding} - #{$grid-gap}) / 2);
padding-bottom: $grid-gap;
}
.wf-page1 .wf-item{
margin-top: 20rpx;
background-color: #fff;
border-radius: 20rpx;
padding-bottom: 0;
}
<template>
<view :class="'wf-page wf-page'+type">
<!-- left -->
<view>
<view id="left" v-if="leftList.length">
<view v-for="(item,index) in leftList" :key="index"
class="wf-item" @tap="itemTap(item)">
<WaterfallsFlowItem :item="item" :border="border" />
</view>
</view>
</view>
<!-- right -->
<view>
<view id="right" v-if="rightList.length">
<view v-for="(item,index) in rightList" :key="index"
class="wf-item" @tap="itemTap(item)">
<WaterfallsFlowItem :item="item" :border="border" />
</view>
</view>
</view>
</view>
</template>
<script>
import WaterfallsFlowItem from './WaterfallsFlowItem.vue';
import {LOGIN_STATUS} from '@/config/cache';
import { HTTP_REQUEST_URL } from '@/config/app';
export default {
components: {
WaterfallsFlowItem
},
props: {
// 瀑布流列表
wfList: {
type: Array,
require: true
},
type: {
type: Number,
default: 0
},
updateNum: {
type: Number,
default: 10
},
border:{
type:Boolean,
default: false
},
isSelf:{
type:Boolean,
default: false
}
},
data() {
return {
allList: [], // 全部列表
leftList: [], // 左边列表
rightList: [], // 右边列表
mark: 0, // 列表标记
boxHeight: [], // 下标0和1分别为左列和右列高度
};
},
watch: {
// 监听列表数据变化
wfList: {
handler(nVal,oVal){
// 如果数据为空或新的列表数据少于旧的列表数据(通常为下拉刷新或切换排序或使用筛选器),初始化变量
if (!this.wfList.length ||
(this.wfList.length === this.updateNum && this.wfList.length <= this.allList.length)) {
this.allList = [];
this.leftList = [];
this.rightList = [];
this.boxHeight = [];
this.mark = 0;
}
// 如果列表有值,调用waterfall方法
if (this.wfList.length) {
this.allList = this.wfList;
this.leftList = [];
this.rightList = [];
this.boxHeight = [];
this.allList.forEach((v, i) => {
if(this.allList.length < 3 || (this.allList.length <= 7 && this.allList.length - i > 1) || (this.allList.length > 7 && this.allList.length - i > 2)) {
if(i % 2){
this.rightList.push(v);
}else{
this.leftList.push(v);
}
}
});
if(this.allList.length < 3){
this.mark = this.allList.length+1;
}else if(this.allList.length <= 7){
this.mark = this.allList.length - 1;
}else{
this.mark = this.allList.length - 2;
}
if(this.mark < this.allList.length){
this.waterFall()
}
}
},
immediate: true,
deep:true
},
mounted(){
},
// 监听标记,当标记发生变化,则执行下一个item排序
mark() {
const len = this.allList.length;
if (this.mark < len && this.mark !== 0 && this.boxHeight.length) {
this.waterFall();
}
}
},
methods: {
// 瀑布流排序
waterFall() {
const i = this.mark;
if (i == 0) {
// 初始化,从左边开始插入
this.leftList.push(this.allList[i]);
// 更新左边列表高度
this.getViewHeight(0);
} else if (i == 1) {
// 第二个item插入,默认为右边插入
this.rightList.push(this.allList[i]);
// 更新右边列表高度
this.getViewHeight(1);
} else {
// 根据左右列表高度判断下一个item应该插入哪边
if(!this.boxHeight.length){
this.rightList.length < this.leftList.length
? this.rightList.push(this.allList[i])
: this.leftList.push(this.allList[i]);
} else {
const leftOrRight = this.boxHeight[0] > this.boxHeight[1] ? 1 : 0;
if (leftOrRight) {
this.rightList.push(this.allList[i])
} else {
this.leftList.push(this.allList[i])
}
}
// 更新插入列表高度
this.getViewHeight();
}
},
// 获取列表高度
getViewHeight() {
// 使用nextTick,确保页面更新结束后,再请求高度
this.$nextTick(() => {
setTimeout(()=>{
uni.createSelectorQuery().in(this).select('#right').boundingClientRect(res => {
res ? this.boxHeight[1] = res.height : '';
uni.createSelectorQuery().in(this).select('#left').boundingClientRect(res => {
res ? this.boxHeight[0] = res.height : '';
this.mark = this.mark + 1;
}).exec();
}).exec();
},100)
})
},
// item点击
itemTap(item) {
if(item.content_type == 1){
uni.navigateTo({
url: '/pages/discover/discoverDetails/index?id=' + item.id
})
}else{
let that = this;
if(this.isSelf){
uni.navigateTo({
// #ifdef MP || H5
url: '/pages/discover/discoverVideo/index?id=' + item.id + '&relation_id=' + item.relation_id
// #endif
// #ifdef APP-PLUS
url: `/pages/discover/discoverVideo/app?url=${HTTP_REQUEST_URL}/pages/discover/discoverVideo/index?content_type=2&token=${that.$Cache.get(LOGIN_STATUS)}&relation_id=${item.relation_id}`
// #endif
})
}else{
// #ifdef MP || H5
uni.navigateTo({
url: '/pages/discover/discoverVideo/index?id=' + item.id
})
// #endif
// #ifdef APP-PLUS
let href = encodeURIComponent(`${HTTP_REQUEST_URL}/pages/discover/discoverVideo/index?content_type=2&id=${item.id}&token=${that.$Cache.get(LOGIN_STATUS)}`)
uni.navigateTo({
url: `/pages/discover/discoverVideo/app?url=${href}`
})
// #endif
}
}
},
}
}
</script>
<style lang="scss" scoped>
$page-padding: 10px;
$grid-gap: 10px;
.wf-page {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: $grid-gap;
}
.wf-item {
width: calc((100vw - 2 * #{$page-padding} - #{$grid-gap}) / 2);
padding-bottom: $grid-gap;
}
.wf-page1 .wf-item{
margin-top: 20rpx;
background-color: #fff;
border-radius: 20rpx;
padding-bottom: 0;
}
</style>