毕设之-Hlang社区-前端律动卡片

前言

废话不多说,我们来直接看到要实现的效果: (没错,我又来写写前端,水博文了,嘿嘿·) 实现效果:

  1. 在视角内的卡片看起来有规律的律动
  2. 图片光标放上去,有放大效果

结构

okey,由于这个效果比较见简单,所有,就非常happy,

html 复制代码
        <div class="center">
            <!-- 后面这里有个循环,负责动态加载数据 -->
            <div class="card-item" 
                v-for="(item, index) in items" :key="index" 
                :id=item.styleId
                @mouseover="handleMouseOver(item)"
                @mouseout="handleMouseOut(item)"
                @click="goCloumnBlogs"
                >
                <div class="img-box">
                    <img :src=item.imgSrc class="card-img">
                </div>
                <div class="card-title">
                    <u-fold line="1">
                        <h3>{{ item.title }}</h3>
                    </u-fold>
                </div>
                <div class="card-context">
                    <u-fold line="3">
                        {{ item.context }}
                    </u-fold>
                </div>
            </div>
        </div>

我们就这几个东西,包裹起来,因为哪些律动效果,都是用Jscript实现的,没办法,前端比较糟糕。

实现

图片放大

首先是图片的一个放大效果,这个效果主要就是,鼠标放上去,然后这个图片放缩的效果。那么这里的实现比较简单,要注意的一个点就是,我们的那个img,我们要再来一个div保住这个东西。放大了over一下就好了。

css 复制代码
.card-img {
    width: 100%;
    height: 150px;
    padding: 2px;
}

.img-box {

    width: 100%;
    height: 150px;
    overflow: hidden;
}

.card-img:hover {
    animation: move .5s linear forwards;
}

@keyframes move {
    0% {
        transform: scale(1);
    }

    100% {
        transform: scale(1.1);
    }
}

然后绑定个动画就可以了。

律动

然后就是律动效果:

首先的话,我们还是来看到这个css,因为我这里其实还是css配合js来实现的。没办法

css 复制代码
#up {
    
    /* 盒子阴影 */
    box-shadow: 4px 20px 40px 5px rgba(6, 100, 224, 0.1);
    /* 盒子向上移动效果,改变上外边距 */
    margin-top: 26px;
    transform: scale(1.1);

}

#down{
    animation: move .2s ease-in reverse;
}

@keyframes move {
    0% {
        transform: scale(1);
    }

    100% {
        transform: scale(1.1);
    }
}


.card-item {
    
    cursor: pointer;
    width: 150px;
    margin-top: 30px;
    margin-bottom: 30px;
    display: flex;
    flex-direction: column;
    background: whitesmoke;
    height: 250px;
    justify-content: center;
    align-items: center;
    border-radius: 10px;
    transition: all 0.5s ease-in;
}


.card-item:hover {
    /* 盒子阴影 */
    box-shadow: 4px 20px 40px 5px rgba(4, 59, 137, 0.5);
    /* 盒子向上移动效果,改变上外边距 */
    margin-top: 26px;
    transform: scale(1.1);
}

.center {

    width: 75%;
    align-content: flex-start;
    margin: 20px auto;
    display: flex;
    column-gap: 40px;
    flex-flow: wrap;
}

这几个css定义了它是怎么样的一个效果,然后实现律动的一个效果的话,就是去修改对应的一个box的一个属性,然后就ok了。

