毕设之-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这条路,钱给的不够啊~

相关推荐
べJL1 分钟前
SVG怎么画渐变甜甜圈(进度环)
前端·css
初遇你时动了情1 分钟前
css3滚动边框特效属性 filter、inset应用
前端·css·css3
Ares码农人生26 分钟前
React 前端框架简介
前端·react.js·前端框架
小汤猿人类27 分钟前
nacos-gateway动态路由
java·前端·gateway
GISer_Jing28 分钟前
前端经典面试合集(二)——Vue/React/Node/工程化工具/计算机网络
前端·vue.js·react.js·node.js
GesLuck1 小时前
C#控件开发4—仪表盘
前端·经验分享·c#
小林爱1 小时前
【Compose multiplatform教程14】【组件】LazyColumn组件
android·前端·kotlin·android studio·框架·多平台
过往记忆7 小时前
告别 Shuffle!深入探索 Spark 的 SPJ 技术
大数据·前端·分布式·ajax·spark
高兴蛋炒饭8 小时前
RouYi-Vue框架,环境搭建以及使用
前端·javascript·vue.js
m0_748240449 小时前
《通义千问AI落地—中》:前端实现
前端·人工智能·状态模式