Vue implements several regularly arranged small boxes to make them change color when clicked, and at the same time, the animation moves the shadow and the big box follows its middle position

Tip: All the codes of the demo are attached at the end of the article, you can skip the browsing directly if necessary

function display:

Dynamic click movement of the small box


personal thoughts

  1. Get the position of the corresponding small box first, and change the color of the small box
  2. Set the width of the shadow box (here set to the width of five small boxes)
  3. Get the position and width of the small box, and calculate the position of the shadow box
  4. It is judged by the location conditions of the small boxes clicked, which are the first three small boxes, the last three small boxes and other small boxes in the middle position (to avoid the situation where the shadow box is pushed out of the screen, for example, there are 20 small boxes, when the first three small boxes are clicked) When there are 1, 2, and 3 boxes, the shadow box should always be close to the left border, and the last three boxes are the same)

提示:以下是本篇文章正文内容,若有缺漏之处欢迎补充

1. Data structure

需要用require将图片的相对路径包起来才能显示图片,否则效果会像视频中第三个图片一样

Because in JavaScript, using require is a common way to load modules or files. When you use a relative path to load an image, if require is not used, the browser will try to resolve the relative path of the image based on the URL of the current page, which may cause the image not to be found or to load incorrectly.
Using require can ensure that the code works normally in the Node.js environment, and it can also prevent some potential security issues. For example, using require can prevent injection attacks because it only allows you to refer to files that already exist in the local file system, while Instead of dynamically loading files from the web. In addition, using require ensures that your code is portable and easy to maintain, because you only need to change the location of the file without modifying the path information in the code.

dataArray: [
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-01'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-02'
                },
                {
    
    
                    url: './images/excel.jpg',//不会显示
                    name: 'abcd-03'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-04'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-05'
                },
                {
    
    
                    url: require('./images/excel.jpg'),
                    name: 'abcd-06'
                },
                {
    
    
                    url: require('./images/excel.jpg'),
                    name: 'abcd-07'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-08'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-09'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-10'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-11'
                },
                {
    
    
                    url: require('./images/excel.jpg'),
                    name: 'abcd-12'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-13'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-14'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-15'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-16'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-17'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-18'
                },
                {
    
    
                    url: require('./images/excel.jpg'),
                    name: 'abcd-19'
                },
                {
    
    
                    url: require('./images/excel.jpg'),
                    name: 'abcd-20'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-21'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-22'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-23'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-24'
                },
],

Two, dom structure

Use a loop to traverse the item items, and give each item an inconsistent id name (:id="'menuOnly'+index"), so that you can get the corresponding item for operation later

<div class="bottom-class">
            <div class="shadow-class" id="pic"></div>
            <div class="outbox-class">
                <div v-for="(item,index) in dataArray" :key="index" :id="'menuOnly'+index" @click="selectOnlyFileV2(index,item)" class="box-class">
                    <div class="state-class">
                        <img v-bind:src="item.url" alt="" style="width: 85%; height: 85%">
                    </div>
                    <div class="stationnum-class">
                        {
   
   {item.name.slice(item.name.length-2,item.name.length)}}
                    </div>
                </div>
            </div>
</div>

Three, js part

1. Initialize the read data

The code is as follows (example):

mounted() {
    
    
    this.selectOnlyFileV2(0, this.dataArray[0]);//默认初始为第一个
},

2.method method

Get the corresponding index and item in the click event

selectOnlyFileV2(i, item) {
    
    
            /**这里编辑操作代码 */
            // this.handleClickV1(i);
            this.handleClickV2(i);
            // this.handleClickV3(i);
},

1. handleClickV1() method

Click and move the shadow box

handleClickV1(i) {
    
    
            window.requestAnimationFrame(function () {
    
    //不需要等待异步执行完成--会导致与.shadow-class不同步,弃用
                $("#menuOnly" + i).addClass("select").siblings().removeClass("select");
            });
            setTimeout(() => {
    
    
                $(".shadow-class").width($("#menuOnly0").outerWidth() * 5);
                // $("#menuOnly" + i).addClass("select").siblings().removeClass("select");
                if (i < 3) {
    
    
                    var left = $("#menuOnly0").offset().left;
                    $(".shadow-class").offset({
    
     left: left })
                } else if (i >= (this.dataArray.length - 3)) {
    
    
                    // 计算出 .shadow-class 盒子的位置
                    var left = $("#menuOnly" + (this.dataArray.length - 1)).offset().left - ($("#menuOnly0").outerWidth() * 4);
                    $(".shadow-class").offset({
    
     left: left });
                } else {
    
    
                    var left = $("#menuOnly" + i).offset().left - (($("#menuOnly0").outerWidth()) * 2);
                    $(".shadow-class").offset({
    
     left: left })
                }
            }, 200);
},

