#弹性布局#(附源码) justify-content:space-between 强制换行,最后一行左对齐

本文详细介绍了如何利用弹性布局(Flexbox)实现一行显示三个子元素,并在父元素宽度有限时自动换行。通过设置`justify-content: space-between`实现两端对齐,同时在最后一行保持左对齐。此外,利用伪元素解决了最后一行中间留白的问题,确保子元素布局的美观和合理性。示例代码中展示了具体的CSS样式和Vue.js的模板结构,适用于前端开发中的布局设计。
部署运行你感兴趣的模型镜像

#弹性布局# justify-content:space-between 最后一行左对齐

一、需求:

一行3个子盒子、

父盒子左右有边距、

会自动换行、

下一行的子盒子左对齐

二、知识点:

弹性布局、

v-for循环渲染、

magin、

盒子居中对齐、

伪元素占位

三、源码示例如下:

<template>
<view>
	<view class="choose" >
		<view class="photo" v-for="(item,index) in imgArr">
                <image :src="item" ></image>
        </view>
	</view>
</view>
</template>

<script>
	export default {
		data() {
				return {	
					imgArr:
                    ["https://pic2.zhimg.w.jpg?source=1940ef5c",
                    "https://pic2.zhimg.w.jpg?source=1940ef5c",
                    "https://pic2.zhimg.w.jpg?source=1940ef5c",
                    "https://pic2.zhimg.w.jpg?source=1940ef5c",
                    "https://pic2.zhimg.w.jpg?source=1940ef5c",]

				}
			},
			methods: {
		
				}
				
			},
		
</script>

<style scoped lang="scss">
        //父盒子
	.choose {
		width: 95%; //不要写死宽度
		display: flex; //使用弹性布局
		flex-wrap: wrap; //强制换行
		justify-content: space-between;  //子盒子排列两端对齐
		margin: 20rpx auto; //居中对齐,距离顶部有20rpx
		text-decoration: none; //取消下划线
        //子盒子
		.photo {
			width: 32%; //设置每一个子盒子的宽度,不要写死宽度
			height: 220rpx;//设置每一个子盒子的高度
			margin-bottom: 20rpx; //设置每个子盒子距离底部有20rpx
			background-color: #2979FF;
			image {
				width: 100%;//子盒子里面的图片高度
				height: 220rpx;//子盒子里面的图片宽度
			}
		}
	}
    //父盒子的最后一个盒子
    //解决末尾中间留白,使其靠左分布的方法:给父容器使用伪元素占位
	.choose:after{  // 使用伪类元素占据单位,不影响页面
	            content: "";
	            height: 0;
	            width: 32%;
	        }
			
</style>

四、效果:

 

 

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