js 复制代码
// 得到指定的在可视区域内的元素
async function traverseVisibleElements(classSelect:string,doing:Function) {


  if(going.value!=false){
    return
  }
  going.value = true;
  const elements = document.querySelectorAll(classSelect);

  for (let i = 0; i < elements.length; i++) {
    const element = elements[i];
    const rect = element.getBoundingClientRect();

    if (
      rect.top >= 0 &&
      rect.left >= 0 &&
      rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
      rect.right <= (window.innerWidth || document.documentElement.clientWidth)
    ) {
    //   console.log('元素在屏幕可视区域内:', element);
     await doing(element,i)

    }
  }

  going.value = false;
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

//按照周期修改元素属性,实现元素周期放大的效果
async function flowUp(element:Element,index){
    
    let sleepTime = Math.abs(Math.sin(((index*Math.PI)/10))*1000)
    element.id = "down"
    await sleep(sleepTime)
    element.id = "up"
    console.log(sleepTime)
}

// 计算每个 item 的初始位置和周期函数值
onMounted(() => {
  traverseVisibleElements(".card-item",flowUp)
  setInterval(() => {
    traverseVisibleElements(".card-item",flowUp)
  },1500); // 刷新间隔
}
);

// 鼠标悬停时取消特效
const handleMouseOver = (item:ItemData) => {
  item.styleId='down'
};

const handleMouseOut = (item:ItemData) => {
    item.styleId='up'
};

这里的话,扫描到在范围内的一个符合条件的盒子,然后定时去刷新,改动属性,然后每个元素按照一个周期函数的间隔去动态修改。这个的话实现一个跳动效果。

页面完整代码

okey,这里再看到页面的一个比较完整的代码,这里的话,还没有功能代码,后面后端搭起来再说。

html 复制代码
<template>

    <aside>
        <!-- 两个按钮 -->
        <el-button class="Official" type="primary" circle>精选</el-button>
        <el-button class="Private" type="primary" circle>ALL</el-button>
    </aside>

    <body>
        <div class="center">
            <!-- 后面这里有个循环,负责动态加载数据 -->
            <div class="card-item" 
                v-for="(item, index) in items" :key="index" 
                :id=item.styleId
                @mouseover="handleMouseOver(item)"
                @mouseout="handleMouseOut(item)"
                @click="goCloumnBlogs"
                >
                <div class="img-box">
                    <img :src=item.imgSrc class="card-img">
                </div>
                <div class="card-title">
                    <u-fold line="1">
                        <h3>{{ item.title }}</h3>
                    </u-fold>
                </div>
                <div class="card-context">
                    <u-fold line="3">
                        {{ item.context }}
                    </u-fold>
                </div>
            </div>
        </div>
    </body>
</template>

<script lang="ts" setup>
import { tr } from 'element-plus/es/locale';
import { ref, computed, onMounted } from 'vue';
import {useRouter} from 'vue-router'

interface ItemData {
    imgSrc: string;
    title: string;
    context: string;
    styleId: string;
}
const items = ref<ItemData[]>([
    { imgSrc: "./../static/image/card1.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card2.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card3.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card2.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card1.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card2.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card3.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card1.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card1.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card2.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card3.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card2.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card1.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card2.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card3.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card1.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card2.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card3.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card2.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card1.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card2.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
    { imgSrc: "./../static/image/card3.png", title: "Java", context: "Java是一种通用的,基于类的,面向对象的编程语言。", styleId: "up" },
]);

//当前动画是否执行完毕
const going = ref(false);
const router = useRouter()

const goCloumnBlogs =()=>{
  router.push(
        {
            path:'/cloumnBlogs'
        }
    );
}


// 得到指定的在可视区域内的元素
async function traverseVisibleElements(classSelect:string,doing:Function) {


  if(going.value!=false){
    return
  }
  going.value = true;
  const elements = document.querySelectorAll(classSelect);

  for (let i = 0; i < elements.length; i++) {
    const element = elements[i];
    const rect = element.getBoundingClientRect();

    if (
      rect.top >= 0 &&
      rect.left >= 0 &&
      rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
      rect.right <= (window.innerWidth || document.documentElement.clientWidth)
    ) {
    //   console.log('元素在屏幕可视区域内:', element);
     await doing(element,i)

    }
  }

  going.value = false;
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

//按照周期修改元素属性,实现元素周期放大的效果
async function flowUp(element:Element,index){
    
    let sleepTime = Math.abs(Math.sin(((index*Math.PI)/10))*1000)
    element.id = "down"
    await sleep(sleepTime)
    element.id = "up"
    console.log(sleepTime)
}

// 计算每个 item 的初始位置和周期函数值
onMounted(() => {
  traverseVisibleElements(".card-item",flowUp)
  setInterval(() => {
    traverseVisibleElements(".card-item",flowUp)
  },1500); // 刷新间隔
}
);

// 鼠标悬停时取消特效
const handleMouseOver = (item:ItemData) => {
  item.styleId='down'
};

const handleMouseOut = (item:ItemData) => {
    item.styleId='up'
};


</script>

<style scoped>

.Official{
  position: fixed;
  left: 30px;
  top: 200px;
  height: 80px;
  width: 80px;
}
.Private{
  position: fixed;
  height: 80px;
  width: 80px;
  left: 20px;
  top: 300px;
}

.card-context {
    width: 100%;
    height: 100px;
}


.card-title {
    height: 50px;
    width: 100%;
}

.card-img {
    width: 100%;
    height: 150px;
    padding: 2px;
}

.img-box {

    width: 100%;
    height: 150px;
    overflow: hidden;
}

.card-img:hover {
    animation: move .5s linear forwards;
}

#up {
    
    /* 盒子阴影 */
    box-shadow: 4px 20px 40px 5px rgba(6, 100, 224, 0.1);
    /* 盒子向上移动效果,改变上外边距 */
    margin-top: 26px;
    transform: scale(1.1);

}

#down{
    animation: move .2s ease-in reverse;
}

@keyframes move {
    0% {
        transform: scale(1);
    }

    100% {
        transform: scale(1.1);
    }
}


.card-item {
    
    cursor: pointer;
    width: 150px;
    margin-top: 30px;
    margin-bottom: 30px;
    display: flex;
    flex-direction: column;
    background: whitesmoke;
    height: 250px;
    justify-content: center;
    align-items: center;
    border-radius: 10px;
    transition: all 0.5s ease-in;
}


.card-item:hover {
    /* 盒子阴影 */
    box-shadow: 4px 20px 40px 5px rgba(4, 59, 137, 0.5);
    /* 盒子向上移动效果,改变上外边距 */
    margin-top: 26px;
    transform: scale(1.1);
}

.center {

    width: 75%;
    align-content: flex-start;
    margin: 20px auto;
    display: flex;
    column-gap: 40px;
    flex-flow: wrap;
}

body {

    width: 96%;
    margin: 0 auto;
}
</style>

总结

okey,水完了一篇,嘿嘿~ 后面我们再挑战一下几天写个推荐框架去玩玩~。后面俺们再转golang去。Java这条路,钱给的不够啊~

相关推荐
码事漫谈13 分钟前
解决 Anki 启动器下载错误的完整指南
前端
im_AMBER33 分钟前
Web 开发 27
前端·javascript·笔记·后端·学习·web
蓝胖子的多啦A梦1 小时前
低版本Chrome导致弹框无法滚动的解决方案
前端·css·html·chrome浏览器·版本不同造成问题·弹框页面无法滚动
玩代码1 小时前
vue项目安装chromedriver超时解决办法
前端·javascript·vue.js
訾博ZiBo1 小时前
React 状态管理中的循环更新陷阱与解决方案
前端
StarPrayers.2 小时前
旅行商问题(TSP)(2)(heuristics.py)(TSP 的两种贪心启发式算法实现)
前端·人工智能·python·算法·pycharm·启发式算法
一壶浊酒..2 小时前
ajax局部更新
前端·ajax·okhttp
DoraBigHead3 小时前
React 架构重生记:从递归地狱到时间切片
前端·javascript·react.js
彩旗工作室3 小时前
WordPress 本地开发环境完全指南:从零开始理解 Local by Flywhee
前端·wordpress·网站
iuuia4 小时前
02--CSS基础
前端·css