Web开发:图片九宫格与非九宫格动态切换效果(HTML、CSS、JavaScript)

目录

一、业务需求

二、实现思路

三、实现过程

1、基础页面

2、图片大小调整

3、图片位置调整

4、鼠标控制切换

5、添加过渡

四、完整代码


一、业务需求

默认显示基础图片;

当鼠标移入,使用九宫格效果展示图片;

当鼠标离开,使用非九宫格效果展示图片;

【鼠标移入,九宫格展示效果】

【鼠标离开,非九宫格展示效果(默认效果)】

【视频效果】

图片九宫格与非九宫格动态切换效果

二、实现思路

  • 准备一个Grid布局,添加 3 * 3 = 9 个Grid元素;
  • 每个Grid元素的背景均设为该目标图片;
  • 调整图片大小,设置每个背景图的宽高为单个Grid元素宽高的三倍;
  • 调整图片位置,设置每个Grid元素显示对应位置的图片内容,能够拼成一个完整的图片;
  • 通过对Grid元素间隙的控制,在视觉上实现九宫格和非九宫格的切换效果;

三、实现过程

1、基础页面

(1)HTML布局

分析需求可知,

  • 布局内容非常简单,只需要1个Grid容器【.grid-container 】和9个Grid元素【.grid-item】;
  • 可以再给Grid容器添加一个父盒子【.container】,使图片的九宫格在父盒子中居中显示;
html 复制代码
<body>
    <div class="container">
        <div class="grid-container">
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
        </div>
    </div>
</body>

(2)CSS样式

  • 设置【.container 】元素为Flex布局,是子元素【.grid-container】水平垂直居中显示(在.container元素中水平垂直居中显示);
  • Grid容器【.grid-container 】中的9个Grid元素【.grid-item 】,呈现【3行3列】的排列方式,并设置Grid元素的间距为10px;
  • 给每个Grid元素【.grid-item】设置背景为目标图片;
css 复制代码
<style>
    .container {
        /* 设为Flex布局 */
        display: flex;
        /* 设置子元素水平居中 */
        justify-content: center;
        /* 设置子元素垂直居中 */
        align-items: center;
        /* 设置宽度为可视窗口宽度 */
        width: 100vw;
        /* 设置高度为可视窗口高度的一半 */
        height: 50vh;
    }

    .grid-container {
        /* 设为grid布局 */
        display: grid;
        /* 子元素分为三列,列宽为100px */
        grid-template-columns: repeat(3, 100px);
        /* 子元素分为两行,行高为80px */
        grid-template-rows: repeat(3, 80px);
        /* 子元素间隔为10px */
        gap: 10px;
    }

    .grid-item {
        background-image: url("D:\\test\\girl.png");
        background-repeat: no-repeat;
        /* 先设置背景图展示出来 */
        background-size: cover;
    }
</style>

(3)现有效果

2、图片大小调整

  • 现有效果仅仅只是,给每个盒子设置了相同的图片作为背景图,显然是不符合需求的;
  • 目标效果是用"一张图片",占满九个盒子;
  • 那一张图片的宽高,就是整个9宫格【.grid-container】的宽高(除去间隙);
  • 所以背景图的宽度和高度,是单个盒子【.grid-item】宽度和高度的三倍;
css 复制代码
.grid-item {
    background-image: url("D:\\test\\girl.png");
    background-repeat: no-repeat;
    /* 先设置背景图展示出来 */
    /* background-size: cover; */

    /* 修改背景图宽高为单个盒子的3倍 */
    background-size: 300%;
}

3、图片位置调整

调整了图片大下后,图片的位置(除了第一个),其他的图片显示的位置并不符合预期;

但可以知道的是,一个盒子的背景图默认是从图片的(0, 0)位置开始渲染的;

所以,需要调整其余背景图片的位置;

  • 第 1 张图片不需要设置位置偏移;
  • 第 2 张图片需要向左偏移一个盒子的宽度(-100px);
  • 第 3 张图片需要向左偏移两个盒子的宽度(-200px);
  • 第 4 张图片不需要向左偏移,但需要向上偏移一个盒子的高度(-80px);
  • ......(以此类推)
  • 第 9 张图片需要向左偏移两个盒子的宽度(-200px),还需要向上偏移两个盒子的高度(-160px);

这里给出两种不同的解决方式,分别使用CSS和JavaScript来背景图位置的偏移量来实现效果;

(1)使用CSS实现

简单粗暴的方式,分别给每个盒子设置自己的背景位置;

