123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- <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(10);
-
- // 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 {
- padding: 20rpx 10rpx;
- box-sizing: border-box;
- >view {
- padding: 0 10rpx;
- }
-
- .list-item{
- margin-bottom: 0;
- // 设置透明,默认是可视的
- opacity: 0;
- box-shadow: 0px 4rpx 8rpx 0px rgba(0,0,0,0.04);
- // 默认超出隐藏,不影响加载中的文字显示效果
- 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>
|