フレックスを使用してウォーターフォール フローを実装する

序文

皆さんこんにちは、藤原とうふ店です 滝の流れを実感した記録記事を書こうと言いましたが、すっかり遅れてしまいました、午後時間のあるときに書きます。

カスケードとは何ですか

滝の流れ。滝の流れレイアウトとも呼ばれます。これは、比較的人気のある Web サイトのページ レイアウトであり、その視覚的なパフォーマンスは不均一な複数列レイアウトです。ページ スクロール バーが下にスクロールすると、このレイアウトはデータ ブロックを読み込み続け、現在の末尾に追加します。

特徴:

  • 幅は固定、高さは可変
  • むらのあるレイアウト

フレックスを使用してウォーターフォール フローを実装する

達成される効果は 2 つの列に分割されたウォーターフォール フローで、下にスライドすると次のページのデータが読み込まれ、ページ内に読み込まれます。

スタイルの実装

<view class="blessing-con">
  <view class='blessing-con-half'>
    <view id="leftHalf">
      <view class="blessing-con-half-item" :class="bgColor[index % 3]"
        v-for="(item, index) in newBlessingWordsList1" :key="index">
        <view class="item-con">
        </view>
      </view>
    </view>
  </view>
  <view class='blessing-con-half'>
    <view id="rightHalf">
      <view class="blessing-con-half-item" :class="bgColor[(index + 1) % 3]"
        v-for="(item, index) in newBlessingWordsList2" :key="index">
        <view class="item-con"></view>
      </view>
    </view>
  </view>
</view>
<view class="blessing-more" @click="handlerMore">
  <image v-if="hasWallNext" class="more-icon"
    src="xx/blessingGame/arr-down.png">
  </image>
  <view class="blessing-more-text">{{ blessingStatus }}</view>
</view>

.blessing-con は、外側のコンテナをフレックス レイアウトとして定義し、主軸の配置を space-between に設定します。

.blessing-con-half は、左側と右側のコンテナのスタイルを定義します。

.blessing-con-half-item は、各小さなボックスのスタイルを定義します。

.blessing-con {
  padding: 32rpx 20rpx;
  display: flex;
  justify-content: space-between;
  height: 1100rpx;
  overflow-y: auto;
  .blessing-con-half {
    width: 320rpx;
    height: 100%;
    box-sizing: border-box;
    .blessing-con-half-item {
      width: 100%;
      height: auto;
      display: flex;
      flex-direction: column;
      box-sizing: border-box;
      margin: 0 0 24rpx;
      position: relative;
    }
  }
}

ここでは、各小さなボックスの背景色は青、黄、赤の順であり、ギザギザの効果を実現するために疑似クラスを介してボックスの上部にギザギザの画像が追加されています。

bgColor: ['blueCol', 'yellowCol', 'pinkCol'], //祝福墙背景
// 不同颜色
.blessing-con-half-item {
    &.pinkCol {
      &::before {
        .setbg(320rpx, 16rpx, 'blessingGame/pink-bg.png');
      }
      .item-con {
        background: #FFE7DF;
      }
    }
  
    &.yellowCol {
      &::before {
        .setbg(320rpx, 16rpx, 'blessingGame/orange-bg.png');
      }
      .item-con {
        background: #fff0e0;
      }
    }
  
    &.blueCol {
      &::before {
        .setbg(320rpx, 16rpx, 'blessingGame/blue-bg.png');
      }
      .item-con {
        background: #e0f7ff;
      }
    }
  }
}

機能実現

data に 2 つの配列を定義して、左右のリストのデータを格納します

data(){
  return{
    blessingWordsList: [],// 祝福墙数据
    newBlessingWordsList: [],
    newBlessingWordsList1: [],//左列表
    newBlessingWordsList2: [],//右列表
    isloading:false,//是否正在加载
    hasWallNext:false,//是否有下一页
    leftHeight: 0,//左高度
    rightHeight: 0,//右高度
    blessingWordsCount: 0,//计数器
    isActive: 0, //tab初始化索引
    timer:null,//定时器
  }
}

コールインターフェースリクエストリストデータ

  • 最初のデータ要求では、リスト データとカウンターを初期化する必要があります。
  • リクエストごとにタイマーを開始する必要がある