2. handleClickV2() method - this method is called in the video

Move the shadow box, add animation movement - this method is to change the color of the small box first, and then move the shadow box

        handleClickV2(i) {
    
    
            setTimeout(() => {
    
    //需要用延对dom进行操作
                const menuItemWidth = $("#menuOnly0").outerWidth(); // 单个小盒子的宽度
                const shadowWidth = menuItemWidth * 5; // 大盒子的宽度为小盒子的五倍
                const shadow = $(".shadow-class"); // 大盒子元素
                const menuItem = $(`#menuOnly${
      
      i}`); // 点击的小盒子元素
                $(".shadow-class").width($("#menuOnly0").outerWidth() * 5);
                $("#menuOnly" + i).addClass("select").siblings().removeClass("select");
                if (i < 3) {
    
    
                    var left = 0;
                    shadow.animate({
    
     left }, 500);
                } else if (i >= (this.dataArray.length - 3)) {
    
    
                    // 若i为后三项,则直接定shadow-class以倒数第三项为中心
                    var left = Math.min(($(window).width() - shadowWidth, ($(`#menuOnly${
      
      this.dataArray.length - 3}`).offset().left - (menuItemWidth * 2))) - $("#menuOnly0").offset().left);
                    shadow.animate({
    
     left }, 500);
                } else {
    
    
                    var left = Math.min(($(window).width() - shadowWidth, (menuItem.offset().left - (menuItemWidth * 2))) - $("#menuOnly0").offset().left);
                    shadow.animate({
    
     left }, 500);
                }
            }, 200);
        },

3. handleClickV3 () method

Move the shadow box, adding animation movement - this method is to move the shadow box first, and then change the color of the clicked small box after the operation is completed

handleClickV3(i) {
    
    
            setTimeout(() => {
    
    //需要用延对dom进行操作
                const menuItemWidth = $("#menuOnly0").outerWidth(); // 单个小盒子的宽度
                const shadowWidth = menuItemWidth * 5; // 大盒子的宽度为小盒子的五倍
                const shadow = $(".shadow-class"); // 大盒子元素
                const menuItem = $(`#menuOnly${
      
      i}`); // 点击的小盒子元素
                $(".shadow-class").width($("#menuOnly0").outerWidth() * 5);
                if (i < 3) {
    
    
                    // 若i为前三项,则直接使阴影盒子的left定位在0的位置上
                    var left = 0;
                    shadow.animate({
    
    //这种方式小盒子背景显示会比较慢
                        left
                    }, {
    
    
                        duration: 500,
                        complete: function () {
    
    
                            $("#menuOnly" + i).addClass("select").siblings().removeClass("select");
                        }
                    });
                } else if (i >= (this.dataArray.length - 3)) {
    
    
                    // 若i为后三项,则直接定shadow-class以倒数第三项为中心
                    var left = Math.min(($(window).width() - shadowWidth, ($(`#menuOnly${
      
      this.dataArray.length - 3}`).offset().left - (menuItemWidth * 2))) - $("#menuOnly0").offset().left);
                    shadow.animate({
    
    
                        left
                    }, {
    
    
                        duration: 500,
                        complete: function () {
    
    
                            $("#menuOnly" + i).addClass("select").siblings().removeClass("select");
                        }
                    });
                } else {
    
    
                    var left = Math.min(($(window).width() - shadowWidth, (menuItem.offset().left - (menuItemWidth * 2))) - $("#menuOnly0").offset().left);
                    shadow.animate({
    
    
                        left
                    }, {
    
    
                        duration: 500,
                        complete: function () {
    
    
                            $("#menuOnly" + i).addClass("select").siblings().removeClass("select");
                        }
                    });
                }
            }, 200);
},

4. Similarities and differences between .offset() and .animate()

offset()andanimate()are two methods in the jQuery library. They can both be used 处理 HTML 元素的位置和动画, but there are some differences and similarities.

Similarities:
Both can be used to change the position and animation effects of elements.
Both can add CSS styles or attributes on elements.
Difference:
The .offset() method is used to get or set the coordinate position of the element relative to the document, while the .animate() method is used to create animation effects.
The .offset() method can only change the position of the element, while the .animate() method can also change the size, transparency and other properties of the element.
The .animate() method can set the duration of the animation effect and the callback function after completion, while the .offset() method has no such option.

In general, the .offset() method is more suitable for static page layouts, while the .animate() method is more suitable for animation effects in dynamic interactive pages.

