prefacio
Hola a todos, esta es la tienda de Fujiwara Tofu, dije que escribiría un artículo para registrar la realización del flujo de la cascada, pero se ha retrasado hasta ahora, lo compensaré cuando tenga tiempo en la tarde.
que es cascada
Flujo de cascada, también conocido como diseño de flujo de cascada. Es un diseño de página de sitio web relativamente popular, y su rendimiento visual es un diseño desigual de varias columnas A medida que la barra de desplazamiento de la página se desplaza hacia abajo, este diseño continuará cargando bloques de datos y agregándolos a la cola actual.
Características:
- ancho fijo, altura variable
- diseño irregular
Use flex para implementar el flujo de cascada
El efecto logrado es un flujo de cascada dividido en dos columnas, y deslizando hacia abajo cargará los datos de la página siguiente y lo cargará en la página.
Implementación de estilo
<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 define el contenedor exterior como un diseño flexible y establece la alineación del eje principal en el espacio entre
.blessing-con-half define el estilo del contenedor en los lados izquierdo y derecho
.blessing-con-half-item define el estilo de cada caja pequeña
.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;
}
}
}
Aquí, el color de fondo de cada cuadro pequeño es del orden azul-amarillo-rojo, y se agrega una imagen irregular en la parte superior del cuadro a través de una pseudoclase para lograr un efecto irregular.
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;
}
}
}
}
realización de funciones
Defina dos matrices en datos para almacenar los datos de las listas izquierda y derecha
data(){
return{
blessingWordsList: [],// 祝福墙数据
newBlessingWordsList: [],
newBlessingWordsList1: [],//左列表
newBlessingWordsList2: [],//右列表
isloading:false,//是否正在加载
hasWallNext:false,//是否有下一页
leftHeight: 0,//左高度
rightHeight: 0,//右高度
blessingWordsCount: 0,//计数器
isActive: 0, //tab初始化索引
timer:null,//定时器
}
}
Datos de la lista de solicitudes de la interfaz de llamadas
- La primera solicitud de datos debe inicializar los datos de la lista y los contadores.
- El temporizador debe iniciarse después de cada solicitud.
// 获取祝福墙列表(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)
}
},
Inicie un temporizador para agregar dinámicamente datos a las listas izquierda y derecha
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)
}
Calcule la altura de los contenedores izquierdo y derecho actuales y determine de qué lado se deben agregar los datos
- Use el método uni-app para obtener los objetos dom de los contenedores izquierdo y derecho, y luego obtenga sus alturas actuales
- Compare las alturas izquierda y derecha e inserte dinámicamente datos en las dos matrices
- Cada vez que se inserta un dato, el contador +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()
},
Hay un punto a tener en cuenta aquí: al llamar al método de inicio, debe asegurarse de que la página represente los elementos de los contenedores izquierdo y derecho, de lo contrario no obtendrá la altura del contenedor.
Por ejemplo, mi proyecto tiene cambio de pestaña
Al ingresar a la página, los datos se solicitarán una vez. En este momento, debido a que el estado inicial de la pestaña es 0, no se llamará al método de inicio. Cuando la pestaña se cambia a 1, se llamará al método de inicio para comenzar a calcular la altura.
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()
}
},
por fin
Esta vez elegí flex para realizar el flujo de la cascada. Hay varias otras formas de realizar el flujo de la cascada. Si hay una posibilidad más tarde, agregaré varios otros métodos. Si está interesado, ¡puede prestar atención!