// 获取祝福墙列表(type=1则请求下一页)
  async getBlessingWall(type = 0) {
    try {
      let res = await api.blessingWall({
        activityId: this.activityId,
        pageNum: this.pageWallNum,
        pageSize: this.pageWallSize
      })
      this.isloading = false
      if (res.code == 1 && res.rows) {
        let list = res.rows
        this.blessingWordsList = (type==0 ? list : [...this.blessingWordsList, ...list])
        if (this.blessingWordsList.length > 0 && !this.timer && this.isActive == 1) {
            if(this.pageWallNum == 1){
                    this.newBlessingWordsList = []
                    this.newBlessingWordsList1 = []
                    this.newBlessingWordsList2 = []
                    this.blessingWordsCount = 0
            }
            this.start()
        }
        // 处理请求下一页的情况
        if (type == 1) {
          this.start()
        }
        this.hasWallNext = res.hasNext
        if (!this.hasWallNext) {
          this.blessingStatus = "没有更多了哟"
        } else {
          this.blessingStatus = "点击加载更多"
        }
      }
    } catch (error) {
      console.log(error)
    }
  },
// 加载更多
 async handlerMore() {
  if (this.hasWallNext && !this.isloading) {
    this.isloading = true
    this.pageWallNum++
     await this.getBlessingWall(1)
  }
},

タイマーを開始して、左右のリストにデータを動的に追加します

start() {
  // 清除定时器
  clearInterval(this.timer)
  this.timer = null;
  
  this.timer = setInterval(() => {
    let len = this.blessingWordsList.length
    if (this.blessingWordsCount < len) {
      let isHave = false
      // 在列表中获取一个元素
      let item =this.blessingWordsList[this.blessingWordsCount]
      // 判断新列表中是否已经存在相同元素,防止重复添加
      this.newBlessingWordsList.forEach((tmp)=>{
        if(tmp.id == item.id){
          isHave = true
        }
      })
      // 如果不存在
      if (!isHave) {
        this.newBlessingWordsList.push(item)//添加该元素
        this.$nextTick(() => {
          this.getHei(item)//添加元素到左右列表
        })
      }
    } else {
      // 遍历完列表中的数据,则清除定时器
      clearInterval(this.timer)
      this.timer = null;
    }
  }, 10)
}

現在の左右のコンテナの高さを計算し、どちら側にデータを追加するかを決定します。

  • uni-app メソッドを使用して、左右のコンテナの dom オブジェクトを取得し、現在の高さを取得します。
  • 左右の高さを比較し、2 つの配列にデータを動的に挿入します。
  • データが挿入されるたびにカウンタが+1されます
getHei(item) {
  const query = uni.createSelectorQuery().in(this)
  // 左边
  query.select('#leftHalf').boundingClientRect(res => {
    if (res) {
      this.leftHeight = res.height
    }
    // 右边
    const query1 = uni.createSelectorQuery().in(this)
    query1.select('#rightHalf').boundingClientRect(dataRight => {
      if (dataRight) {
        this.rightHeight = dataRight.height != 0 ? dataRight.height : 0
        if (this.leftHeight == this.rightHeight || this.leftHeight < this.rightHeight) {
          // 相等 || 左边小  
          this.newBlessingWordsList1.push(item)
        } else {
          // 右边小
          this.newBlessingWordsList2.push(item)
        }
      }
      this.blessingWordsCount++
    }).exec()
  }).exec()
},

ここで注意すべき点があり、start メソッドを呼び出すときは、ページが左右のコンテナの要素をレンダリングすることを確認する必要があります。そうしないと、コンテナの高さを取得できません。

たとえば、私のプロジェクトにはタブ切り替えがあります

ページに入るときに一度データをリクエストしますが、このときタブの初期状態は0なのでstartメソッドは呼び出されません、タブが1に切り替わるとstartメソッドが呼び出されて計算が開始されます。高さ。

data(){
  return{
    isActive: 0, //tab初始化索引
    timer:null,//定时器
  }
}
async onLoad(options) {
  this.getBlessingWall()
}
// tab选项卡切换
tabClick(index) {
  this.isActive = index
  this.isLoaded = false;
  if (this.blessingWordsList.length > 0 && !this.timer && this.isActive == 1) {
    if(this.pageWallNum == 1){
      this.newBlessingWordsList = []
      this.newBlessingWordsList1 = []
      this.newBlessingWordsList2 = []
      this.blessingWordsCount = 0
    }
    this.start()
  }
},

やっと

今回は滝の流れを実現するために flex を選択しましたが、滝の流れを実現するには他にもいくつかの方法があります。後で機会があれば、他の方法もいくつか追加します。興味がある方は注目してください。

おすすめ

転載: juejin.im/post/7260713996165021754