css 复制代码
<style>
    ......
    .grid-item:nth-child(1){
        background-position: 0 0;
    }
    .grid-item:nth-child(2){
        background-position: -100px 0;
    }
    .grid-item:nth-child(3){
        background-position: -200px 0;
    }
    .grid-item:nth-child(4){
        background-position: 0 -80px;
    }
    .grid-item:nth-child(5){
        background-position: -100px -80px;
    }
    .grid-item:nth-child(6){
        background-position: -200px -80px;
    }
    .grid-item:nth-child(7){
        background-position: 0 -160px;
    }
    .grid-item:nth-child(8){
        background-position: -100px -160px;
    }
    .grid-item:nth-child(9){
        background-position: -200px -160px;
    }
</style>

(2)使用JavaScript实现

使用JavaScript也可以达到同样的效果,两者选其一即可;

  • 通过querySelectorAll() 方法获取所有的【.grid-item 】元素,得到数组 itemList ,其中有item[0]~item[8];循环遍历该数组,计算每个元素的行号和列号;
  • 计算每个元素的行号r :计算 i / 3 ,再向下取整,得到 0,1,2;
  • 计算每个元素的列号c :计算 i % 3 ,得到 0,1,2;
  • 行号( r ) * 元素高度(itemHeight),得到每一行的向上偏移量(取反);
  • 列号( c ) * 元素宽度(itemWidth),得到每一行的向左偏移量(取反);
  • 再将计算结果直接赋值给该元素即可(别忘了加 'px' );

注意:

  • 这里需要修改一些样式,应用CSS中的变量,需要在【body】中声明变量,在【.grid-container】中使用CSS变量;
  • 方便在JavaScript中获取定义好的变量值,设置每个元素的偏移位置;

【需要修改的CSS代码】

html 复制代码
<style>
    ......
    body {
        /* 定义CSS变量 */
        /* 定义子元素的宽度 */
        --item-width: 100px;
        /* 定义子元素的高度 */
        --item-height: 80px;
        /* 定义元素间隔 */
        --item-gap: 10px;
    }

    ......

    .grid-container {
        /* 设为grid布局 */
        display: grid;
        /* 子元素分为三列,列宽为100px */
        grid-template-columns: repeat(3, var(--item-width));
        /* 子元素分为两行,行高为80px */
        grid-template-rows: repeat(3, var(--item-height));
        /* 子元素间隔为10px */
        gap: var(--item-gap);
    }
    ......
</style>

【添加的JavaScript代码】

javascript 复制代码
<script>
    // 获取元素
    var body = document.querySelector("body");
    var container = document.querySelector(".grid-container");
    var itemList = document.querySelectorAll(".grid-item");

    // 获取CSS变量(元素的宽度、元素的高度)
    var itemWidth = parseInt(getComputedStyle(container).getPropertyValue('--item-width'));
    var itemHeight = parseInt(getComputedStyle(container).getPropertyValue('--item-height'));

    // 计算偏移量
    for (let i = 0; i < itemList.length; i++) {
        // 计算是元素位置,
        // 元素的行号(从0开始)
        const r = Math.floor(i / 3);
        // console.log(r);

        // 元素的列号(从0开始)
        const c = i % 3;
        // console.log(c);

        // 计算元素的偏移量
        const dx = -(c * itemWidth) + 'px';
        const dy = -(r * itemHeight) + 'px';

        console.log((i + 1), dx, dy);
        // 设置元素的偏移
        itemList[i].style.backgroundPosition = `${dx} ${dy}`;
    }
</script>

【实现的效果】

4、鼠标控制切换

分析需求可知:

  • 图片九宫格与非九宫格的展示,现在仅仅就变成了调整元素间隙的问题;
  • 九宫格展示,元素间隙【--item-gap: 10px;】
  • 非九宫格展示,元素间隙【--item-gap: 0;】
  • 给【.grid-container】盒子注册鼠标移入事件;当鼠标进入,设置元素间隙为10px(值可以自行定义),使用九宫格效果展示;
  • 给【.grid-container】盒子注册鼠标离开事件;当鼠标离开,设置元素间隙为0,使用非九宫格效果展示;

注意:

  • 这里需要修改CSS,调整默认的元素间距为0;
css 复制代码
body {
    /* 定义CSS变量 */
    ......
    /* 定义元素间隔 初始为0 */
    --item-gap: 0;
}

【初始效果】

【添加下列JavaScript代码】

