vue手写轮播

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        #app {
            width: 1200px;
            height: 500px;
            border: 1px solid red;
            margin: 50px auto;
        }

        .swiper {
            width: 100%;
            height: 100%;
            position: relative;
            overflow: hidden;
        }

        .item {
            width: 100%;
            height: 100%;
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            z-index: 0;
            overflow: hidden;
        }

        .active {
            z-index: 2
        }

        .animating {
            transition: transform .4s ease-in-out;
        }

        .item:nth-child(1) {
            background: pink;
        }

        .item:nth-child(2) {
            background: green;
        }

        .item:nth-child(3) {
            background: blue;
        }

        .item:nth-child(4) {
            background: red;
        }

        .item:nth-child(5) {
            background: orange;
        }

        .text {
            font-size: 50px;
            text-align: center;
            color: #fff;
            line-height: 500px;
        }

        .button {
            width: 50px;
            height: 100px;
            background: #fff;
            opacity: .6;
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            z-index: 3;
        }

        .left {
            left: 20px;
        }

        .right {
            right: 20px;
        }

        .indicators {
            position: absolute;
            bottom: 0;
            left: 50%;
            transform: translateX(-50%);
            z-index: 3;
            list-style: none;
            margin: 0;
            padding: 0;
            height: 27px;
        }

        .labels {
            width: 30px;
            height: 3px;
            display: inline-block;
            padding: 12px 4px;
            list-style: none;
            margin: 0;
            opacity: 0.5;
        }

        .labels-active {
            opacity: 1;
        }

        .labels > span {
            display: block;
            width: 100%;
            height: 100%;
            background: #fff;
        }
    </style>
</head>
<body>
<div id="app"></div>
<script src="./vue.global.js"></script>
<script>
    // Composition API
    const {reactive, onMounted, effect, createApp, onRenderTriggered, computed, watch, onBeforeMount, createComponent} = Vue;

    const Item = createComponent({
        template: `<div class="item text"
                        :class="{
                        'active':data.active,
                        'animating': data.animating
                        }"
                        :style="itemStyle()">
                       <slot></slot>
                   </div>`,
        setup(props) {
            let width = 0;
            const data = reactive({
                translate: 0,
                active: false,
                animating: false
            });
            onMounted(() => {
                width = document.querySelector('.item').offsetWidth;
                translateItem(props.index, props.active, props.length, props.oldIndex);
            });
            const itemStyle = () => {
                const value = `translateX(${data.translate}px)`;
                return {
                    transform: value
                }
            };
            const calcTranslate = (index, active) => {
                return width * (index - active);
            };
            const processIndex = (index, active, length) => {
                if (active === 0 && index === length - 1) {
                    return -1;
                } else if (active === length - 1 && index === 0) {
                    return length;
                } else if (index < active - 1 && active - index >= length / 2) {
                    return length + 1;
                } else if (index > active + 1 && index - active >= length / 2) {
                    return -2;
                }
                return index;
            };
            const translateItem = (index, active, length, oldIndex) => {
                if (width === 0) {
                    return;
                }
                if (oldIndex !== undefined) {
                    data.animating = index === active || index === oldIndex;
                }
                if (index !== active && length > 2) {
                    index = processIndex(index, active, length);
                }
                data.active = index === active;
                data.translate = calcTranslate(index, active)
            };
            effect(() => {
                translateItem(props.index, props.active, props.length, props.oldIndex);
            });
            return {
                data,
                itemStyle
            }
        }
    });

    const App = {
        template: `<div class="swiper"
                        @mouseenter.stop="removeActive()"
                        @mouseleave.stop="changeActive()">
                       <Item v-for="($item, $index) in data.list"
                             :key="$index"
                             :index="$index"
                             :oldIndex="data.oldIndex"
                             :length="data.list.length"
                             :active="data.index">
                           {{$index + 1}}
                       </Item>
                       <div class="button left"
                            @click="activeLeft()">
                       </div>
                       <div class="button right"
                            @click="activeRight()">
                       </div>
                       <ul class="indicators">
                           <li class="labels"
                               :class="{'labels-active':data.index === $index}"
                               v-for="($item, $index) in data.list"
                               @mouseenter="changeLabelsActive($index)">
                               <span></span>
                           </li>
                       </ul>
                   </div>`,
        components: {Item},
        setup() {
            const data = reactive({
                list: [1, 2, 3, 4, 5],
                index: 0,
                oldIndex: undefined,
                time: 3000
            });
            watch(() => data.index, (val, oldVal) => {
                data.oldIndex = oldVal
            });
            let time = null;
            const _initTimer = (time) => {
                return setInterval(() => {
                    if (data.index < data.list.length - 1) {
                        data.index++
                    } else {
                        data.index = 0
                    }
                }, time);
            };
            onMounted(() => {
                time = _initTimer(data.time);
            });
            const changeActive = () => {
                clearInterval(time);
                time = _initTimer(data.time);
            };
            const removeActive = () => {
                clearInterval(time);
            };
            const throttle = (method, delay) => { // 节流函数
                let timer = null;
                let start = null;
                return function () {
                    let now = Date.now();
                    if (!start) {
                        start = now;
                    }
                    if (now - start > delay) {
                        method.apply(this, arguments);
                        start = now;
                    } else {
                        clearTimeout(timer);
                        timer = setTimeout(() => {
                            method.apply(this, arguments);
                        }, delay);
                    }
                }
            };
            const debounce = (method, delay) => { // 防抖函数
                let timer = null;
                let start = false;
                return function () {
                    if (!start) {
                        start = true;
                        method.apply(this, arguments);
                        timer = setTimeout(() => {
                            start = false;
                        }, delay);
                    }
                }
            };
            const activeLeft = debounce(() => {
                if (data.index > 0) {
                    data.index--
                } else {
                    data.index = data.list.length - 1
                }
            }, 300);
            const activeRight = debounce(() => {
                if (data.index < data.list.length - 1) {
                    data.index++
                } else {
                    data.index = 0
                }
            }, 300);
            const changeLabelsActive = throttle((index) => {
                data.index = index;
            }, 300);
            return {
                data,
                changeActive,
                removeActive,
                activeLeft,
                activeRight,
                changeLabelsActive
            }
        }
    };
    // 挂载
    let app = document.getElementById('app');
    createApp().mount(App, app);
</script>
</body>
</html>

  

  基于Vue3.0的CSS3动画轮播

猜你喜欢

转载自www.cnblogs.com/QQPrincekin/p/12022746.html