This commit is contained in:
hupeng
2023-10-11 11:27:47 +08:00
commit d0b337c596
659 changed files with 67106 additions and 0 deletions

View File

@ -0,0 +1,24 @@
## 1.0.82023-08-17
1. 修复只有一条数据切换时可能存在位置错误的BUG
## 1.0.72023-07-22
1. 避免快速切换报错的BUG
## 1.0.62023-07-17
1. 优化文档
2. 优化其他
## 1.0.52023-07-14
1. 优化changeList未处理数据时正确返回对应列的数据避免误导
## 1.0.42023-05-27
1. 修复在百度小程序中可能存在的BUG
2. 去掉原有的slot方式
## 1.0.32023-05-23
1. 修复在百度/头条小程序显示异常等BUG
2. 增加changeList回调函数处理数据
3. 更新示例
## 1.0.22023-05-16
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.12023-05-12
1. 增加clear回调函数
2. 增加remove回调函数
## 1.0.02023-05-10
uv-waterfall 瀑布流

View File

@ -0,0 +1,69 @@
export default {
props: {
// 瀑布流数据
// #ifdef VUE2
value: {
type: Array,
default: () => []
},
// #endif
// #ifdef VUE3
modelValue: {
type: Array,
default: () => []
},
// #endif
// 数据的id值根据id值对数据执行删除操作
// 如数据为:{id: 1, name: 'uv-ui'}那么该值设置为id
idKey: {
type: String,
default: 'id'
},
// 每次插入数据的事件间隔间隔越长能保证两列高度相近但是用户体验不好单位ms
addTime: {
type: Number,
default: 200
},
// 瀑布流的列数默认2最高为5
columnCount: {
type: [Number, String],
default: 2
},
// 列与列的间隙默认20
columnGap: {
type: [Number, String],
default: 20
},
// 左边和列表的间隙
leftGap: {
type: [Number, String],
default: 0
},
// 右边和列表的间隙
rightGap: {
type: [Number, String],
default: 0
},
// 是否显示滚动条仅nvue生效
showScrollbar: {
type: [Boolean],
default: false
},
// 列宽nvue生效
columnWidth: {
type: [Number, String],
default: 'auto'
},
// 瀑布流的宽度nvue生效
width: {
type: [Number, String],
default: ''
},
// 瀑布流的高度nvue生效
height: {
type: [Number, String],
default: ''
},
...uni.$uv?.props?.waterfall
}
}

View File