javascript 复制代码
<script>
    // 获取元素
    var body = document.querySelector("body");
    var container = document.querySelector(".grid-container");
    ......

    // 鼠标进入,显示九宫格
    container.addEventListener('mouseenter', function () {
        // 修改CSS变量
        body.style.setProperty('--item-gap', '10px');
    })

    // 鼠标离开,不显示九宫格
    container.addEventListener('mouseleave', function () {
        // 修改CSS变量
        body.style.setProperty('--item-gap', '0');
    })
</script>

到这一步,效果基本上是可以实现了;

5、添加过渡

现有的切换效果生硬的,添加过度效果进行优化;

css 复制代码
.grid-container {
    ......
    /* 添加过渡 */
    transition: 0.6s;
}

四、完整代码

【使用CSS控制图片位置】

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图片九宫格切换展示效果</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        body {
            /* 定义CSS变量 */
            /* 定义子元素的宽度 */
            --item-width: 100px;
            /* 定义子元素的高度 */
            --item-height: 80px;
            /* 定义元素间隔 初始值*/
            --item-gap: 0;
        }

        .container {
            /* 设为Flex布局 */
            display: flex;
            /* 设置子元素水平居中 */
            justify-content: center;
            /* 设置子元素垂直居中 */
            align-items: center;
            /* 设置宽度为可视窗口宽度 */
            width: 100vw;
            /* 设置高度为可视窗口高度的一半 */
            height: 50vh;
        }

        .grid-container {
            /* 设为grid布局 */
            display: grid;
            /* 子元素分为三列,列宽为100px */
            grid-template-columns: repeat(3, var(--item-width));
            /* 子元素分为两行,行高为80px */
            grid-template-rows: repeat(3, var(--item-height));
            /* 子元素间隔为10px */
            gap: var(--item-gap);

            /* 添加过渡 */
            transition: 0.6s;

            border-radius: 6px;
            box-shadow: 0 0 6px 1px #999;
        }

        .grid-item {
            background-image: url("D:\\test\\girl.png");
            background-repeat: no-repeat;
            /* 先设置背景图展示出来 */
            /* background-size: cover; */

            /* 修改背景图宽高为单个盒子的3倍 */
            background-size: 300%;
        }

        .grid-item:nth-child(1) {
            background-position: 0 0;
        }

        .grid-item:nth-child(2) {
            background-position: calc(-1* var(--item-width)) 0;
        }

        .grid-item:nth-child(3) {
            background-position: calc(-2* var(--item-width)) 0;
        }

        .grid-item:nth-child(4) {
            background-position: 0 calc(-1* var(--item-height));
        }

        .grid-item:nth-child(5) {
            background-position: calc(-1* var(--item-width)) calc(-1* var(--item-height));
        }

        .grid-item:nth-child(6) {
            background-position: calc(-2* var(--item-width)) calc(-1* var(--item-height));
        }

        .grid-item:nth-child(7) {
            background-position: 0 calc(-2* var(--item-height));
        }

        .grid-item:nth-child(8) {
            background-position: calc(-1* var(--item-width)) calc(-2* var(--item-height));
        }

        .grid-item:nth-child(9) {
            background-position: calc(-2* var(--item-width)) calc(-2* var(--item-height));
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="grid-container">
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
        </div>
    </div>
</body>
<script>
    // 获取元素
    var body = document.querySelector("body");
    var container = document.querySelector(".grid-container");
    var itemList = document.querySelectorAll(".grid-item");

    // 鼠标进入,显示九宫格
    container.addEventListener('mouseenter', function () {
        // 修改CSS变量
        body.style.setProperty('--item-gap', '10px');

        this.style.boxShadow = "none";
        this.style.borderRadius = "0";

        itemList.forEach(el => {
            el.style.boxShadow = "0 0 6px 1px #999";
            el.style.borderRadius = "6px";
        });
    })

    // 鼠标离开,不显示九宫格
    container.addEventListener('mouseleave', function () {
        // 修改CSS变量
        body.style.setProperty('--item-gap', '0');

        this.style.boxShadow = "0 0 6px 1px #999";
        this.style.borderRadius = "6px";

        itemList.forEach(el => {
            el.style.boxShadow = "none";
            el.style.borderRadius = "0";
        });
    })
</script>

</html>

【使用JavaScript控制图片位置】

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图片九宫格切换展示效果</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        body {
            /* 定义CSS变量 */
            /* 定义子元素的宽度 */
            --item-width: 100px;
            /* 定义子元素的高度 */
            --item-height: 80px;
            /* 定义元素间隔 初始值 */
            --item-gap: 0;
        }

        .container {
            /* 设为Flex布局 */
            display: flex;
            /* 设置子元素水平居中 */
            justify-content: center;
            /* 设置子元素垂直居中 */
            align-items: center;
            /* 设置宽度为可视窗口宽度 */
            width: 100vw;
            /* 设置高度为可视窗口高度的一半 */
            height: 50vh;
        }

        .grid-container {
            /* 设为grid布局 */
            display: grid;
            /* 子元素分为三列,列宽为100px */
            grid-template-columns: repeat(3, var(--item-width));
            /* 子元素分为两行,行高为80px */
            grid-template-rows: repeat(3, var(--item-height));
            /* 子元素间隔为10px */
            gap: var(--item-gap);

            /* 添加过渡 */
            transition: 0.6s;

            border-radius: 6px;
            box-shadow: 0 0 6px 1px #999;
        }

        .grid-item {
            background-image: url("D:\\test\\girl.png");
            background-repeat: no-repeat;
            /* 先设置背景图展示出来 */
            /* background-size: cover; */

            /* 修改背景图宽高为单个盒子的3倍 */
            background-size: 300%;
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="grid-container">
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
            <div class="grid-item"></div>
        </div>
    </div>
</body>
<script>
    // 获取元素
    var body = document.querySelector("body");
    var container = document.querySelector(".grid-container");
    var itemList = document.querySelectorAll(".grid-item");

    // 获取CSS变量(元素的宽度、元素的高度)
    var itemWidth = parseInt(getComputedStyle(container).getPropertyValue('--item-width'));
    var itemHeight = parseInt(getComputedStyle(container).getPropertyValue('--item-height'));

    // 获取元素间隙
    // var itemGap = parseInt(getComputedStyle(container).getPropertyValue('--item-gap'));

    // 计算偏移量
    for (let i = 0; i < itemList.length; i++) {
        // 计算是元素位置,
        // 元素的行号(从0开始)
        const r = Math.floor(i / 3);
        // console.log(r);

        // 元素的列号(从0开始)
        const c = i % 3;
        // console.log(c);

        // 计算元素的偏移量
        const dx = -(c * itemWidth) + 'px';
        const dy = -(r * itemHeight) + 'px';

        console.log((i + 1), dx, dy);
        // 设置元素的偏移
        itemList[i].style.backgroundPosition = `${dx} ${dy}`;
    }

    // 鼠标进入,显示九宫格
    container.addEventListener('mouseenter', function () {
        // 修改CSS变量
        body.style.setProperty('--item-gap', '10px');

        this.style.boxShadow = "none";
        this.style.borderRadius = "0";

        itemList.forEach(el => {
            el.style.boxShadow = "0 0 6px 1px #999";
            el.style.borderRadius = "6px";
        });
    })

    // 鼠标离开,不显示九宫格
    container.addEventListener('mouseleave', function () {
        // 修改CSS变量
        body.style.setProperty('--item-gap', '0');

        this.style.boxShadow = "0 0 6px 1px #999";
        this.style.borderRadius = "6px";

        itemList.forEach(el => {
            el.style.boxShadow = "none";
            el.style.borderRadius = "0";
        });
    })
</script>

</html>

=========================================================================

每天进步一点点~!

期待你更好的实现方法~~!

相关推荐
瘦的可以下饭了41 分钟前
Day01-API
javascript
Nan_Shu_6141 小时前
学习:Vue (2)
javascript·vue.js·学习
一水鉴天1 小时前
整体设计 定稿 之24 dashboard.html 增加三层次动态记录体系仪表盘 之2 程序 (Q208 之1)
前端·html
亮子AI2 小时前
【css】列表的标号怎么实现居中对齐?
前端·css
一水鉴天2 小时前
整体设计 定稿 之22 dashboard.html 增加三层次动态记录体系仪表盘 之1
前端·html
一水鉴天3 小时前
整体设计 定稿 之24+ dashboard.html 增加三层次动态记录体系仪表盘 之2 程序 (Q208 之2)
开发语言·前端·javascript
二狗哈3 小时前
Cesium快速入门17:与entity和primitive交互
开发语言·前端·javascript·3d·webgl·cesium·地图可视化
GISer_Jing4 小时前
AI驱动营销增长:7大核心场景与前端实现
前端·javascript·人工智能
星光不问赶路人4 小时前
new Array() 与 Array.from() 的差异与陷阱
javascript·面试
T___T4 小时前
Vue 3 做 todos , ref 能看懂,computed 终于也懂了
前端·javascript·面试