近日甲方要求想要照片墙滚动,其实不想写,奈何电话一直打 fan!!!! 最后vue3.2 +css 实现一下

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>
相关推荐
昨天;明天。今天。12 分钟前
案例-任务清单
前端·javascript·css
zqx_71 小时前
随记 前端框架React的初步认识
前端·react.js·前端框架
惜.己2 小时前
javaScript基础(8个案例+代码+效果图)
开发语言·前端·javascript·vscode·css3·html5
什么鬼昵称2 小时前
Pikachu-csrf-CSRF(get)
前端·csrf
长天一色2 小时前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript
NiNg_1_2343 小时前
npm、yarn、pnpm之间的区别
前端·npm·node.js
秋殇与星河3 小时前
CSS总结
前端·css
BigYe程普3 小时前
我开发了一个出海全栈SaaS工具,还写了一套全栈开发教程
开发语言·前端·chrome·chatgpt·reactjs·个人开发
余生H3 小时前
前端的全栈混合之路Meteor篇:关于前后端分离及与各框架的对比
前端·javascript·node.js·全栈
程序员-珍3 小时前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发