@ -0,0 +1,265 @@
<template>
<view class="uv-waterfall">
<!-- #ifndef APP-NVUE -->
<view class="uv-waterfall__gap_left" :style="[gapLeftStyle]"></view>
<template v-if="columnNum>=1">
<view id="uv-waterfall-1" class="uv-waterfall__column">
<slot name="list1"></slot>
</view>
</template>
<template v-if="columnNum>=2">
<view class="uv-waterfall__gap_center" :style="[gapCenterStyle]"></view>
<view id="uv-waterfall-2" class="uv-waterfall__column">
<slot name="list2"></slot>
</view>
</template>
<template v-if="columnNum>=3">
<view class="uv-waterfall__gap_center" :style="[gapCenterStyle]"></view>
<view id="uv-waterfall-3" class="uv-waterfall__column">
<slot name="list3"></slot>
</view>
</template>
<template v-if="columnNum>=4">
<view class="uv-waterfall__gap_center" :style="[gapCenterStyle]">
</view>
<view id="uv-waterfall-4" class="uv-waterfall__column">
<slot name="list4"></slot>
</view>
</template>
<template v-if="columnNum>=5">
<view class="uv-waterfall__gap_center" :style="[gapCenterStyle]">
</view>
<view id="uv-waterfall-5" class="uv-waterfall__column">
<slot name="list5"></slot>
</view>
</template>
<view class="uv-waterfall__gap_right" :style="[gapRightStyle]">
</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<view class="waterfall-warapper">
<waterfall :column-count="columnNum" :show-scrollbar="false" column-width="auto" :column-gap="columnGap" :left-gap="leftGap" :right-gap="rightGap" :always-scrollable-vertical="true" :style="[nvueWaterfallStyle]"
@loadmore="scrolltolower">
<slot></slot>
</waterfall>
</view>
<!-- #endif -->
</view>
</template>
<script>
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
import props from './props.js';
/**
* 瀑布流
* @description 该组件兼容所有端nvue参考https://uniapp.dcloud.net.cn/component/waterfall.html
* @tutorial https://www.uvui.cn/components/list.html
* @property {Array} value/modelValue 瀑布流数组数据非nvue生效 (默认 []
* @property {String} idKey 数据的id值根据id值对数据执行删除操作如数据为{id: 1, name: 'uv-ui'}那么该值设置为id非nvue有效 (默认 ''
* @property {String Number} addTime 每次插入数据的事件间隔间隔越长能保证两列高度相近但是用户体验不好单位ms非nvue生效默认 200
* @property {String Number} columnCount 瀑布流的列数(默认 2
* @property {String Number} columnGap 列与列的间隙(默认 0
* @property {String Number} leftGap 左边和列表的间隙(默认 0
* @property {String Number} rightGap 右边和列表的间隙(默认 0
* @property {Boolean} showScrollbar 控制是否出现滚动条仅nvue有效 (默认 false
* @property {String Number} columnWidth 描述瀑布流每一列的列宽nvue生效 (默认 auto
* @property {String Number} width 瀑布流的宽度nvue生效 (默认 屏幕宽
* @property {String Number} height 瀑布流的高度nvue生效 (默认 屏幕高
* @property {Object} customStyle 定义需要用到的外部样式
*
* @example <uv-waterfall v-model="list"></uv-waterfall>
*/
export default {
name: 'uv-waterfall',
mixins: [mpMixin, mixin, props],
data() {
return {
list1: [],
list2: [],
list3: [],
list4: [],
list5: [],
// 临时列表
tempList: []
}
},
computed: {
// 破坏value变量引用否则数据会保持不变
copyValue() {
// #ifdef VUE2
return this.$uv.deepClone(this.value)
// #endif
// #ifdef VUE3
return this.$uv.deepClone(this.modelValue)
// #endif
},
columnNum() {
return this.columnCount <= 0 ? 0 : this.columnCount >= 5 ? 5 : this.columnCount;
},
gapLeftStyle() {
const style = {}
style.width = this.$uv.addUnit(this.leftGap)
return style;
},
gapRightStyle() {
const style = {}
style.width = this.$uv.addUnit(this.rightGap)
return style;
},
gapCenterStyle() {
const style = {}
style.width = this.$uv.addUnit(this.columnGap)
return style;
},
nvueWaterfallStyle() {
const style = {};
if (this.width != 0) style.width = this.$uv.addUnit(this.width)
if (this.height != 0) style.height = this.$uv.addUnit(this.height)
// 如果没有定义列表高度,则默认使用屏幕高度
if (!style.width) style.width = this.$uv.addUnit(this.$uv.sys().windowWidth, 'px')
if (!style.height) style.height = this.$uv.addUnit(this.$uv.sys().windowHeight, 'px')
return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
}
},
watch: {
copyValue(nVal, oVal) {
// #ifndef APP-NVUE
if (nVal.length != 0) {
// 取出数组发生变化的部分
let startIndex = Array.isArray(oVal) && oVal.length > 0 ? oVal.length : 0
// 拼接原有数据
this.tempList = this.tempList.concat(this.$uv.deepClone(nVal.slice(startIndex)))
this.splitData()
}
// #endif
}
},
mounted() {
// #ifndef APP-NVUE
this.tempList = this.$uv.deepClone(this.copyValue)
this.splitData()
// #endif
},
methods: {
// 滚动到底部触发事件
scrolltolower(e) {
this.$uv.sleep(30).then(() => {
this.$emit('scrolltolower')
})
},
// 拆分数据
async splitData() {
let rectArr = [];
let emitList = {};
if (!this.tempList.length) return
for (let i = 1; i <= this.columnNum; i++) {
const rect = await this.$uvGetRect(`#uv-waterfall-${i}`);
rectArr.push({ ...rect, name: i });
}
let item = this.tempList[0]
// 因为经过上面两个await节点查询和定时器数组有可能会变成空[]导致item的值为undefined
// 解决多次快速滚动会导致数据乱的问题
if (!item) return
const minCol = this.getMin(rectArr);
// 列宽可能使用的到
item.width = minCol.width;
this[`list${minCol.name}`].push(item);
emitList.name = `list${minCol.name}`;
emitList.value = item;
this.$emit('changeList', emitList);
// 移除临时数组中已处理的数据
this.tempList.splice(0, 1)
// 如果还有数据则继续执行
if (this.tempList.length) {
let _timeout = this.addTime;
// 部分平台在延时较短的情况会出现BUG
// #ifdef MP-BAIDU
_timeout = _timeout < 200 ? 200 : _timeout;
// #endif
await this.$uv.sleep(_timeout);
this.splitData()
} else {
this.$emit('finish')
}
},
getMin(arr) {
let result = null;
const filter = arr.filter(item => item.height == 0);
if (!filter.length) {
const min = Math.min.apply(Math, arr.map(item => {
return item.height;
}))
const [item] = arr.filter(item => item.height == min);
result = item;
} else {
let newArr = [];
arr.map((item, index) => {
newArr.push({ len: this[`list${index+1}`].length, item: item });
});
const minLen = Math.min.apply(Math, newArr.map(item => {
return item.len;
}))
try {
const { item } = newArr.find(item => item.len == minLen && item.item.height == 0);
result = item;
} catch (e) {
const { item } = newArr.find(item => item.item.height == 0);
result = item;
}
}
return result;
},
// 清空数据列表
async clear() {
// 清除数据
for (let i = 0; i < this.columnCount; i++) {
this[`list${i+1}`] = [];
}
// #ifdef VUE2
this.$emit('input', [])
// #endif
// #ifdef VUE3
this.$emit('update:modelValue', [])
// #endif
this.tempList = []
await this.$uv.sleep(300);
this.$emit('clear');
},
// 清除指定的某一条数据根据id来实现
remove(id) {
let index = -1
// 删除组件数据
for (let i = 1; i <= this.columnCount; i++) {
index = this[`list${i}`].findIndex(item => item[this.idKey] == id)
if (index != -1) {
this[`list${i}`].splice(index, 1)
}
}
// 同时删除父组件对应的数据
// #ifdef VUE2
index = this.value.findIndex(item => item[this.idKey] == id)
if (index != -1) this.$emit('input', this.value.splice(index, 1))
// #endif
// #ifdef VUE3
index = this.modelValue.findIndex(item => item[this.idKey] == id)
if (index != -1) this.$emit('update:modelValue', this.modelValue.splice(index, 1))
// #endif
this.$emit('remove', id);
}
}
}
</script>
<style lang="scss" scoped>
@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
.uv-waterfall {
@include flex(row);
align-items: flex-start;
&__column {
@include flex(column);
flex: 1;
// #ifndef APP-NVUE
height: auto;
// #endif
}
}
</style>

