vue项目里手动写一个走马灯效果
我们知道elementUI里有个走马灯的组件,如下图,每隔指定的时间,就可以实现轮播切换
现在项目需求是顶部的派出所和下面的警务人员名单都是后端接口返回的数据,然后派出所是个可以单击选中且有走马灯效果的tab导航,效果如下:
后端返回的数据结构如下:
policeList: [{organName: "赵李桥派出所",organId: "1",roleList: [{roleName: "村辅",policeManList: [{userRealName: "张三",roleName: "村辅",userPhone: "123838732873",personCount: "8",placeCount: "0"}]}]},{organName: "车埔派出所",organId: "2"},{organName: "官塘派出所",organId: "3"}],
这里走马灯的每一项是一个数组,然后我定死了这个数组放6个派出所,所以我要对后端返给我的数据做分组,也就是在v-for时用的 v-for=“item in Math.ceil(policeList.length / 6)“和v-for=”(item, i) in policeList.slice((item - 1) * 6, item * 6)”,除此之外我还要对“村辅”“辅警”等警务数据进行折叠处理,也就是在对警务人员名单v-for时用的 v-for=“(memberItem,
memberIndex) in peopleItem.policeManList.slice(0, 9)” 和 v-for=“(memberItem2,
memberIndex2) in peopleItem.policeManList.slice(
9,
peopleItem.policeManList.length
)” ,因为用到了饿了么组件Collapse 折叠面板,这样就能实现收起和展开效果。完整代码如下:
<template><div class="box"><div class="top"><span class="leftTips">警务人员名单</span><div class="line"></div><div class="rightBox"><el-carouselheight="30px"indicator-position="none"arrow="hover":interval="6000":autoplay="false"class="carousel"><el-carousel-itemv-for="item in Math.ceil(policeList.length / 6)":key="item"><divclass="child"v-for="(item, i) in policeList.slice((item - 1) * 6, item * 6)":key="i"@click="selectItem(item, i)"><el-tooltipclass="el-tooltip"effect="dark":content="item.organName"placement="top"><spanclass="name":class="activeOrganId == item.organId ? 'activeName' : ''">{{ item.organName }}</span></el-tooltip><divv-if="activeOrganId == item.organId"class="activeHeng"></div></div></el-carousel-item></el-carousel></div></div><div class="bottom"><div class="jobBox" v-if="roleList && roleList.length > 0"><div v-for="(peopleItem, peopleIndex) in roleList" :key="peopleIndex"><el-collapse accordion><el-collapse-item><template slot="title"><div class="jobTipsBox">{{ peopleItem.roleName }}</div><div class="memberList"><divclass="member"v-for="(memberItem,memberIndex) in peopleItem.policeManList.slice(0, 9)":key="memberIndex"><el-popoverplacement="top-start"width="240"trigger="hover"><divclass="popBox"style=" display: flex;flex-direction: column;justify-content: center;align-items:center;line-height: 28px;"><spanclass="userName"style=" font-family: pingfang;font-size: 1.25rem;">{{ memberItem.userRealName }}</span><span class="roleName">角色:{{ memberItem.roleName }}</span><span class="userPhone">联系电话: {{ memberItem.userPhone }}</span><el-divider></el-divider><divclass="bottomBox"style=" display: flex;flex-direction: column;"><divclass="child"style=" line-height: 1.75rem;display: flex;justify-content: space-around;width:15rem"><span>管辖重点人员</span><div:style="{cursor:memberItem.personCount &&Number(memberItem.personCount) > 0? 'pointer': 'auto'}"@click="goPeople(memberItem)"><span:style="{color:memberItem.personCount &&Number(memberItem.personCount) > 0? '#2c8ef0': '#333'}">{{ memberItem.personCount }}</span><span><i:style="{visibility:memberItem.personCount &&Number(memberItem.personCount) > 0? 'visible': 'hidden'}"class="el-icon-arrow-right"></i></span></div></div><divclass="child"style=" line-height: 1.75rem;display: flex;justify-content: space-around;width:15rem"><span>管辖重点场所</span><div:style="{cursor:memberItem.placeCount &&Number(memberItem.placeCount) > 0? 'pointer': 'auto'}"@click="goPlace(memberItem)"><span:style="{color:memberItem.placeCount &&Number(memberItem.placeCount) > 0? '#2c8ef0': '#333'}">{{ memberItem.placeCount }}</span><span><i:style="{visibility:memberItem.placeCount &&Number(memberItem.placeCount) > 0? 'visible': 'hidden'}"class="el-icon-arrow-right"></i></span></div></div></div></div><span slot="reference">{{ memberItem.userRealName }}</span></el-popover></div></div></template><div class="memberList marginLeft"><divclass="member"v-for="(memberItem2,memberIndex2) in peopleItem.policeManList.slice(9,peopleItem.policeManList.length)":key="memberIndex2"><span> {{ memberItem2.userRealName }}</span></div></div></el-collapse-item></el-collapse><el-divider v-if="peopleIndex != roleList.length - 1"></el-divider></div></div><div class="jobBox" v-else><div class="noPaddingBox"><img src="@/assets/images/new-home/NoPaddingTask.png" alt="" /><span>暂无警务人员</span></div></div></div></div>
</template><script>
export default {props: {policeList: {type: Array}},data() {return {// policeList: [// {// organName: "赵李桥派出所",// organId: "1",// roleList: [// {// roleName: "村辅",// policeManList: [// {// userRealName: "张三",// roleName: "村辅",// userPhone: "123838732873",// personCount: "8",// placeCount: "0"// }// ]// }// ]// },// {// organName: "车埔派出所",// organId: "2"// },// {// organName: "官塘派出所",// organId: "3"// }// ],activeOrganId: "",roleList: []};},created() {this.activeOrganId =this.policeList && this.policeList.length > 0? this.policeList[0].organId: "";},watch: {activeOrganId: {handler(newOrganId, oldOrganId) {let findObj = this.policeList.find(k => {return k.organId == newOrganId;});if (findObj) {this.$nextTick(() => {this.roleList = findObj.roleList;});}},immediate: true}},methods: {selectItem(item, i) {if (this.activeOrganId == item.organId) {} else {this.activeOrganId = item.organId;this.$emit("getPolice", item.organId);}},goPeople(memberItem) {if (memberItem.personCount && Number(memberItem.personCount) == 0) {} else {this.$router.push({path: "/resource/person",query: {userId: memberItem.userId}});}},goPlace(memberItem) {if (memberItem.placeCount && Number(memberItem.placeCount) == 0) {} else {this.$router.push({path: "/resource/placement",query: {userId: memberItem.userId}});}}}
};
</script><style lang="less" scoped>
.box {display: flex;flex-direction: column;min-height: 12.1062rem;.top {height: 2.75rem;position: relative;.leftTips {position: absolute;top: 1.125rem;left: 1.25rem;height: 1.1875rem;font-size: 1.25rem;font-family: pingfang;font-weight: bold;color: #333333;line-height: 1.375rem;}.line {position: absolute;top: 1.3125rem;left: 9.4375rem;width: 1px;height: 1.125rem;border: 1px solid #dddddd;}/deep/ .rightBox {position: absolute;top: 1.375rem;left: 10.4375rem;display: flex;flex-wrap: nowrap;width: 50rem;// border: 1px solid red;.el-carousel {width: 100%;.el-carousel__container {width: 100%;.el-carousel__arrow {margin-top: -0.25rem;width: 1.25rem !important;height: 1.25rem !important;}.el-carousel__item {padding: 0 3.125rem;display: flex;.child {width: 7.5rem;position: relative;font-size: 1.125rem;font-family: pingfang;font-weight: 500;color: #838a9d;line-height: 1.375rem;.name {width: 7.5rem;position: absolute;top: 0rem;left: 0;text-align: center;cursor: pointer;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;}.activeName {position: absolute;top: 0rem;left: 0;font-weight: bold;color: #2969ff;}.activeHeng {position: absolute;// margin-top: 1.5rem;top: 1.65rem;left: 50%;transform: translateX(-50%);width: 2.25rem;height: 4px;background: #2969ff;}}}}}}}/deep/ .bottom {// border: 1px solid blue;margin: 1.25rem 0;.jobBox {padding-left: 1.25rem;position: relative;.noPaddingBox {position: absolute;top: -2.2rem;left: 50%;transform: translateX(-50%);display: flex;flex-direction: column;text-align: center;img {width: 8.5rem;height: 7.0625rem;}span {font-size: 1.125rem;font-family: pingfang;font-weight: 500;color: #333333;line-height: 1.375rem;margin-top: 1.0625rem;}}.jobTipsBox {width: 5rem;height: 2.5rem;background: rgba(41, 105, 255, 0.05);border: 1px solid #1182fb;border-radius: 4px;text-align: center;font-size: 1rem;font-family: pingfang;font-weight: 500;color: #2969ff;line-height: 2.5rem;margin-right: 1.25rem;}.memberList {display: flex;.member {width: 4rem;font-size: 1rem;font-family: pingfang;font-weight: 400;color: #3c4353;line-height: 1.375rem;margin-right: 1.8rem;.el-popover {.popBox {.userName {}.roleName {}.userPhone {}.el-divider {}.bottomBox {.child {div {span {&:nth-child(1) {}&:nth-child(2) {}}}}}}}}}.marginLeft {margin-left: 6.25rem;}}}/deep/ .el-collapse {border: none;}/deep/ .el-collapse-item__wrap {border: none;}/deep/ .el-collapse-item__header {border-bottom: none;}/deep/ .el-divider--horizontal {width: 95%;}
}
</style>
这是利用饿了么官方的组件Carousel实现的走马灯,我们自己也可以实现走马灯,如下效果:
这个任务类型统计里一页打算展示10个任务类型,如果超过10个就也有走马灯轮播切换效果,然后鼠标放在文本上还有提示效果,鼠标放在每项任务上时开启自动轮播,鼠标移出时清除定时轮播,由于后端返回的接口数据是没有图片的,所以需要前端处理一下拿到的接口数据并展示,这里用到了定时器,记得在destroyed里clearInterval(this.start)清除定时器哦,然后用到鼠标移入移出事件,taskCountArr是父组件发请求后传过来的源数据,前端需要处理才能展示,完整代码如下:
<template><div class="box"><div class="top"><span class="leftTips">任务类型统计</span></div><div class="barBox"><div class="tabBox" v-if="imgList && imgList.length > 0"><divclass="SwiperBox"ref="SwiperBox"@mouseenter="MouseFun('移入')"@mouseleave="MouseFun('移出')"><divclass="imgBox":style="{ left: `-${leftVal}px`, transition: `${ition}s` }"><divclass="Swiper-item-parent"v-for="(item, index) in imgList":key="index"><divclass="Swiper-item":style="{'margin-bottom':index == 5 ||index == 6 ||index == 7 ||index == 8 ||index == 9? '0': '1.25rem'}"v-for="(items, indexs) in item":key="indexs"><!-- items.imgUrl --><img :src="items.imgUrl" alt="" /><span class="num">{{ items.num }}</span><el-tooltipclass="el-tooltip"effect="dark":content="items.tips"placement="top"><span class="tips">{{ items.tips }}</span></el-tooltip></div></div><!-- 复制第一张放到最后,以实现无缝无线循环滚动效果 --><divclass="Swiper-item-parent"v-for="(item2, index2) in imgList":key="'2023-' + index2"><divclass="Swiper-item":style="{'margin-bottom':'2023-' + index2 == 5 ||'2023-' + index2 == 6 ||'2023-' + index2 == 7 ||'2023-' + index2 == 8 ||'2023-' + index2 == 9? '0': '1.25rem'}"v-for="(items2, indexs2) in item2":key="'2023-' + indexs2"><img :src="items2.imgUrl" alt="" /><span class="num">{{ items2.num }}</span><el-tooltipclass="el-tooltip"effect="dark":content="items2.tips"placement="top"><span class="tips">{{ items2.tips }}</span></el-tooltip></div></div></div></div><!-- 左箭头按钮 --><!-- <div class="leftBtn" @click="throttle(PrevFun)">←</div>右箭头按钮 <div class="rightBtn" @click="throttle(NextFun)">→</div> --><!-- 下方指示点容器 --><div class="instBox"><div@click="instFun(i)"v-for="(item, i) in imgList.length":key="i":class="['inst', i == imgShow ? 'instActv' : '']"></div></div></div><div class="tabBox" v-else><div class="noPaddingBox"><img src="@/assets/images/new-home/NoPaddingTask.png" alt="" /><span>暂无任务类型</span></div></div></div></div>
</template><script>
export default {props: {startDate: {type: String},endDate: {type: String},taskCountArr: {type: Array}},data() {return {leftVal: 0, // 轮播图盒子的偏移值flag: true, // 用来节流防止重复点击jstart: null, // 自动执行下一张定的时器imgWidth: 960, // 在这里填写你需要的图片宽度ition: 0.8, // 设置轮播图过度时间imgShow: 0, // 表示当前显示的图片索引imgList: []};},watch: {taskCountArr: {handler(newVal, oldVal) {// console.log("接收taskCountArr", newVal);//先清除定时器clearInterval(this.start);let imgArr = [require("../../../../assets/images/new-home/collect/icon01.png"),require("../../../../assets/images/new-home/collect/icon02.png"),require("../../../../assets/images/new-home/collect/icon03.png"),require("../../../../assets/images/new-home/collect/icon04.png"),require("../../../../assets/images/new-home/collect/icon05.png"),require("../../../../assets/images/new-home/collect/icon06.png"),require("../../../../assets/images/new-home/collect/icon07.png"),require("../../../../assets/images/new-home/collect/icon08.png"),require("../../../../assets/images/new-home/collect/icon09.png"),require("../../../../assets/images/new-home/collect/icon10.png")];let random = Math.floor(Math.random() * 10); //获取0到9的随机整数。if (newVal && newVal.length > 0) {let newArr = newVal.map((item, index) => {return {imgUrl: index > 9 ? imgArr[random] : imgArr[index],num: item.valuetag,tips: item.keytag};});// 数组分割let arr = [];let num = 10; // 填写需要分割成几个一组的数量if (newArr.length) {for (let i = 0; i < newArr.length; i += num) {arr.push(newArr.slice(i, i + num));}}this.$nextTick(() => {this.imgList = arr;});// console.log("TaskCount回显", this.imgList);if (newArr.length > 10) {this.autoPlayWay();}this.$forceUpdate();} else {this.imgList = [];}},immediate: true}},destroyed() {clearInterval(this.start);},methods: {// 这里定义一个鼠标移入移出事件,鼠标悬停时停止自动轮播,鼠标移出则重新执行自动轮播MouseFun(type) {// 停止定时器 // 重新执行定时器type == "移入" ? clearInterval(this.start) : this.autoPlayWay();},// 此为自动轮播定时器autoPlayWay() {this.start = setInterval(() => {this.NextFun();}, 4000);},// 这里通过额外封装的节流函数触发 PrevFun() 和 NextFun(),以达到防止重复点击的效果throttle(fun) {if (this.flag) {this.flag = false;fun(); // 此为模板中传递进来的PrevFun()或NextFun()函数setTimeout(() => {this.flag = true;}, 1200); // 节流间隔时间}},// 上一张PrevFun() {if (this.leftVal == 0) {// 判断显示的图片 是 第一张时执行// this.imgList.length是指循环图片数组的图片个数this.ition = 0; // 将过渡时间变成0,瞬间位移到最后一张图this.imgShow = this.imgList.length - 1; // 将高亮小点改为最后一张图this.leftVal = this.imgList.length * this.imgWidth; // 瞬间移动setTimeout(() => {// 通过延时障眼法,归原过渡时间,执行真正的“上一张”函数this.ition = 0.8;this.leftVal -= this.imgWidth;}, this.ition * 1000);} else {// 判断显示的图片 不是 第一张时执行this.ition = 0.8;this.leftVal -= this.imgWidth;this.imgShow--;}},// 下一张NextFun() {// console.log(// "this",// this.leftVal,// (this.imgList.length - 1) * this.imgWidth// );if (this.leftVal == (this.imgList.length - 1) * this.imgWidth) {// 判断显示的项 是 最后一张时执行this.ition = 0.8;this.leftVal += this.imgWidth;this.imgShow = 0;setTimeout(() => {this.ition = 0;this.leftVal = 0;}, this.ition * 4000);} else {// 判断显示的项 不是 最后一张时执行this.ition = 0.8;this.leftVal += this.imgWidth;this.imgShow++;}},// 点击小圆点instFun(index) {this.ition = 0.8;this.leftVal = index * this.imgWidth;this.imgShow = index;}}
};
</script><style lang="less" scoped>
.box {display: flex;flex-direction: column;.top {height: 2.75rem;position: relative;.leftTips {position: absolute;top: 1.125rem;left: 1.25rem;height: 1.1875rem;font-size: 1.25rem;font-family: pingfang;font-weight: bold;color: #333333;line-height: 1.375rem;}}.barBox {// border: 0.5px solid red;margin-top: 0.8125rem;.tabBox {height: 9.75rem;padding: 0 0.75rem 0 1.25rem;position: relative;.noPaddingBox {position: absolute;top: 0;left: 50%;transform: translateX(-50%);display: flex;flex-direction: column;text-align: center;img {width: 8.5rem;height: 7.0625rem;}span {font-size: 1.125rem;font-family: pingfang;font-weight: 500;color: #333333;line-height: 1.375rem;margin-top: 1.0625rem;}}/* 图片容器样式 */.SwiperBox {position: relative;width: 60rem;height: 9.75rem;box-sizing: border-box;overflow: hidden;}.imgBox {position: absolute;top: 0px;left: 0px;// min-width: 60rem;height: 9.75rem;display: flex;justify-content: flex-start;}.Swiper-item-parent {display: flex;flex-wrap: wrap;width: 60rem;/* 图片默认样式 */.Swiper-item {flex-shrink: 0;width: 11.25rem;height: 4.25rem;// margin-bottom:1.25rem;margin-right: 0.75rem;background: #eff3fb;border-radius: 4px;display: flex;position: relative;img {position: absolute;top: 1.25rem;left: 0.625rem;width: 2rem;height: 2rem;}.num {position: absolute;top: 0.4375rem;left: 3.25rem;height: 1.125rem;font-size: 1.25rem;font-family: OPPOSANS-H;font-weight: 800;color: #333333;line-height: 1.75rem;}.tips {position: absolute;top: 2.1rem;left: 3.25rem;width: 6.6875rem;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;font-size: 1rem;font-family: pingfang;font-weight: 500;color: #838a9d;}}}/* 两个按钮共有的样式,也可直接使用箭头图片替代 */.leftBtn,.rightBtn {position: absolute;top: 50%;transform: translateY(-50%);width: 30px;height: 30px;display: flex;justify-content: center;align-items: center;background: rgba(109, 109, 109, 0.445);color: #fff;border-radius: 50%;cursor: pointer;font-size: 12px;font-weight: 500;}.leftBtn {left: 10px;}.rightBtn {right: 10px;}/* 下方指示器盒子 */.instBox {position: absolute;left: 50%;margin-top: 0.625rem;transform: translateX(-50%);// border: 1px solid red;display: flex;}/* 小圆点 */.inst {width: 8px;height: 8px;border: 1px solid #838a9d;margin-right: 0.75rem;background: #eff3fb;border-radius: 50%;cursor: pointer;}.inst:last-child {margin-right: 0px;}.instActv {border: 1px solid #838a9d;background: #1182fb;}#app {width: 100%;padding: 120px;display: flex;justify-content: center;padding: 80px 0px;}}}
}
</style>
vue项目里手动写一个走马灯效果相关推荐
- Node.js 单元测试:我要写测试 - Mocha - Nodejs开源项目里怎么样写测试、CI和代码测试覆盖率
-------------------------------------- 单元测试Express/NodeJs 个人理解, 1,如果不是测试http请求的单元测试,用Mocha, Chai等基本够 ...
- 原来热加载如此简单,手动写一个 Java 热加载吧
1. 什么是热加载 热加载是指可以在不重启服务的情况下让更改的代码生效,热加载可以显著的提升开发以及调试的效率,它是基于 Java 的类加载器实现的,但是由于热加载的不安全性,一般不会用于正式的生产环 ...
- Vue项目里Websocket的使用
由于项目需求有要使用长链接,我们普通的http请求如果用轮询的方式与服务端通讯就很消耗资源.我们一起来学习一下在vue项目里如何使用websocket,本文纯属个人观点,如果有不正确的地方请大家批评指 ...
- jq的插件 vue中引用_详解如何在 vue 项目里正确地引用 jquery 和 jquery-ui的插件
本篇文章主要介绍了详解如何在 vue 项目里正确地引用 jquery 和 jquery-ui的插件,具有一定的参考价值,有兴趣的可以了解一下 使用vue-cli构建的vue项目,webpack的配置文 ...
- 搭建vue项目环境以及创建一个简单的vue的demo
一.vue-cli脚手架的搭建步骤 1.首先,确定你的电脑上已经安装了nodejs,可以使用npm包管理器安装环境,如果还没有安装node环境,则需要安装node.js 这个很简单 默认点击安装 ...
- vue项目打包后生成一个配置文件可以修改打包后的服务器api地址
vue项目打包后生成一个配置文件可以修改打包后的服务器api地址 问题描述:vue项目打包上线之后,如果要改服务器api地址,只能在源码更改然后重新打包发布,为了解决这个问题,我们可以在static增 ...
- 如何手动写一个命令行工具?
文章目录 前言 一.一个最简单的命令行工具 二.命令行解析工具 1.commander (1)option (2)version (3)command (4)argument 2.co-prompt ...
- butterknife 插件_知道这个插件,能让你的项目里少写1000行代码
在项目开发中,我们时常遇到需要创建实体类,一般的做法是: 先写成员变量, 再提供get().set()相对应的方法,然后看是否需要提供toString等方法.这样一来会发现每写一个实体类的话就会有很多 ...
- 深入Vue底层,手写一个vuex
深入底层,手把手教你写一个Vuex 1. Vuex是什么?什么场景下使用? 2. Vuex的基本使用 3. 手写一个vuex 1. Vuex是什么?什么场景下使用? Vuex是vue的一个插件,叫做状 ...
最新文章
- 【面向对象设计模式】 接口型模式 (一)
- Android开发之Java的IO流读写的十种方法
- flutter 一个用户登录页面
- 解决VS.NET 里Atuomation 服务器不能创建对象
- HDFS使用流的方式上传下载
- 30天敏捷结果(14):要事第一
- jogamp-env.xml:48: Unsupported Java version: 11. Make sure that the version of the Java compiler is
- 数字信号处理笔记02:离散时间傅里叶变换(DTFT)
- android expandablelistview 高度自适应,计算ExpandableListView高度
- 解决Synology群晖VideoStation电影电视信息无法手动搜索
- Linux 下安装和配置 MinDoc
- 获取ftp服务器文件,ftp获取服务器文件
- 笔记本html外接显示器,提升效率 笔记本外接显示器(Intel篇)
- 多线程在单核cpu与多核cpu下如何工作
- 北京中医药大学计算机应用基础作业,北京中医药大学计算机应用基础第五次.doc...
- Python学习13 ----Seaborn调色板
- 一篇关于GPS定位写得最详实清晰的文章之一
- mybatis执行流程
- android app自动锁屏,Android开机自动启动app 不锁屏
- Minecraft 1.12.2 彩色渐变字体 模组发布