近日甲方要求想要照片墙滚动,其实不想写,奈何电话一直打 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>
相关推荐
L耀早睡33 分钟前
mapreduce打包运行
大数据·前端·spark·mapreduce
HouGISer1 小时前
副业小程序YUERGS,从开发到变现
前端·小程序
outstanding木槿1 小时前
react中安装依赖时的问题 【集合】
前端·javascript·react.js·node.js
霸王蟹2 小时前
React中useState中更新是同步的还是异步的?
前端·javascript·笔记·学习·react.js·前端框架
霸王蟹2 小时前
React Hooks 必须在组件最顶层调用的原因解析
前端·javascript·笔记·学习·react.js
专注VB编程开发20年2 小时前
asp.net IHttpHandler 对分块传输编码的支持,IIs web服务器后端技术
服务器·前端·asp.net
爱分享的程序员2 小时前
全栈项目搭建指南:Nuxt.js + Node.js + MongoDB
前端
隐含3 小时前
webpack打包,把png,jpg等文件按照在src目录结构下的存储方式打包出来。解决同一命名的图片资源在打包之后,重复命名的图片就剩下一个图片了。
前端·webpack·node.js
lightYouUp3 小时前
windows系统中下载好node无法使用npm
前端·npm·node.js
Dontla3 小时前
npm cross-env工具包介绍(跨平台环境变量设置工具)
前端·npm·node.js