first commit

This commit is contained in:
lxj
2025-06-26 12:38:35 +08:00
commit c536475e19
1236 changed files with 186274 additions and 0 deletions

View File

@@ -0,0 +1,68 @@
<template>
<view class="waterfall-item-container">
<view class="waterfall-item" @tap="onTap">
<image :src="params.image" mode="widthFix" @load="emitHeight" @error="emitHeight"></image>
<view class="content">
<view>{{params.name}}</view>
<view>{{params.msg}}</view>
</view>
</view>
</view>
</template>
<script>
export default {
name:"helangWaterfallItem",
options:{
virtualHost: true
},
props:{
params:{
type: Object,
default(){
return {}
}
},
tag:{
type:String | Number,
default:''
},
index:{
type:Number,
default:-1
}
},
data() {
return {
};
},
methods:{
// 发出组件高度信息,在此处可以区分正确和错误的加载,给予错误的提示图片
emitHeight(e){
const query = uni.createSelectorQuery().in(this);
query.select('.waterfall-item-container').boundingClientRect(data => {
let height = Math.floor(data.height);
this.$emit("height",height,this.$props.tag);
}).exec();
},
onTap(){
this.$emit("click",this.$props.index,this.$props.tag);
}
}
}
</script>
<style lang="scss" scoped>
.waterfall-item{
width: 100%; background: #fff; border-radius: 10rpx;
image{ display: block; width: 100%; height: 350rpx; border-radius: 10rpx 10rpx 0 0; }
.content{
width: 100%; height: 160rpx; box-sizing: border-box; padding: 20rpx 20rpx 0;
view{
&:nth-child(1){ line-height: 40rpx; color: #333; font-size: 28rpx; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
&:nth-child(2){ margin-top: 10rpx; line-height: 34rpx; height: 68rpx; color: #999; font-size: 24rpx; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
}
}
}
</style>

View File

@@ -0,0 +1,238 @@
<template>
<view>
<view class="waterfall-box h-flex-x h-flex-2" v-if="showList">
<view>
<view v-for="(item,index) in leftList" :key="item._render_id"
class="list-item"
:class="{'show': showPage > item._current_page }"
>
<helang-waterfall-item
:params="item"
tag="left"
:index="index"
@height="onHeight"
@click="onClick"
></helang-waterfall-item>
</view>
</view>
<view>
<view v-for="(item,index) in rightList" :key="item._render_id"
class="list-item"
:class="{'show': showPage > item._current_page }"
>
<helang-waterfall-item
:params="item"
@height="onHeight"
@click="onClick"
tag="right"
:index="index"
></helang-waterfall-item>
</view>
</view>
</view>
<slot name="default"></slot>
</view>
</template>
<script>
import helangWaterfallItem from "./waterfall-item.vue"
export default {
name:"helangWaterfallList",
options:{
virtualHost: true
},
components: {
"helang-waterfall-item": helangWaterfallItem
},
props:{
// 组件状态
status:{
type: String,
default:''
},
// 待渲染的数据
list:{
type: Array,
default(){
return [];
}
},
// 重置列表,设置为 true 时,瀑布流会自动重新渲染列表
reset:{
type: Boolean,
default:false
},
},
watch:{
"$props.status"(newValue,oldValue){
// 状态变更为 加载成功 时,执行瀑布流数据渲染
if(newValue == 'success'){
this.startRender();
}else if(!this.showList){
this.resetData();
}
}
},
computed:{
showList(){
return !["fail","empty"].includes(this.$props.status);
}
},
data() {
return {
// 左侧列表高度
leftHeight: 0,
// 右侧列表高度
rightHeight: 0,
// 左侧列表数据
leftList: [],
// 右侧列表数据
rightList: [],
// 待渲染列表
awaitRenderList:[],
// 当前展示页码数据
showPage:1
}
},
mounted() {
if(this.$props.status == 'success'){
this.startRender();
}
},
methods: {
// 监听高度变化
onHeight(height, tag) {
/**
* 这个为实际渲染后 CSS 中 margin-buttom 的值本示例默认为20rpx
* 用于解决实际渲染后因为数据条数关系,高度差计算偏差的问题
* */
let marginBottom = uni.upx2px(20);
// console.log(`左高:${this.leftHeight},右高:${this.rightHeight},当前高:${height},插入方向:${tag}`)
if (tag == 'left') {
this.leftHeight += (height + marginBottom);
} else {
this.rightHeight += (height + marginBottom);
}
this.renderList();
},
// 组件点击事件
onClick(index, tag){
// 对应的数据
if(tag == 'left'){
this.$emit("click",this.leftList[index],index,tag);
}else{
this.$emit("click",this.rightList[index],index,tag);
}
},
// 渲染列表,这里实现瀑布流的左右分栏
renderList() {
// 待渲染长度为 0 时表示已渲染完成
if(this.awaitRenderList.length < 1){
this.showPage++;
this.$emit("done");
// 为防止 js 数值类型最大值溢出,当高度值大于 1亿时重置高度
if(this.leftHeight > 100000000){
if(this.leftHeight > this.rightHeight){
this.leftHeight = 2;
this.rightHeight = 1;
}else{
this.leftHeight = 1;
this.rightHeight = 2;
}
}
return;
}
let item = {
...this.awaitRenderList.splice(0,1)[0],
// 当前数据添加当前页面标识
_current_page:this.showPage,
// 当前数据添加一个渲染id解决 v-for 重复会出现不执行 load 的 BUG
_render_id:new Date().getTime()
};
if(this.leftHeight > this.rightHeight){
this.rightList.push(item);
}else{
this.leftList.push(item);
}
},
// 重置数据
resetData(){
this.leftHeight = 0;
this.rightHeight = 0;
this.leftList = [];
this.rightList = [];
this.awaitRenderList = [];
// 当前展示页码数据
this.showPage = 1;
},
// 启动渲染
startRender(){
if(!this.showList){
this.resetData();
return;
}
if(!this.$props.list || this.$props.list.length < 1){
console.log('河浪瀑布流插件提示:当前数据为空,不会触发列表渲染');
return;
}
// 若本次渲染为 重置 则先恢复组件的默认参数
if(this.$props.reset){
this.resetData();
}
this.awaitRenderList = [...this.$props.list];
this.renderList();
}
}
}
</script>
<style lang="scss" scoped>
.waterfall-box {
width: 100%;
>view {
width: 334rpx; margin-right: 18rpx;
&:last-child{ margin-right: 0; }
}
.list-item{
margin-bottom: 0;
// 设置透明,默认是可视的
opacity: 0;
// 默认超出隐藏,不影响加载中的文字显示效果
overflow: hidden;
height: 0;
&.show{
margin-bottom: 20rpx;
opacity: 1;
overflow: auto;
height: auto;
}
}
}
.h-flex-x {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: flex-start;
align-content: flex-start;
&.h-flex-2 {
>view {
width: 50%;
}
}
}
</style>