TNBLOG
首页
博客
视频
资源
问答
猿趣
手机
关于
搜索
收藏
便签
笔记
消息
创作
登录
剑轩
应无所住,而生其心
博主信息
排名
6
文章
6
粉丝
16
评论
8
文章类别
CSS
16篇
微服务
41篇
Git
15篇
.NET
104篇
移动开发
33篇
软件架构
23篇
.NET Core
119篇
.NET MVC
11篇
英语
3篇
随笔
90篇
Bootstrap
3篇
Redis
21篇
编辑器
10篇
Js相关
15篇
虚拟化
8篇
更多
Oracle
7篇
Python
14篇
数据库
26篇
EF
17篇
微信
3篇
前端
160篇
消息队列
6篇
docker
41篇
多线程
1篇
Java
4篇
软件基础
2篇
C++
2篇
WCF
7篇
Linux
7篇
nginx
5篇
K8S
9篇
ABP
2篇
最新文章
最新评价
{{item.articleTitle}}
{{item.blogName}}
:
{{item.content}}
关于我们
ICP备案 :
渝ICP备18016597号-1
网站信息:
2018-2024
TNBLOG.NET
技术交流:
群号656732739
联系我们:
contact@tnblog.net
欢迎加群
欢迎加群交流技术
原
uni-app app,小程序 时间轴样式,时间轴效果。弹窗里边使用时间轴。悬浮菜单
576
人阅读
2024/5/31 17:21
总访问:
4428704
评论:
0
收藏:
0
手机
分类:
前端
tn2>虽然可以用一些时间轴组件比如,timeline,但是有时候还是自己写点样式定制性好一点,不需要像组件那么通用。 [TOC] ### 时间轴效果一 #### 效果图 ![](https://img.tnblog.net/arcimg/aojiancc2/79d1cf2a8d824ac59a88db5245e2d842.jpg) #### 具体的代码和样式 ``` <template> <view class="teaching-dynamics-container"> <view class="tdc-course-info"> <view class="tdc-grade">优</view> <view class="tdc-coursename">《MySQL数据库设计与实现(第二版)》</view> </view> <view class="tdc-class-schedule"> <view class="tdc-classinfo"> <view class="tcs-classtag">班级:</view> <view class="tsc-classname">22级移动互联应用技术1班</view> </view> <view class="tdc-cs-schedule"> <view class="tcs-cs-scheduletag">进度:</view> <view class="tsc-cs-schedulename">第3章 MySQL存储引擎和数据类型</view> </view> <view class="tdc-line"></view> <view class="tdc-cs-completeinfo"> <view class="tdc-csc-warp"> <view>应完成:</view> <view>60%</view> </view> <view class="tdc-csc-warp tdc-csc-warp-right"> <view>完成:</view> <view>59%</view> </view> </view> </view> <view class="system-study-situation" style="margin-top: 35rpx"> <view class="timeline-list"> <block v-for="(item, index) in 3" :key="index"> <view class="timeline-item"> <view class="timeline-item_tail"></view> <view class="timeline-item_node"> <view class="timeline-item-innode"></view> </view> <view class="timeline-item_wrapper"> <view class="sss-title-complete"> <view class="sss-title"> <view>评估系统</view> <!-- <view class="sss-grade grade-excellent">优</view> --> <view class="sss-grade grade-excellent" :class="state.gradeStyle[index]">{{ state.gradeDesc[index] }}</view> </view> <view class="sss-complete-info"> <view>完成80%</view> <view>应完成70%</view> </view> </view> <view class="sss-chapter-study-situation" v-for="(initem, inindex) in 2" :key="inindex"> <view class="sss-css-item"> <view class="sss-ci-title">第1章MySQL数据库基础</view> <view class="sss-ci-situation">未开始</view> </view> </view> </view> </view> </block> </view> </view> </view> </template> <script setup lang="ts" name="tasks"> import { defineAsyncComponent, reactive, onMounted, toRefs, ref } from 'vue'; const state = reactive({ title: '更新', schoolID: null, // 优,良,差样式 gradeStyle: { 0: "grade-excellent", 1: "grade-good", 2: "grade-bad", }, // 优,良,差描述 gradeDesc: { 0: "优", 1: "良", 2: "差", } }) onMounted(() => { }) </script> <!-- 时间轴的样式 --> <style lang="scss" scoped> .timeline-list { margin: 10rpx 0px 10px 5px; margin-top: 62rpx; font-size: 28rpx; list-style: none; } .timeline-item:last-child .timeline-item_tail { display: none; } .timeline-item { position: relative; padding-bottom: 20rpx; } .timeline-item_tail { position: absolute; left: 4rpx; height: 100%; border-left: 2rpx solid rgba(109, 209, 201, 0.3); // 时间轴左边的线修改为虚线 border-left-style: dashed; } .timeline-item_node { position: absolute; background-color: #FFFFFF; border-radius: 50%; display: flex; justify-content: center; align-items: center; left: -8rpx; width: 22rpx; height: 22rpx; background: #fff; border: 2rpx solid #6DD1C9; .timeline-item-innode { width: 14rpx; height: 14rpx; background: #6DD1C9; border-radius: 50%; } } .timeline-item_wrapper { position: relative; padding: 26rpx 0rpx 0rpx 0rpx; margin-left: 39rpx; top: -34rpx; background-color: #ffffff; border-radius: 20rpx; // width: 600rpx; } .timeline-item_timestamp { color: #38254D; font-weight: bold; font-size: 30rpx; line-height: 32rpx; } .timeline-item_content { display: flex; flex-direction: column; margin-top: 20rpx; margin-bottom: 20rpx; text { font-size: 26rpx; color: #574966; line-height: 40rpx; } .btn { align-self: flex-end; font-size: 26rpx; color: #F06245; line-height: 60rpx; text-align: center; margin-top: -40rpx; width: 140rpx; height: 60rpx; border: 1rpx solid #F06245; border-radius: 30rpx; } } </style> <!-- 其他的内容样式 --> <style scoped="scoped" lang="scss"> .teaching-dynamics-container { padding: 39rpx 30rpx 30rpx 30rpx; // 优秀 .grade-excellent { background: #5ECDB6; } // 良好 .grade-good { background: #FF8B64; } // 差 .grade-bad { background: #FF6363; } .tdc-line { height: 1rpx; background: #ECEDEF; // background: #ff6666; margin-top: 25rpx; margin-bottom: 25rpx; } .tdc-course-info { display: flex; .tdc-grade { width: 54rpx; height: 36rpx; background: #5ECDB6; border-radius: 24rpx 24rpx 0rpx 24rpx; text-align: center; font-family: PingFang SC, PingFang SC; font-weight: 400; font-size: 24rpx; color: #FFFFFF; } .tdc-coursename { font-family: PingFang SC, PingFang SC; font-weight: 400; font-size: 28rpx; color: #313960; padding-left: 13rpx; } } .tdc-class-schedule { margin-top: 30rpx; // height: 196rpx; background: #F7F8FB; border-radius: 8rpx 8rpx 8rpx 8rpx; padding: 30rpx 30rpx; .tdc-classinfo { display: flex; padding-left: 46rpx; .tcs-classtag { color: #B3B3B3; font-size: 24rpx; font-family: PingFang SC, PingFang SC; } .tsc-classname { color: #313960; font-size: 24rpx; font-family: PingFang SC, PingFang SC; } } .tdc-cs-schedule { display: flex; margin-top: 20rpx; padding-left: 46rpx; .tcs-cs-scheduletag { color: #B3B3B3; font-size: 24rpx; font-family: PingFang SC, PingFang SC; } .tsc-cs-schedulename { color: #313960; font-size: 24rpx; font-family: PingFang SC, PingFang SC; } } .tdc-cs-completeinfo { display: flex; font-family: PingFang SC, PingFang SC; font-weight: 400; font-size: 24rpx; color: #55B6FF; padding-left: 46rpx; .tdc-csc-warp { display: flex; } } .tdc-csc-warp-right { margin-left: 100rpx; } } .system-study-situation { .sss-title-complete { display: flex; justify-content: space-between; align-items: center; .sss-title { font-size: 30rpx; color: #313960; display: flex; align-items: center; .sss-grade { width: 39rpx; height: 32rpx; // background: #5ECDB6; border-radius: 10rpx 8rpx 10rpx 8rpx; margin-left: 10rpx; // 微调一下间距 margin-top: -4rpx; text-align: center; font-family: PingFang SC, PingFang SC; font-weight: 400; font-size: 24rpx; color: #FFFFFF; } } .sss-complete-info { display: flex; font-family: PingFang SC, PingFang SC; font-weight: 400; font-size: 24rpx; color: #313960; :last-child { margin-left: 20rpx; } } } .sss-chapter-study-situation { .sss-css-item { display: flex; justify-content: space-between; align-items: center; height: 73rpx; background: #F9F9F9; border-radius: 8rpx 8rpx 8rpx 8rpx; font-family: PingFang SC, PingFang SC; font-weight: 400; font-size: 24rpx; color: rgba(0, 0, 0, 0.6); margin-top: 20rpx; padding: 0px 15rpx; // .sss-ci-title { // } // .sss-ci-situation{ // } } } } } </style> ``` ### 时间轴效果2 #### 注意横向滚动条的问题 tn6>有可能会因为宽度问题出现横向滚动条,注意根据实际情况微调一下样式即可。这里的样式是不会出现横向滚动条的,要改造样式的话注意一下因为宽度问题造成的横向滚动条即可。 一般因为宽度问题出现横向滚动条是因为这里的样式: ``` .timeline-item_wrapper { position: relative; padding: 32rpx 24rpx; // ****就是这一句,宽度窄的时候不会出现横向滚动条,但是宽度撑满的时候就会出现了**** left: 42rpx; top: -32rpx; background-color: #ffffff; border-radius: 20rpx; width: 600rpx; } ``` 所以其实建议这样修改更科学一点(通过padding与margin-left来实现不使用left): ``` .timeline-item_wrapper { position: relative; padding: 0rpx 0rpx 20rpx 25rpx; // 加一个left可能会出现横向滚动条,体验不太好,可以通过margin-left来设置就不会有问题了 // left: 32rpx; margin-left: 32rpx; top: -6rpx; background-color: #ffffff; } ``` 贴的其他例子中,如果timeline-item_wrapper里边使用left来实现位置调整的,都可能有这个问题,就不在累述了,根据上面的规则调整即可 #### 效果图2 ![](https://img.tnblog.net/arcimg/aojiancc2/aa3cb59bf858420282707bc0984c3ed4.png) #### 具体的代码和样式2 ``` <template> <view class="content"> <view class="describle"> 参加班级、寝室第1次扫除道并上传打扫完之后的图片<span style="color:#4D9DF5">(已完成3次)</span> </view> <view class="writeContent"> <textarea style="background-color: #fff;width: 100%;"></textarea> </view> <view class="timeline-list"> <block v-for="(item, index) in 3" :key="index"> <view class="timeline-item"> <view class="timeline-item_tail"></view> <view class="timeline-item_node"></view> <view class="timeline-item_wrapper"> <div>已完成《参加班级扫除道》并上传照片</div> <div class="image-content"> <image class="imgitem" @click="previewImg(0)" mode="scaleToFill" src="https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg"></image> <image class="imgitem" @click="previewImg(1)" src="https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg"></image> </div> <div class="task_time"> 2023-08-30 16:53:08 </div> </view> </view> </block> </view> </view> </template> <script setup lang="ts"> import { ref } from 'vue' const title = ref('Hello') // import UaTimeline from '@/component/ua-timeline/ua-timeline.vue' // import UaTimelineItem from '@/component/ua-timeline-item/ua-timeline-item.vue' const previewImg = (index = 0) => { console.log("预览!") uni.previewImage({ urls: ['https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg', 'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg', 'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg'], current: index }); } </script> <style lang="scss" scoped> .content { background: #F4F6F9; .describle { // font-size: 32rpx; margin-top: 25rpx; font-family: PingFang SC-Regular, PingFang SC; font-weight: 400; } .writeContent { margin-top: 30rpx; } .taskContent { background-color: #fff; margin-top: 30rpx; padding-top: 10px; } .image-content { margin-top: 10px; display: flex; flex-wrap: wrap; justify-content: space-between; .imgitem { flex: 0 0 32%; /* 动态计算间距 */ margin-right: calc(4% / 3); // margin-bottom: calc(5% / 3); margin-bottom: 6px; // width: 124px; height: 139px; background: #F6F6F6; border-radius: 0px 0px 0px 0px; opacity: 1; } /* 去除每行尾的多余边距 */ .imgitem:nth-child(3n) { margin-right: 0; } /* 使最后一个元素的边距填满剩余空间 */ .imgitem:last-child { margin-right: auto; } } } </style> <!-- 时间轴样式 --> <style lang="scss" scoped> .timeline-list { margin: 32rpx; margin-top: 62rpx; font-size: 28rpx; list-style: none; } .timeline-item:last-child .timeline-item_tail { display: none; } .timeline-item { position: relative; padding-bottom: 20rpx; } .timeline-item_tail { position: absolute; left: 4rpx; height: 100%; border-left: 2rpx solid rgba(109, 209, 201, 0.3); } .timeline-item_node { position: absolute; background-color: #FFFFFF; border-radius: 50%; display: flex; justify-content: center; align-items: center; left: -12rpx; width: 22rpx; height: 22rpx; background: #fff; border: 6rpx solid #6DD1C9; } .timeline-item_wrapper { position: relative; padding: 32rpx 24rpx; left: 42rpx; top: -32rpx; background-color: #ffffff; border-radius: 20rpx; width: 600rpx; } .timeline-item_timestamp { color: #38254D; font-weight: bold; font-size: 30rpx; line-height: 32rpx; } .timeline-item_content { display: flex; flex-direction: column; margin-top: 20rpx; margin-bottom: 20rpx; text { font-size: 26rpx; color: #574966; line-height: 40rpx; } .btn { align-self: flex-end; font-size: 26rpx; color: #F06245; line-height: 60rpx; text-align: center; margin-top: -40rpx; width: 140rpx; height: 60rpx; border: 1rpx solid #F06245; border-radius: 30rpx; } } </style> ``` ### 时间轴效果3(在uni-app小程序弹窗里边使用的) #### 效果图3 <img src="https://img.tnblog.net/arcimg/aojiancc2/4ed95c65bc3a49c68879e195f0ba41ae.png" style="width:399px;height:auto;"> #### 具体的代码和样式3 这里实现了图片超过一行后会自适应布局的,一行显示4张图 **弹窗里边的内容** ``` <template> <view class="monthTaskDetails-container"> <view class="titleWrap"> <view class="title">{{ title }}</view> <view class="closeTag" @tap="handleClose">×</view> </view> <view class="splitline"></view> <scroll-view scroll-y="true" style=" height: 700rpx;"> <view class="timeline-list"> <block v-for="(item, index) in 3" :key="index"> <view class="timeline-item"> <view class="timeline-item_tail"></view> <view class="timeline-item_node"></view> <view class="timeline-item_wrapper"> <div>已完成《参加班级扫除道》并上传照片</div> <view class="image-content"> <image class="imgitem" @click="previewImg(0)" mode="scaleToFill" src="https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg"> </image> <image class="imgitem" @click="previewImg(1)" src="https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg"> </image> <image class="imgitem" @click="previewImg(2)" src="https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg"> </image> <image class="imgitem" @click="previewImg(3)" src="https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg"> </image> <image class="imgitem" @click="previewImg(4)" src="https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg"> </image> <image class="imgitem" @click="previewImg(5)" src="https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg"> </image> </view> <view class="extraData"> <view class="task_time"> 2023-08-30 16:53:08 </view> <image class="deleteimg" src="../../static/delete.png"> </image> </view> </view> </view> </block> </view> </scroll-view> </view> </template> <script setup lang="ts"> import { ref, reactive } from 'vue' const props = defineProps({ title: { type: String, default: "完成人次" }, userList: { type: Array, default: [] } }) // 触发closePopup事件 const emit = defineEmits(['closePopup']) const handleClose = () => { emit('closePopup', '参数') } // 图片预览 const previewImg = (index = 0) => { uni.previewImage({ urls: ['https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg', 'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg', 'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg', 'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg', 'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg', 'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg'], current: index }); } </script> <style lang="scss" scoped> .monthTaskDetails-container { height: 799rpx; background-color: #fff; border-top-left-radius: 60rpx; border-top-right-radius: 60rpx; .titleWrap { display: flex; padding-top: 22rpx; padding-left: 20rpx; padding-right: 20rpx; justify-content: center; align-items: center; /* 垂直居中 */ position: relative; .title { font-family: PingFang SC, PingFang SC; font-weight: bold; font-size: 36rpx; color: #313960; } .closeTag { position: absolute; right: 16rpx; padding: 10rpx 20rpx; font-size: 50rpx; } } .splitline { margin-left: -20rpx; margin-right: -20rpx; margin-top: 30rpx; height: 1rpx; background: #f3f3f3; } .image-content { margin-top: 10px; display: flex; flex-wrap: wrap; justify-content: space-between; .imgitem { flex: 0 0 23%; /* 动态计算间距 */ margin-right: calc(8% / 3); margin-bottom: 15rpx; height: 200rpx; background: #F6F6F6; border-radius: 0px 0px 0px 0px; opacity: 1; } /* 去除每行尾的多余边距 */ .imgitem:nth-child(4n) { margin-right: 0; } /* 使最后一个元素的边距填满剩余空间 */ .imgitem:last-child { margin-right: auto; } } .extraData { display: flex; margin-top: 10rpx; align-items: center; .task_time { font-size: 24rpx; color: #909399; } .deleteimg { width: 22rpx; height: 22rpx; margin-left: 20rpx; margin-top: -2rpx; } } } </style> <!-- 时间轴样式 --> <style lang="scss" scoped> .timeline-list { margin: 32rpx; margin-top: 62rpx; font-size: 28rpx; list-style: none; } .timeline-item:last-child .timeline-item_tail { display: none; } .timeline-item { position: relative; padding-bottom: 20rpx; } // 时间轴的竖线样式 .timeline-item_tail { position: absolute; left: 2rpx; height: 100%; border-left: 2rpx solid rgba(109, 209, 201, 0.3); } .timeline-item_node { position: absolute; background-color: #FFFFFF; border-radius: 50%; display: flex; justify-content: center; align-items: center; left: -12rpx; width: 17rpx; height: 17rpx; background: #fff; border: 6rpx solid #E5E5E5; } // 时间轴的第一个圈的颜色 .timeline-item:first-child { .timeline-item_node { border: 6rpx solid #4D9DF5; } } .timeline-item_wrapper { position: relative; // padding: 32rpx 24rpx; padding: 32rpx calc(8% / 3) 32rpx 24rpx; left: 26rpx; top: -39rpx; background-color: #ffffff; border-radius: 20rpx; } .timeline-item_timestamp { color: #38254D; font-weight: bold; font-size: 30rpx; line-height: 32rpx; } .timeline-item_content { display: flex; flex-direction: column; margin-top: 20rpx; margin-bottom: 20rpx; text { font-size: 26rpx; color: #574966; line-height: 40rpx; } .btn { align-self: flex-end; font-size: 26rpx; color: #F06245; line-height: 60rpx; text-align: center; margin-top: -40rpx; width: 140rpx; height: 60rpx; border: 1rpx solid #F06245; border-radius: 30rpx; } } </style> ``` **父组件,使用弹窗的地方** ``` <template> <view class="body-view"> <uni-popup ref="monthTaskDetailsPopup" background-color="#fff" border-radius="60rpx 60rpx 0rpx 0rpx;" type="bottom"> <monthTaskDetails @closePopup="closeMonthTaskDetails" title="参加班级扫除道"> </monthTaskDetails> </uni-popup> </view> </template> <script setup lang="ts"> import monthTaskDetails from './component/monthTaskDetails.vue' let monthTaskDetailsPopup = ref() // 打开弹窗 const showMonthTaskDetails = () => { monthTaskDetailsPopup.value.open() } // 关闭弹窗 const closeMonthTaskDetails = () => { monthTaskDetailsPopup.value.close() } </script> ``` ### 时间轴效果4(包含grid布局实现一行显示3个文字,图文消息,参与人员与缺勤人员,悬浮菜单等) #### 效果图4 <img src="https://img.tnblog.net/arcimg/aojiancc2/af23221ebd464820aed6b5049251ee98.jpg" style="width:399px;height:auto;"> #### 具体的代码和样式4 ``` <template> <view class="content"> <view class="describle"> {{ state.taskName }}<text>(已完成3次)</text> </view> <!-- <view v-for="(stu, index) in 50" :key="index"> {{index}} </view> --> <view class="timeline-list"> <template v-for="item in 3" :key="item.id"> <view class="timeline-item"> <view class="timeline-item_tail" /> <view class="timeline-item_node" /> <view class="timeline-item_wrapper"> <view class="stu-name"> 王佳佳 </view> <view class="task-content">已完成《参加班级扫除道》并上传照片</view> <view class="image-content"> <image class="imgitem" v-for="(img, index) in state.imgLists" :key="index" mode="aspectFill" :src="img" /> <view class="" style="flex: 1" /> </view> <view class="task-person"> <view class="participant-list"> <!-- 参与人员 --> <view class="p-item" v-for="(stu, index) in 15" :key="index"> <view class="tp-stu">小明{{ index }}:</view> <view class="tp-status">参与</view> </view> <!-- 缺勤人员 --> <view class="p-item" v-for="(stu, index) in 5" :key="index"> <view class="tp-stu">小红{{ index }}:</view> <view class="tp-status-absence">缺勤</view> </view> </view> </view> <view class="task_time"> 2024-7-24 12:30 <!-- <text class="task-reject">删除</text> --> </view> </view> </view> </template> </view> <view class="task-complate-to"></view> </view> </template> <script setup lang="ts"> import { ref, reactive } from 'vue' import { onLoad, onShow } from '@dcloudio/uni-app' import http from '@/common/request.ts' import config from '@/common/config.ts' import dayjs from 'dayjs' const state = reactive({ taskName: '参加早迎接活动', imgLists: ['https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg', 'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg', 'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg', 'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg', 'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg', 'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg'] }) </script> <style lang="scss" scoped> .content { background: #f4f6f9; .describle { padding: 20rpx; font-weight: 400; font-size: 30rpx; color: #313960; border-top: 4rpx solid #ededed; text { margin-left: 20rpx; color: #4d9df5; font-size: 24rpx; } } .image-content { margin-top: 20rpx; display: flex; flex-wrap: wrap; // justify-content: space-between; .imgitem { width: 31%; /* 动态计算间距 */ margin-right: calc(7% / 2); // margin-bottom: calc(5% / 3); margin-bottom: 20rpx; // height: width; height: 199rpx; background: #f6f6f6; border-radius: 0px 0px 0px 0px; opacity: 1; } /* 去除每行尾的多余边距 */ .imgitem:nth-child(3n) { margin-right: 0px; } /* 使最后一个元素的边距填满剩余空间 */ .imgitem:last-child { margin-right: auto; } } .task-complate-to { width: 108rpx; height: 108rpx; background: linear-gradient(180deg, #4d9df5 0%, #63cfff 100%); box-shadow: 0px 4rpx 10rpx 1rpx rgba(77, 157, 245, 0.32); border-radius: 50%; position: fixed; bottom: 102rpx; right: 30rpx; } .task-complate-to::before { content: ' '; width: 56rpx; border-bottom: 4rpx solid #ffffff; position: absolute; left: calc(50% - 28rpx); top: calc(50% - 2rpx); } .task-complate-to::after { content: ' '; height: 56rpx; border-right: 4rpx solid #ffffff; position: absolute; left: calc(50% - 2rpx); top: calc(50% - 28rpx); } } </style> <style lang="scss" scoped> .timeline-list { font-size: 28rpx; list-style: none; padding: 30rpx 30rpx 20rpx 30rpx; padding-bottom: 0; background-color: #ffffff; } .timeline-item:last-child .timeline-item_tail { display: none; } .timeline-item { position: relative; // padding-bottom: 20rpx; .timeline-item_tail { position: absolute; left: 6rpx; top: 0; bottom: 0; border-left: 2rpx solid rgba(109, 209, 201, 0.3); } .timeline-item_node { position: absolute; background-color: #ffffff; border-radius: 50%; display: flex; justify-content: center; align-items: center; left: -9rpx; width: 18rpx; height: 18rpx; background: #fff; border: 6rpx solid #6dd1c9; } .timeline-item_wrapper { position: relative; padding: 0rpx 0rpx 20rpx 25rpx; // 加一个left可能会出现横向滚动条,体验不太好,可以通过margin-left来设置就不会有问题了 // left: 32rpx; margin-left: 32rpx; top: -6rpx; background-color: #ffffff; // margin-left: 42rpx; // border-radius: 20rpx; // width: 600rpx; .stu-name { font-size: 30rpx; font-weight: bold; color: #174a90; margin-bottom: 10rpx; } .task-content { color: #313960; font-size: 30rpx; font-weight: 400; } .task-person { margin-top: 20rpx; font-size: 24rpx; .p-item { display: flex; margin-bottom: 22rpx; .tp-stu { color: #313960; } } .participant-list { display: grid; /*每行显示四个,宽度由内容自适应*/ grid-template-columns: repeat(3, auto); /*显示方式为左右无间距,中间均分*/ justify-content: space-between; grid-column-gap: 19rpx; } .participant-list { .tp-status { color: #67c23a; background: #f0f9eb; border-radius: 4rpx; padding: 0 10rpx; } .tp-status-absence { color: #f56c6c; background: #fef0f0; border-radius: 4rpx; padding: 0 10rpx; } } } .task_time { margin-top: 4rpx; margin-bottom: 40rpx; color: #909399; font-size: 24rpx; .task-reject { color: #f56c6c; font-size: 24rpx; margin-left: 20rpx; } } } } </style> ``` #### 包含vue绑定数据的也贴一下吧 上面那个是静态的可以直接复制进去看效果的,这个加了一点数据绑定解析的 ``` <template> <view class="content"> <view class="describle"> {{ state.taskName }}<text>(已完成{{ state.dataList.length }}次)</text> </view> <view class="timeline-list"> <template v-for="(item, findex) in state.dataList" :key="findex"> <view class="timeline-item"> <view class="timeline-item_tail" /> <view class="timeline-item_node" /> <view class="timeline-item_wrapper"> <view class="stu-name"> 王佳佳 </view> <view class="task-content">{{ item.comment }}</view> <view class="image-content"> <image class="imgitem" v-for="(img, index) in JSON.parse(item.imgJson)" :key="index" mode="aspectFill" :src="GetImgUrl(img)" @tap="previewImg(item.imgJson, index)" /> <view class="" style="flex: 1" /> </view> <view class="task-person"> <view class="participant-list"> <!-- 参与人员 --> <view class="p-item" v-for="(stu, index) in item.groupUsers" :key="index"> <view class="tp-stu">{{ stu }}:</view> <view class="tp-status">参与</view> </view> <!-- 缺勤人员 --> <view class="p-item" v-for="(stu, index) in item.noGroupUsers" :key="index"> <view class="tp-stu">{{ stu }}:</view> <view class="tp-status-absence">缺勤</view> </view> </view> </view> <view class="task_time"> {{dayjs(item.completeDateTime).format('YYYY-MM-DD HH:mm:ss')}} <!-- <text class="task-reject">删除</text> --> </view> </view> </view> </template> </view> <view class="task-complate-to" v-if="false"></view> </view> </template> <script setup lang="ts"> import { ref, reactive } from 'vue' import { onLoad, onShow } from '@dcloudio/uni-app' import http from '@/common/request.ts' import config from '@/common/config.ts' import dayjs from 'dayjs' import { GetImgUrl } from '@/common/utils.ts' const state = reactive({ taskName: '参加早迎接活动', dataList: [] as any }) onLoad((e) => { state.taskName = e?.taskName // 设置页面标题 if (e?.taskName && e?.taskName.length < 18) { uni.setNavigationBarTitle({ title: e?.taskName }); } uni.getStorage({ key: 'studentCompleteDetails', success: function (res) { state.dataList = res.data console.log("跳转过来获得的数据", res.data); } }); }) // 图片预览 const previewImg = (imgListJson: any, index = 0) => { let imgIdList = JSON.parse(imgListJson) let imgList = [] as any // 根据图片id获取图片的浏览地址 for (let index = 0; index < imgIdList.length; index++) { const element = imgIdList[index]; imgList.push(GetImgUrl(element)) } uni.previewImage({ urls: imgList, current: index }); } </script> <style lang="scss" scoped> .content { background: #f4f6f9; .describle { padding: 20rpx; font-weight: 400; font-size: 30rpx; color: #313960; border-top: 4rpx solid #ededed; text { margin-left: 20rpx; color: #4d9df5; // font-size: 24rpx; } } .image-content { margin-top: 20rpx; display: flex; flex-wrap: wrap; // justify-content: space-between; .imgitem { width: 31%; /* 动态计算间距 */ margin-right: calc(7% / 2); // margin-bottom: calc(5% / 3); margin-bottom: 20rpx; // height: width; height: 199rpx; background: #f6f6f6; border-radius: 0px 0px 0px 0px; opacity: 1; } /* 去除每行尾的多余边距 */ .imgitem:nth-child(3n) { margin-right: 0px; } /* 使最后一个元素的边距填满剩余空间 */ .imgitem:last-child { margin-right: auto; } } .task-complate-to { width: 108rpx; height: 108rpx; background: linear-gradient(180deg, #4d9df5 0%, #63cfff 100%); box-shadow: 0px 4rpx 10rpx 1rpx rgba(77, 157, 245, 0.32); border-radius: 50%; position: fixed; bottom: 102rpx; right: 30rpx; } .task-complate-to::before { content: ' '; width: 56rpx; border-bottom: 4rpx solid #ffffff; position: absolute; left: calc(50% - 28rpx); top: calc(50% - 2rpx); } .task-complate-to::after { content: ' '; height: 56rpx; border-right: 4rpx solid #ffffff; position: absolute; left: calc(50% - 2rpx); top: calc(50% - 28rpx); } } </style> <style lang="scss" scoped> .timeline-list { font-size: 28rpx; list-style: none; padding: 30rpx 30rpx 20rpx 30rpx; padding-bottom: 0; background-color: #ffffff; } .timeline-item:last-child .timeline-item_tail { display: none; } .timeline-item { position: relative; // padding-bottom: 20rpx; .timeline-item_tail { position: absolute; left: 6rpx; top: 0; bottom: 0; border-left: 2rpx solid rgba(109, 209, 201, 0.3); } .timeline-item_node { position: absolute; background-color: #ffffff; border-radius: 50%; display: flex; justify-content: center; align-items: center; left: -9rpx; width: 18rpx; height: 18rpx; background: #fff; border: 6rpx solid #6dd1c9; } .timeline-item_wrapper { position: relative; padding: 0rpx 0rpx 20rpx 25rpx; // 加一个left可能会出现横向滚动条,体验不太好,可以通过margin-left来设置就不会有问题了 // left: 32rpx; margin-left: 32rpx; top: -6rpx; background-color: #ffffff; // margin-left: 42rpx; // border-radius: 20rpx; // width: 600rpx; .stu-name { font-size: 30rpx; font-weight: bold; color: #174a90; margin-bottom: 10rpx; } .task-content { color: #313960; font-size: 30rpx; font-weight: 400; } .task-person { margin-top: 20rpx; font-size: 24rpx; .p-item { display: flex; margin-bottom: 22rpx; .tp-stu { color: #313960; } } .participant-list { display: grid; /*每行显示四个,宽度由内容自适应*/ grid-template-columns: repeat(3, auto); /*显示方式为左右无间距,中间均分*/ justify-content: space-between; grid-column-gap: 19rpx; } .participant-list { .tp-status { color: #67c23a; background: #f0f9eb; border-radius: 4rpx; padding: 0 10rpx; } .tp-status-absence { color: #f56c6c; background: #fef0f0; border-radius: 4rpx; padding: 0 10rpx; } } } .task_time { margin-top: 4rpx; margin-bottom: 40rpx; color: #909399; font-size: 24rpx; .task-reject { color: #f56c6c; font-size: 24rpx; margin-left: 20rpx; } } } } </style> ``` ### 备注 tn2> 具体的页面模板以及更多模板存储在云盘里边
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739
👈{{preArticle.title}}
👉{{nextArticle.title}}
评价
{{titleitem}}
{{titleitem}}
{{item.content}}
{{titleitem}}
{{titleitem}}
{{item.content}}