1.大概的思想就是后台管理端可以不断的添加图片让它来循环滚动,并且多行多列根据不同的图片总数来展示。
html
<div class="scrool-box">
<div class="box">
<ul ref="ulDom" @mouseenter="pause" @mouseleave="resume">
<li v-for="item in 4" :key="item.id">
<div class="divDom" v-for="item1 in 16" :key="item1.id">小飞侠</div>
</li>
</ul>
</div>
</div>
上面的代码意思很简单我要显示四行 剩下的16 就是每行展示16个图片 那么问题来了他要是在新增不是16怎么办呢,所以就要取后端的数据或者json 了
html
<div class="scroll-box">
<div class="box">
<ul ref="ulDom" @mouseenter="pause" @mouseleave="resume">
<li v-for="(rowItems, index) in shuffledRows" :key="index">
<div class="divDom" v-for="item in rowItems" :key="item">
<img
style="width: 100%; height: 100%"
v-if="item.picture"
:src="item.picture"
/>
<img
style="width: 100%; height: 100%"
v-else
:src="'/assets/home/wanda.png'"
alt=""
/>
</div>
</li>
</ul>
</div>
</div>
这个就是要改造的把他变成数组,前端来操作一下js部分 关键代码
js
const numberOfRows = 4;
const itemsPerRow = 16;
const shuffledRows = ref([]);
const startScroll = (content, contentWidth) => {
let position = 0;
const step = () => {
position -= 1.1;
if (position <= -contentWidth+3) {
position = 0;
}
content.value.style.transform = `translateX(${position}px)`;
requestAnimationFrame(step);
};
requestAnimationFrame(step);
};
function shuffle(array) {
const newArray = [...array];
for (let i = newArray.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[newArray[i], newArray[j]] = [newArray[j], newArray[i]];
}
return newArray;
}
const animation = () => {
const ulWidth = ulDom.value.offsetWidth;
let position = 0;
const animate = () => {
position -= 1.2;
if (position <= -(ulWidth / numberOfRows + 2)) {
position = 0;
}
ulDom.value.style.transform = `translateX(${position}px)`;
animationId = requestAnimationFrame(animate);
};
animate();
};
const pause = () => {
cancelAnimationFrame(animationId);
isPaused = true;
};
const resume = () => {
if (!isPaused) return;
animationId = requestAnimationFrame(animation);
isPaused = false;
};
onMounted(() => {
animation();
});
通过以上代码可以看出,最后实现的办法是通过随机函数生成。
总体思路接下来上完整的代码
js
<template>
<div class="caseBox">
<div class="caseBox-top">
<headerBox path="/serviceScope/caseIndex"></headerBox>
<div class="caseBox-title">
<div class="title">团队业绩</div>
<div class="content">专业负责 · 共创价值</div>
</div>
</div>
<div class="case-consultant">
<div class="case-consultant-title">
<div class="name">深耕细分行业,提供更加垂直的解决方案</div>
<div class="content">
政府决策顾问、政策课题研究、债务化解咨询、园区及片区开发等解决方案
</div>
</div>
<div class="case-information">
<div class="case-information-left">
<div
:class="tabIndex == index ? 'listActive' : 'list'"
v-for="(item, index) in menuListEnum"
:key="index"
@mouseover="changeIndex(index, item)"
>
{{ item.name }}
</div>
</div>
<div class="case-information-right">
<div class="information-title">
{{ content.title ? content.title : menuList[0].title }}
</div>
<div class="information-content" v-if="content.content">
{{ content.content }}
</div>
<div class="information-content" v-else>
{{ content.content ? content.content : "" }}
</div>
<!-- <div class="information-button">
立即咨询<img src="../../../assets/case/right.png" />
</div> -->
<div class="buttonList">
<div
class="tab"
v-for="item in menuList"
:key="item.id"
@mouseover="getData(item)"
>
{{ item.title }}
</div>
</div>
</div>
</div>
</div>
<div class="cityPartner">
<div class="cityPartner-title">
<div class="title">研城伙伴</div>
<div class="englishTitle">partner</div>
</div>
<div class="scroll-box">
<div class="box">
<ul ref="ulDom" @mouseenter="pause" @mouseleave="resume">
<li v-for="(rowItems, index) in shuffledRows" :key="index">
<div class="divDom" v-for="item in rowItems" :key="item">
<img
style="width: 100%; height: 100%"
v-if="item.picture"
:src="item.picture"
/>
<img
style="width: 100%; height: 100%"
v-else
:src="'/assets/home/wanda.png'"
alt=""
/>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
<footer-box></footer-box>
</template>
<script setup>
import { computed, reactive, ref } from "vue";
import headerBox from "../../../components/header.vue";
import footerBox from "../../../components/footer-box.vue";
import { getApiStories, getApiExample } from "../../../api/home.js";
import { onMounted } from "vue";
import { Vue3SeamlessScroll } from "vue3-seamless-scroll";
const ulDom = ref(null);
let animationId = null;
let isPaused = false;
const numberOfRows = 4;
const itemsPerRow = 16;
const shuffledRows = ref([]);
const content = ref({});
const container = ref(null);
const list = ref(null);
const classOption = ref({
limitMoveNum: 2,
direction: 2,
});
const queryForm = reactive({
size: 10,
number: 1,
total: 0,
type: undefined,
});
const listContainer = ref(null);
const getData = (row) => {
console.log(row);
content.value = row;
};
const menuList = ref([
{ name: "政府决策顾问" },
{ name: "政策课题研究" },
{ name: "债务化解咨询" },
{ name: "园区及片区开发" },
{ name: "国有企业发展" },
{ name: "区域发展规划" },
{ name: "预算绩效评价" },
{ name: "国际金融贷款" },
{ name: "专项债券" },
]);
const menuListEnum = ref([
{ name: "政府决策顾问", type: 0 },
{ name: "政策课题研究", type: 1 },
{ name: "债务化解咨询", type: 2 },
{ name: "园区及片区开发", type: 3 },
{ name: "国有企业发展", type: 4 },
{ name: "区域发展规划", type: 5 },
{ name: "预算绩效评价", type: 6 },
{ name: "国际金融贷款", type: 7 },
{ name: "投融资咨询", type: 8 },
{ name: "专项债券", type: 9 },
]);
const governmentList = ref([
{ name: "呼和浩特市财政局长期咨询顾问" },
{ name: "包头市财政局长期咨询顾问" },
{ name: "土默特左旗人民政府长期咨询顾问" },
{ name: "回民区人民政府长期咨询顾问" },
{ name: "托克托县人民政府长期咨询顾问" },
{ name: "清水河财政局长期咨询顾问" },
{ name: "赛罕区城投建设有限公司长期咨询顾问" },
]);
const example = ref([]);
const tabIndex = ref(0);
const startScroll = (content, contentWidth) => {
let position = 0;
const step = () => {
position -= 1.1;
if (position <= -contentWidth+3) {
position = 0;
}
content.value.style.transform = `translateX(${position}px)`;
requestAnimationFrame(step);
};
requestAnimationFrame(step);
};
const changeIndex = (index, row) => {
console.log(row);
queryForm.type = row.type;
tabIndex.value = index;
content.value = row;
setTimeout(() => {
//经典案例
getApiStories(queryForm).then((res) => {
console.log(res);
if (res.code == 200) {
menuList.value = res.data.list;
}
});
}, 500);
};
//经典案例
getApiStories().then((res) => {
console.log(res);
if (res.code == 200) {
menuList.value = res.data.list;
}
});
//获取照片
getApiExample({ number: 1, size: 100 }).then((res) => {
example.value = res.data.list;
for (let i = 0; i < numberOfRows; i++) {
shuffledRows.value.push(shuffle(example.value));
}
});
const visibleItemCount = 5; // 可见项目的数量
const currentIndex = ref(0);
const visibleData = computed(() => {
const dataLength = example.value.length;
const result = [];
for (let i = 0; i < visibleItemCount; i++) {
const dataIndex = (currentIndex.value + i) % dataLength;
result.push(example.value[dataIndex]);
}
return result;
});
// const pause = () => {
// cancelAnimationFrame(animationId);
// isPaused = true;
// };
// const resume = () => {
// if (!isPaused) return;
// animationId = requestAnimationFrame(animation);
// isPaused = false;
// };
// let position = 0;
// const animation = () => {
// const ulWidth = ulDom.value.offsetWidth;
// const animate = () => {
// position -= 1.3;
// if (position <= -(ulWidth / 2)) {
// position = 0;
// }
// ulDom.value.style.transform = `translateX(${position}px)`;
// animationId = requestAnimationFrame(animate);
// };
// animate();
// };
function shuffle(array) {
const newArray = [...array];
for (let i = newArray.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[newArray[i], newArray[j]] = [newArray[j], newArray[i]];
}
return newArray;
}
const animation = () => {
const ulWidth = ulDom.value.offsetWidth;
let position = 0;
const animate = () => {
position -= 1.2;
if (position <= -(ulWidth / numberOfRows + 2)) {
position = 0;
}
ulDom.value.style.transform = `translateX(${position}px)`;
animationId = requestAnimationFrame(animate);
};
animate();
};
const pause = () => {
cancelAnimationFrame(animationId);
isPaused = true;
};
const resume = () => {
if (!isPaused) return;
animationId = requestAnimationFrame(animation);
isPaused = false;
};
onMounted(() => {
// const items = Array.from({ length: itemsPerRow }, (_, index) => index + 1);
animation();
});
</script>
<style scoped lang="scss">
.scroll-box {
display: flex;
justify-content: center;
align-items: center;
transition: all 0.5s ease-in-out;
.box {
width: 100%;
height: 700px;
overflow: hidden;
flex-wrap: wrap;
ul {
width: 200%;
height: 100%;
li {
width: 100%;
float: left;
list-style: none;
display: flex;
.divDom {
width: 120px;
margin: 1%;
}
}
}
}
}
</style>
<style scoped lang="scss">
.caseBox {
.cityPartner {
// height: 100rem;
background: url("../../../assets/home/partner.png") no-repeat;
background-size: cover;
padding: 11rem 24rem;
position: relative;
.cityPartner-title {
.title {
font-size: 4rem;
color: #3b4683;
}
.englishTitle {
color: #767676;
font-size: 2rem;
}
}
}
.case-consultant {
height: 100rem;
background: url("../../../assets/case/caseBack.png") no-repeat;
background-size: 100% 100%;
.case-information {
height: 78.6rem;
margin-left: 24rem;
margin-right: 24rem;
margin-top: 4rem;
display: flex;
.case-information-right {
width: 100%;
height: 100%;
background: #ffffff94;
padding-left: 6rem;
.information-button {
margin-top: 2rem;
width: 19rem;
height: 6rem;
border: 1px solid rgba(0, 0, 0, 0.85);
display: flex;
align-items: center;
justify-content: space-evenly;
cursor: pointer;
font-size: 1.8rem;
}
.buttonList {
display: flex;
flex-wrap: wrap;
margin-top: 2rem;
margin-left: -1rem;
.tab {
width: 30%;
height: 9rem;
background: #ffffff;
margin: 1rem;
display: flex;
align-items: center;
justify-content: center;
color: rgba(0, 0, 0, 0.851);
font-size: 1.6rem;
font-weight: bold;
padding-left: 1rem;
padding-right: 1rem;
// cursor: pointer;
}
.tab:hover {
background: #c5cbf0;
}
}
.information-title {
padding-top: 8rem;
font-size: 2.4rem;
color: #000;
}
.information-content {
padding-right: 6rem;
height: 3rem;
// padding-top: 3.6rem;
color: rgba(0, 0, 0, 0.6);
font-size: 1.8rem;
line-height: 4rem;
max-width: 100rem;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.case-information-left {
width: 33.2rem;
height: 100%;
background: #ffffff;
cursor: pointer;
.list {
height: 7rem;
padding-left: 4.5rem;
display: flex;
align-items: center;
font-size: 1.8rem;
color: rgba(0, 0, 0, 0.6);
}
.listActive {
height: 7rem;
padding-left: 4.5rem;
display: flex;
align-items: center;
font-size: 1.8rem;
color: #ffffff;
background: linear-gradient(90deg, #3b4683 0%, #6272cd 100%);
position: relative;
}
.listActive::before {
width: 10px;
height: 10px;
box-sizing: border-box;
border: 2px solid #ffffff;
border-radius: 100% 100%;
content: "";
position: relative;
left: -1rem;
}
}
}
.case-consultant-title {
padding-top: 4rem;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
.name {
font-size: 4rem;
color: #3b4683;
padding-bottom: 2rem;
font-weight: bold;
}
.content {
color: #3b4683;
font-size: 2rem;
}
}
}
.caseBox-top {
height: 68.7rem;
background: url("../../../assets/case/caseBackgroud.png") no-repeat;
background-size: cover;
.caseBox-title {
margin: 9.5rem 24rem;
.title {
font-size: 7rem;
color: #ffffff;
text-shadow: 0px 4px 2px rgba(59, 70, 131, 0.38);
}
.content {
font-size: 3rem;
color: #ffffff;
text-shadow: 0px 2px 2px rgba(59, 70, 131, 0.27);
padding-top: 4rem;
}
}
}
}
</style>