先上效果图!
这个页面展示的原理是什么嘞?
其实就是将屏幕分为左右两大块,
然后判断左右两边加载的块块高度,
左边高了就加到右边的list,右边高了就加到左边的list(主打一个水多加面,面多加水),
这样就可以很灵活而且很平均啦!下面是js部分(这个双列瀑布流的精华计算部分,html的话,其实就是分别加载leftList跟rightList啦,全部代码会放在最下方)
<script>
let query, leftHeight = 0 , rightHeight = 0;
export default {
data() {
return {
totalList:[], // 所有数据
leftList: [], // 左边数据
rightList: [], // 右边数据
}
},
mounted() {
this.getDataDom()
},
methods: {
async getDataDom() {
let data = this.$data;
query = uni.createSelectorQuery().in(this);
for (let item in data.totalList) {
// 判断两边的高度 看往什么list加
leftHeight <= rightHeight ? data.leftList.push(data.totalList[item]) : data.rightList.push(data.totalList[item]);
//加完计算左右的高度,好进行下一轮比较
await this.getBoxHeight(data.leftList, data.rightList);
}
},
getBoxHeight(leftList, rightList) {
return new Promise((resolve, reject) => {
this.$data.leftList = leftList
this.$data.rightList = rightList
query.select('#dis_left').boundingClientRect();
query.select('#dis_right').boundingClientRect();
// 处理异步问题,没有数据
setTimeout(() => {
query.exec((res) => {
leftHeight = res[0].height; //获取左边列表的高度
rightHeight = res[1].height; //获取右边列表的高度
resolve();
});
})
})
}
}
}
</script>
OK!解决完这个页面最精华的问题,就可以调整一些细节,
例如每一卡片的高度,我设定的是文字类型就固定高度,图片类型就根据图片的高度来布置卡片,这样可以有些变化,不至于太死板,因此在我的html部分,又用了v-if来判断这么一张卡片是属于图片类型,还是文字类型的
还有个不太容易注意到的小细节就是,固定高度的话,假如文字特别长怎么办呢,一开始,我没有写overflow:hidden,文字直接飞出屏幕了,加上的话 我发现他不是从第一行开始显示的,因为我设置的是水平垂直居中,ok,前端水平欠缺的我直接是一个大求助gpt,嘿嘿嘿,真好用啊,学习利器
终于解决了展示的一些小小细节,在哪里发布图片其实也有很多选择,一开始,我是准备把
截图里"阿钙的留言板"换成发布文章的,有个问题就是,如果用户翻到很下边的地方,想发布文章,还得回到顶部,那不会很糟心吗,于是我否决了这个美丽的小想法,灵光一闪,想起小米的备忘录,觉得右下角加一个固定按钮设计还蛮不错的,因此使用了这个方案,css中fixed类型就能固定,ohhh!(一些页面设计的小小思路)
下面代码的页面分布模块,微微讲解一下,有时候看csdn上的有些文章会迷迷糊糊的(暖心)
html就分为,左边列表跟右边列表,然后每一边的view模块中又遍历leftList或者rightList(他们的区分就是在js中事先计算左右高度) 遍历的时候发现,欸有图片类型的信息,有文字类型的信息,分别塞入不同css的卡片中(文字卡片固定一个高度 图片卡片根据图片高度来) 卡片的下半部分,就是固定高度的用户跟用户名,右下角有个发布新留言按钮,没了没了,就是这样简单!
基本上这个页面的静态内容就是这样了,下面放所有代码!还没写后端,这个代码也是没有后端部分的,放心大胆的看!放心大胆的复制粘贴!放心大胆的点赞收藏!把图片url的部分替换,应该就可以直接在页面上看到效果啦!如果觉得有帮助的话可以给我点一个赞,我会很开心的,嘻嘻
<template>
<view class="dislocat_content">
<view id="dis_left" class="dislocat_content_left">
<view class="border-outside" >
<view class="top-card">
<view class="centered-text2">阿钙的<br/>留言板</view>
</view>
</view>
<view class="border-outside" v-for="(item,index) in leftList" >
<!-- 文字类型信息 -->
<view class="card" v-if="item.infoType=='0'">
<view class="top-section" >
<text class="centered-text">{{item.context}}</text>
</view>
<view class="bottom-section">
<view class="avatar-wrapper">
<image class="avatar" :src="item.src" mode="aspectFill"></image>
</view>
<view class="name-wrapper">
<text class="name">{{item.userName}}</text>
</view>
</view>
</view>
<view class="card1" v-if="item.infoType=='1'" >
<!-- 图片类型信息 -->
<view class="top-section1" >
<image class="img_icon" :src="item.photoUrl" mode="widthFix"></image>
</view>
<view class="bottom-section">
<view class="avatar-wrapper">
<image class="avatar" :src="item.src" mode="aspectFill"></image>
</view>
<view class="name-wrapper">
<text class="name">{{item.userName}}</text>
</view>
</view>
</view>
</view>
</view>
<view id="dis_right" class="dislocat_content_right">
<view class="border-outside" v-for="(item,index) in rightList" >
<!-- 文字类型信息 -->
<view class="card" v-if="item.infoType=='0'">
<view class="top-section" >
<text class="centered-text">{{item.context}}</text>
</view>
<view class="bottom-section">
<view class="avatar-wrapper">
<image class="avatar" :src="item.src" mode="aspectFill"></image>
</view>
<view class="name-wrapper">
<text class="name">{{item.userName}}</text>
</view>
</view>
</view>
<view class="card1" v-if="item.infoType=='1'" >
<!-- 图片类型信息 -->
<view class="top-section1" >
<image class="img_icon" :src="item.photoUrl" mode="widthFix"></image>
</view>
<view class="bottom-section">
<view class="avatar-wrapper">
<image class="avatar" :src="item.src" mode="aspectFill"></image>
</view>
<view class="name-wrapper">
<text class="name">{{item.userName}}</text>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 固定在右下角的圆形按钮 -->
<view class="fixed-button">
<view class="circle">
+
</view>
</view>
</template>
<script>
let query, leftHeight = 0 , rightHeight = 0;
export default {
data() {
return {
totalList: [
{src:"https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0",
infoType:"0",
context:"这是第一条信息",
userName:"阿钙"
},
{src:"https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0",
infoType:"0",
context:"我喜欢吃椰子",
userName:"coconutwy"
},
{src:"https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0",
infoType:"0",
context:"我爱打篮球",
userName:"小蔡"
},
{src:"https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0",
infoType:"1",
photoUrl:"../../static/hxd.jpg",
userName:"阿钙"
},
{src:"https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0",
infoType:"0",
context:"我笑死了,一个个都怕卷到自己,都劝退java,实际呢?还不是机械5k是东山再起,计算机20w尽显颓势。我小学毕业就出来打工四处碰壁,直到我碰见了余胜军,参加了java培训,毫不夸张,只要你好好学,出去两万是保底的事,都说java学的多,实际呢?也不过就spring,微服务,并发那些罢了,一个月学俩门,一个半月就能拿下,以后java必是蓝海专业,国家大力发展数字经济,所谓大佬也不过就是顺应局势罢了,当你们还在讨论今年java已死的时候,我已经拿到5个offer了,差距就是这样打开的",
userName:"Java之父"
},
{src:"https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0",
infoType:"0",
context:"我爱吃钙片",
userName:"阿钙"
},{src:"https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0",
infoType:"1",
photoUrl:"../../static/hxd.jpg",
userName:"阿钙"
},
{src:"https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0",
infoType:"1",
photoUrl:"../../static/hxd.jpg",
userName:"阿钙"
},
], // 所有数据
leftList: [], // 左边数据
rightList: [], // 右边数据
}
},
mounted() {
this.getDataDom()
},
methods: {
async getDataDom() {
let data = this.$data;
query = uni.createSelectorQuery().in(this);
for (let item in data.totalList) {
// 判断两边的高度
leftHeight <= rightHeight ? data.leftList.push(data.totalList[item]) : data.rightList.push(data.totalList[item]);
await this.getBoxHeight(data.leftList, data.rightList);
}
},
getBoxHeight(leftList, rightList) {
return new Promise((resolve, reject) => {
this.$data.leftList = leftList
this.$data.rightList = rightList
query.select('#dis_left').boundingClientRect();
query.select('#dis_right').boundingClientRect();
// 处理异步问题,没有数据
setTimeout(() => {
query.exec((res) => {
leftHeight = res[0].height; //获取左边列表的高度
rightHeight = res[1].height; //获取右边列表的高度
resolve();
});
})
})
}
}
}
</script>
<style lang="scss" scoped>
.dislocat_content{
width: 100%;
position: relative;
overflow: hidden;
box-sizing: border-box;
&_left, &_right{
width: 48.2%;
float: left;
border-radius: 10rpx;
}
&_left{
margin-left: 1.2%;
margin-right: 0.6%;
}
&_right{
margin-right: 1.2%;
margin-left: 0.6%;
}
.border-outside{
margin-top: 14rpx;
.img_icon{
width: 100%;
display: block;
border-radius: 10rpx;
}
}
}
.card {
width: 100%;
height: 550rpx;
background-color: white;
border: 1px solid #ff557f;
border-radius: 20rpx; /* 整体卡片的圆角 */
box-shadow: 2rpx 6rpx 8rpx rgba(0, 0, 0, 0.1); /* 卡片的阴影 */
padding:0 20rpx; /* 卡片内部的内边距 */
box-sizing: border-box; /* 使padding不影响卡片的总宽度 */
}
.card1 {
width: 100%;
min-height: 0; /* 添加最小高度限制 */
background-color: white;
border: 1px solid #ff557f;
border-radius: 20rpx; /* 整体卡片的圆角 */
box-shadow: 2rpx 6rpx 8rpx rgba(0, 0, 0, 0.1); /* 卡片的阴影 */
padding: 20rpx; /* 卡片内部的内边距 */
box-sizing: border-box; /* 使padding不影响卡片的总宽度 */
}
.top-card{
width: 100%;
height: 300rpx;
background-color: white;
border: 3px solid #ff557f;
border-radius: 20rpx; /* 整体卡片的圆角 */
box-shadow: 2rpx 6rpx 8rpx rgba(0, 0, 0, 0.1); /* 卡片的阴影 */
padding: 20rpx; /* 卡片内部的内边距 */
box-sizing: border-box; /* 使padding不影响卡片的总宽度 */
display: flex;
justify-content: center;
align-items: center;
background-color:rgba(255, 182, 193, 0.3);
}
.top-section {
height: 390rpx; /* 上部分高度占比 */
padding: 20rpx 0;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}
.top-section1 {
margin-bottom: 20rpx;
flex: 1; /* 占据剩余空间 */
display: flex;
justify-content: center;
align-items: center;
}
.centered-text {
font-size: 30rpx;
color: #333;
display: -webkit-box; /* 使用flexbox布局 */
-webkit-box-orient: vertical; /* 垂直方向 */
-webkit-line-clamp: 10; /* 最多显示两行 */
overflow: hidden; /* 超出部分隐藏 */
}
.centered-text2 {
font-size: 80rpx;
color: #ffffff;
text-shadow:
-1px -1px 0 #000,
1px -1px 0 #000,
-1px 1px 0 #000,
1px 1px 0 #000; /* 设置文字描边 */
}
.bottom-section {
height: 100rpx; /* 下部分高度占比 */
display: flex;
align-items: center;
background-color: rgba(255, 182, 193, 0.3); /* 圆角透明的灰粉色背景 */
border-radius: 20rpx; /* 下部分背景的圆角 */
padding: 0 20rpx; /* 下部分的左右内边距 */
box-sizing: border-box; /* 使padding不影响元素的总宽度 */
}
.avatar-wrapper {
flex: 0 0 auto; /* 固定大小,不缩放 */
width: 50rpx;
height: 50rpx;
margin-right: 20rpx; /* 右边的间距 */
border-radius: 50%; /* 头像框的圆形 */
overflow: hidden;
}
.avatar {
width: 100%;
height: 100%;
}
.name-wrapper {
flex: 1; /* 占据剩余空间 */
display: flex;
align-items: center;
}
.name {
font-size: 28rpx;
color: #333;
}
.fixed-button {
position: fixed; /* 固定定位,始终在视窗右下角 */
right: 50rpx; /* 距离视窗右侧的距离 */
bottom: 50rpx; /* 距离视窗底部的距离 */
z-index: 1000; /* 确保按钮在其他内容之上 */
width: 120rpx; /* 圆形按钮的直径 */
height: 120rpx; /* 圆形按钮的直径 */
background-color: #ff557f; /* 圆形按钮的背景色 */
border-radius: 50%; /* 让正方形变成圆形 */
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.1); /* 添加阴影效果 */
/* 圆形按钮样式 */
.circle {
font-size: 60rpx; /* 加号的字体大小 */
font-weight: bold;
color: white; /* 加号的颜色 */
}
}
</style>
之后会做发布留言的页面,包括这个卡片点开的样子,不想跟小红书做的一模一样,可能点开会是一个弹出层的设计,然后能够像朋友圈一样被评论(纯纯自娱自乐的功能哈哈哈哈哈哈),具体的还得构想构想!接下来想引入一些动画什么的,看看能不能做出一些有趣的效果吧