<template> <view class="container"> <!-- 轮播图区域 --> <view class="swiper_area"> <SCSwiper :images="bannerImages"></SCSwiper> </view> <!-- 诉求分类 --> <view class="category_area"> <view v-if="loadingCategories" class="loading">加载分类中...</view> <uni-segmented-control v-else :values="categoryNames" @clickItem="changeCategory" styleType="text" :current="currentCategoryIndex"></uni-segmented-control> </view> <!-- 诉求列表 --> <view class="appeal_list"> <view v-if="loadingAppeals" class="loading">加载诉求中...</view> <view v-else> <uni-list> <uni-list-item v-for="item in currentAppeals" :key="item.id" :title="item.title" :note="`${item.appealCategoryName || &#39;未分类&#39;} | ${item.stateText}`" :thumb="item.imgUrl ? (ip + item.imgUrl) : &#39;&#39;" thumb-size="lg" :right-text="item.stateText" @click="viewAppealDetail(item.id)"> <template v-slot:footer> <view class="list-footer"> <text class="time">{{ formatDate(item.createTime) }}</text> </view> </template> </uni-list-item> </uni-list> <!-- 无数据提示 --> <view v-if="currentAppeals.length === 0" class="no_data"> 暂无诉求数据 </view> </view> </view> <!-- 底部操作按钮 - 关键修复 --> <view class="nav_actions"> <button class="create_btn" @click="createAppeal">创建诉求</button> <button class="my_btn" @click="viewMyAppeals">我的诉求</button> </view> </view> </template> <script setup> import { ref, onMounted } from &#39;vue&#39; import { ip, getHttp } from &#39;../../utils/http.js&#39; // 轮播图数据 const bannerImages = ref([]) // 诉求分类数据 const appealCategories = ref([]) const categoryNames = ref([]) const currentCategoryIndex = ref(0) // 当前显示的诉求列表 const currentAppeals = ref([]) // 加载状态 const loadingCategories = ref(true) const loadingAppeals = ref(true) // 状态码转文本函数 const getStateText = (state) => { const stateMap = { &#39;0&#39;: &#39;待处理&#39;, &#39;1&#39;: &#39;处理中&#39;, &#39;2&#39;: &#39;已解决&#39;, &#39;3&#39;: &#39;已关闭&#39; } return stateMap[state] || &#39;未知状态&#39; } // 格式化日期 const formatDate = (timestamp) => { if (!timestamp) return &#39;&#39;; const date = new Date(timestamp); return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, &#39;0&#39;)}-${date.getDate().toString().padStart(2, &#39;0&#39;)}`; } // 获取广告轮播图 async function getBanners() { try { const res = await getHttp({ url: &#39;/prod-api/api/gov-service-hotline/ad-banner/list&#39; }) // 统一处理响应结构 const data = res.data?.code === 200 ? res.data.data : res.code === 200 ? res.data : []; if (Array.isArray(data)) { bannerImages.value = data.map(item => ip + item.imgUrl) } } catch (error) { console.error(&#39;获取轮播图失败:&#39;, error) } } // 获取诉求分类 async function getAppealCategories() { try { loadingCategories.value = true const res = await getHttp({ url: &#39;/prod-api/api/gov-service-hotline/appeal-category/list&#39; }) // 统一处理响应结构 const data = res.data?.code === 200 ? (res.data.rows || res.data.data) : res.code === 200 ? (res.rows || res.data) : []; if (Array.isArray(data)) { appealCategories.value = data categoryNames.value = data.map(item => item.name) // 默认加载第一个分类的诉求 if (data.length > 0) { getAppealsByCategory(data[0].id) } } } catch (error) { console.error(&#39;获取诉求分类失败:&#39;, error) uni.showToast({ title: &#39;获取分类失败&#39;, icon: &#39;none&#39; }) } finally { loadingCategories.value = false } } // 根据分类获取诉求 async function getAppealsByCategory(categoryId) { try { loadingAppeals.value = true const res = await getHttp({ url: &#39;/prod-api/api/gov-service-hotline/appeal/list&#39;, data: { appealCategoryId: categoryId, pageNum: 1, pageSize: 10 } }) // 统一处理响应结构 const data = res.data?.code === 200 ? (res.data.rows || res.data.data) : res.code === 200 ? (res.rows || res.data) : []; if (Array.isArray(data)) { currentAppeals.value = data.map(item => ({ ...item, stateText: getStateText(item.state) })) } } catch (error) { console.error(&#39;获取诉求列表失败:&#39;, error) uni.showToast({ title: &#39;获取诉求列表失败&#39;, icon: &#39;none&#39; }) } finally { loadingAppeals.value = false } } // 分类切换处理 - 修复事件处理 function changeCategory(e) { const index = e.currentIndex; if (index >= 0 && index < appealCategories.value.length) { currentCategoryIndex.value = index const category = appealCategories.value[index] getAppealsByCategory(category.id) } } // 查看诉求详情 function viewAppealDetail(id) { uni.navigateTo({ url: `/pages/index/AppealDetail?id=${id}` }) } // 创建诉求 function createAppeal() { uni.navigateTo({ url: &#39;/pages/index/CreateAppeal&#39; }) } // 查看我的诉求 function viewMyAppeals() { uni.navigateTo({ url: &#39;/pages/index/MyAppeals&#39; }) } onMounted(() => { getBanners() getAppealCategories() }) </script> <style lang="scss" scoped> .container { padding: 20rpx; background-color: #f5f5f5; .loading { padding: 30rpx; text-align: center; color: #888; font-size: 28rpx; } .swiper_area { height: 350rpx; margin-bottom: 30rpx; border-radius: 15rpx; overflow: hidden; box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1); } .category_area { margin-bottom: 30rpx; background: #fff; border-radius: 15rpx; padding: 20rpx 10rpx; min-height: 80rpx; box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05); } .appeal_list { margin-bottom: 120rpx; :deep(.uni-list-item__container) { padding: 24rpx 30rpx; } :deep(.uni-list-item__content-title) { font-size: 32rpx; font-weight: bold; margin-bottom: 10rpx; } :deep(.uni-list-item__content-note) { color: #666; font-size: 26rpx; margin-top: 8rpx; } :deep(.uni-list-item__extra-text) { font-size: 26rpx; color: #007AFF; } .list-footer { margin-top: 10rpx; .time { font-size: 24rpx; color: #999; } } .no_data { text-align: center; padding: 80rpx 40rpx; color: #999; font-size: 30rpx; background: #fff; border-radius: 15rpx; } } /* 固定在导航栏上方的按钮 */ .nav_actions { bottom: 0; left: 0; right: 0; display: flex; flex-direction: row; /* 明确设置为行布局 */ align-items: center; justify-content: space-between; /* 使用空间分布对齐 */ padding: 15rpx 30rpx; background: #fff; border-top: 1rpx solid #e0e0e0; border-radius: 10rpx; box-shadow: 0 -4rpx 12rpx rgba(0, 0, 0, 0.05); /* 安全区域适配 */ padding-bottom: calc(15rpx + constant(safe-area-inset-bottom)); padding-bottom: calc(15rpx + env(safe-area-inset-bottom)); z-index: 1000; box-sizing: border-box; /* 确保内边距包含在宽度内 */ /* 安全区域占位 */ &::after { content: &#39;&#39;; position: absolute; bottom: 0; left: 0; right: 0; height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom); background: #fff; } button { flex: 1; /* 等分空间 */ min-width: 0; /* 允许内容收缩 */ margin: 0 15rpx; /* 左右间距 */ font-size: 30rpx; height: 80rpx; line-height: 80rpx; border-radius: 50rpx; position: relative; z-index: 2; box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1); transition: all 0.2s; display: flex; /* 内部使用flex */ align-items: center; /* 垂直居中 */ justify-content: center; /* 水平居中 */ /* 安全区域适配 */ margin-bottom: constant(safe-area-inset-bottom); margin-bottom: env(safe-area-inset-bottom); overflow: hidden; /* 防止内容溢出 */ /* 创建诉求按钮 - 蓝色风格 */ &.create_btn { background: #007AFF; /* 纯蓝色背景 */ color: white; border: none; /* 点击效果 */ &:active { background: #0062cc; transform: scale(0.98); box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.1); } } /* 我的诉求按钮 - 白色风格 */ &.my_btn { background: #ffffff; color: #333; border: 1rpx solid #e0e0e0; /* 点击效果 */ &:active { background: #f8f8f8; transform: scale(0.98); box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.1); } } } } } </style> 把 诉求分类栏 改成文字横向显示
最新发布
06-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值