View File

@ -0,0 +1,89 @@
{
"id": "uv-waterfall",
"displayName": "uv-waterfall 瀑布流 全面兼容vue3+2、app、h5、小程序等多端",
"version": "1.0.8",
"description": "该组件主要用于瀑布流式布局显示视觉表现为参差不齐的多栏布局随着页面滚动条向下滚动这种布局还会不断加载数据块并附加至当前尾部同时集成nvue的原生瀑布流。",
"keywords": [
"uv-waterfall",
"uvui",
"uv-ui",
"waterfall",
"瀑布流"
],
"repository": "",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "插件不采集任何数据",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [
"uv-ui-tools",
"uv-image",
"uv-loading-icon"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "y"
},
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y",
"钉钉": "u",
"快手": "u",
"飞书": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}

View File

@ -0,0 +1,19 @@
## Waterfall 瀑布流
> **组件名uv-waterfall**
该组件主要用于瀑布流式布局显示,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部,同时集成`nvue`的原生瀑布流用于`app-nvue`。常用于一些电商商品展示等如某宝首页、x红书等。
研究uniapp瀑布流多年**该方式是目前小程序端最佳方案**,灵活配置,简单易用,开箱即用。
该插件请根据文档耐心查看,`vue`的写法稍微麻烦点,但是效果是很好的,比之前上线的两个版本的瀑布流适用,更有扩展性,我自己的上线项目也是用的此插件。
# <a href="https://www.uvui.cn/components/waterfall.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui)
### [更多插件请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
#### 如使用过程中有任何问题反馈或者您对uv-ui有一些好的建议欢迎加入uv-ui官方交流群<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>