5. The similarities and differences between outerWidth() and width()

outerWidth()andwidth()are used for 获取元素宽度的 jQuery 方法.

Difference:
The outerWidth() method returns the entire width including the padding and border of the element.
The width() method only returns the content width of the element.

In general, if a border and padding are set in the CSS style of an element, the calculated outerWidth() will be larger than width(). Below is an example:

<div id="myElement" style="width: 200px; border: 2px solid black; padding: 10px;">
  This is some content.
</div>

Using $('#myElement').outerWidth() will return 224, because the content width of this element is 200px, plus a 2px border on the left and right sides and a 10px inner margin, the total width is 200 + 2 2 + 2 10 = 224.

Using $('#myElement').width() will only return a content width of 200, excluding borders and padding.

Similarity:
Both methods can accept an optional Boolean type parameter, indicating whether to include margin, and the default is not included. If this parameter is set to true, then the returned width will include the value of margin.


all codes

<!-- 若干个规则排列的小盒子点击时使其变色同时动画移动阴影大盒子跟随在其中间位置 -->
<template>
    <div class="big-class">
        <div class="bottom-class">
            <div class="shadow-class" id="pic"></div>
            <div class="outbox-class">
                <div v-for="(item,index) in dataArray" :key="index" :id="'menuOnly'+index" @click="selectOnlyFileV2(index,item)" class="box-class">
                    <div class="state-class">
                        <img v-bind:src="item.url" alt="" style="width: 85%; height: 85%">
                    </div>
                    <div class="stationnum-class">
                        {
    
    {
    
    item.name.slice(item.name.length-2,item.name.length)}}
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    
    
    components: {
    
    },
    name: "movedemo",
    data() {
    
    
        return {
    
    
            dataArray: [
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-01'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-02'
                },
                {
    
    
                    url: './images/excel.jpg',//不会显示
                    name: 'abcd-03'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-04'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-05'
                },
                {
    
    
                    url: require('./images/excel.jpg'),
                    name: 'abcd-06'
                },
                {
    
    
                    url: require('./images/excel.jpg'),
                    name: 'abcd-07'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-08'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-09'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-10'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-11'
                },
                {
    
    
                    url: require('./images/excel.jpg'),
                    name: 'abcd-12'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-13'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-14'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-15'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-16'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-17'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-18'
                },
                {
    
    
                    url: require('./images/excel.jpg'),
                    name: 'abcd-19'
                },
                {
    
    
                    url: require('./images/excel.jpg'),
                    name: 'abcd-20'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-21'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-22'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-23'
                },
                {
    
    
                    url: require('./images/popo.jpg'),
                    name: 'abcd-24'
                },
            ],
        };
    },
    props: {
    
    },
    computed: {
    
    },
    mounted() {
    
    
        this.selectOnlyFileV2(0, this.dataArray[0]);//默认初始为第一个
    },
    methods: {
    
    
        selectOnlyFileV2(i, item) {
    
    
            /**这里存操作代码 */
            // this.handleClickV1(i);
            this.handleClickV2(i);
            // this.handleClickV3(i);
        },
        // 点击并移动阴影盒子
        handleClickV1(i) {
    
    
            window.requestAnimationFrame(function () {
    
    //不需要等待异步执行完成--会导致与.shadow-class不同步,弃用
                $("#menuOnly" + i).addClass("select").siblings().removeClass("select");
            });
            setTimeout(() => {
    
    
                $(".shadow-class").width($("#menuOnly0").outerWidth() * 5);
                // $("#menuOnly" + i).addClass("select").siblings().removeClass("select");
                if (i < 3) {
    
    
                    var left = $("#menuOnly0").offset().left;
                    $(".shadow-class").offset({
    
     left: left })
                } else if (i >= (this.dataArray.length - 3)) {
    
    
                    // 计算出 .shadow-class 盒子的位置
                    var left = $("#menuOnly" + (this.dataArray.length - 1)).offset().left - ($("#menuOnly0").outerWidth() * 4);
                    $(".shadow-class").offset({
    
     left: left });
                } else {
    
    
                    var left = $("#menuOnly" + i).offset().left - (($("#menuOnly0").outerWidth()) * 2);
                    $(".shadow-class").offset({
    
     left: left })
                }
            }, 200);
        },
        // 移动阴影盒子,加了动画移动-此方法是先给小盒子变色,再移动阴影盒子
        handleClickV2(i) {
    
    
            setTimeout(() => {
    
    //需要用延对dom进行操作
                const menuItemWidth = $("#menuOnly0").outerWidth(); // 单个小盒子的宽度
                const shadowWidth = menuItemWidth * 5; // 大盒子的宽度为小盒子的五倍
                const shadow = $(".shadow-class"); // 大盒子元素
                const menuItem = $(`#menuOnly${
      
      i}`); // 点击的小盒子元素
                $(".shadow-class").width($("#menuOnly0").outerWidth() * 5);
                $("#menuOnly" + i).addClass("select").siblings().removeClass("select");
                if (i < 3) {
    
    
                    var left = 0;
                    shadow.animate({
    
     left }, 500);
                } else if (i >= (this.dataArray.length - 3)) {
    
    
                    // 若i为后三项,则直接定shadow-class以倒数第三项为中心
                    var left = Math.min(($(window).width() - shadowWidth, ($(`#menuOnly${
      
      this.dataArray.length - 3}`).offset().left - (menuItemWidth * 2))) - $("#menuOnly0").offset().left);
                    shadow.animate({
    
     left }, 500);
                } else {
    
    
                    var left = Math.min(($(window).width() - shadowWidth, (menuItem.offset().left - (menuItemWidth * 2))) - $("#menuOnly0").offset().left);
                    shadow.animate({
    
     left }, 500);
                }
            }, 200);
        },
        // 移动阴影盒子,加了动画移动-此方法是先移动阴影盒子,操作结束后在给点击的小盒子变色
        handleClickV3(i) {
    
    
            setTimeout(() => {
    
    //需要用延对dom进行操作
                const menuItemWidth = $("#menuOnly0").outerWidth(); // 单个小盒子的宽度
                const shadowWidth = menuItemWidth * 5; // 大盒子的宽度为小盒子的五倍
                const shadow = $(".shadow-class"); // 大盒子元素
                const menuItem = $(`#menuOnly${
      
      i}`); // 点击的小盒子元素
                $(".shadow-class").width($("#menuOnly0").outerWidth() * 5);
                if (i < 3) {
    
    
                    // 若i为前三项,则直接使阴影盒子的left定位在0的位置上
                    var left = 0;
                    shadow.animate({
    
    //这种方式小盒子背景显示会比较慢
                        left
                    }, {
    
    
                        duration: 500,
                        complete: function () {
    
    
                            $("#menuOnly" + i).addClass("select").siblings().removeClass("select");
                        }
                    });
                } else if (i >= (this.dataArray.length - 3)) {
    
    
                    // 若i为后三项,则直接定shadow-class以倒数第三项为中心
                    var left = Math.min(($(window).width() - shadowWidth, ($(`#menuOnly${
      
      this.dataArray.length - 3}`).offset().left - (menuItemWidth * 2))) - $("#menuOnly0").offset().left);
                    shadow.animate({
    
    
                        left
                    }, {
    
    
                        duration: 500,
                        complete: function () {
    
    
                            $("#menuOnly" + i).addClass("select").siblings().removeClass("select");
                        }
                    });
                } else {
    
    
                    var left = Math.min(($(window).width() - shadowWidth, (menuItem.offset().left - (menuItemWidth * 2))) - $("#menuOnly0").offset().left);
                    shadow.animate({
    
    
                        left
                    }, {
    
    
                        duration: 500,
                        complete: function () {
    
    
                            $("#menuOnly" + i).addClass("select").siblings().removeClass("select");
                        }
                    });
                }
            }, 200);
        },
    }
}
</script>
<style scoped>
.big-class{
    
    
    width: 100%;
    height: 100%;
    background: #ced5e3;
}
/* 底部缩略样式 */
.bottom-class {
    
    
    width: 100%;
    height: 10%;
    /* border: 1px solid red; */
    box-sizing: border-box;
    position: absolute;
    bottom: 15px;
    right: 0;
}
.outbox-class {
    
    
    height: 83%;
    display: flex;
    margin-top: 0.55%;
}
.box-class {
    
    
    flex: 1;
    border: 0.5px solid #32c4fd;
    /* border: 1px solid #a7a7a7; */
    z-index: 99;
    color: #fff;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
}
.box-class:hover {
    
    
    cursor: pointer;
    box-shadow: 0 0 25px 10px rgba(43, 177, 231, 0.2);
}
.shadow-class {
    
    
    /* width: 20%; */
    height: 100%;
    /* border: 1px solid yellow; */
    box-sizing: border-box;
    position: absolute;
    background: #3896d3;
    opacity: 0.2;
}
.shadow-class:hover {
    
    
    cursor: pointer;
}
.select {
    
    
    color: #2bb1e7;
    background: #346671;
}
</style>

Guess you like

Origin blog.csdn.net/weixin_42676530/article/details/130502864