轮播图组件化 | 青训营笔记

101 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
相信大家在日常写项目中,都会遇到写轮播图的问题,或许我们选择使用一些现成的轮播图的库去实现轮播图的功能,又或者是我们选择自己手写一个。但是在手写的时候,大家是否思考过我们可以把轮播图写成一个组件的样子,这样在我们日后使用的时候也是非常方便的

轮播图组件封装

下面我们封装一个轮播图组件,主要功能有自动轮播,点击左右切换按钮可跳转上一张或是下一张

思考一下,在封装这个组件之前,我们要做哪些准备工作?

  • 结构设计
  • 展现效果
  • 行为设计
    • API(功能)
    • Event(控制流)
  • ......

本篇笔记重点在对API和Event的记录

API部分

我们思考一下,完成一个自动播放轮播图需要哪些功能

  • 获取当前展示图片序号
  • 播放下一张
  • 播放上一张
  • 自动播放
  • 停止自动播放

这样我们就可以让这个轮播图自动播放起来

class Slider {
    constructor(sliderBoxId, imageData) {
        this.container = document.getElementById(sliderBoxId);
        this.timer = undefined;
        this.items = this.container.querySelectorAll('.slider-list_item,.slider-list_item-selected');
    }

    autoPlayStart() {
        this.autoPlayStop()
        this.timer = setInterval(() => {
            this.goToNext()
        }, 1500)
    }

    autoPlayStop() {
        clearInterval(this.timer)
    }

    getSelectedIdx() {
        const item = document.querySelector('.slider-list_item-selected')
        return Array.from(this.items).indexOf(item); 
    }

    goToNext() { 
        const selectedIdx = this.getSelectedIdx()
        const nextSelectedIdx = (selectedIdx + 1) % (this.items.length);
        if (selectedIdx === -1) {
            this.container.querySelectorAll('.slider-list_item,.slider-list_item-selected')[nextSelectedIdx].className = 'slider-list_item-selected'
        }
        else {
            this.items[selectedIdx].className = 'slider-list_item';
            this.items[nextSelectedIdx].className = 'slider-list_item-selected'
        }

    }
    goToPre() { 
        const selectedIdx = this.getSelectedIdx()
        const preSelectedIdx = (selectedIdx + 4) % (this.items.length);
        this.items[selectedIdx].className = 'slider-list_item';
        this.items[preSelectedIdx].className = 'slider-list_item-selected'

    }
}

切换按钮

我们可以在上面代码中加入下面部分,记得要先获取按钮元素,本处就不展示了

    goNextBtnWork() {
        this.goNextBtn.addEventListener('click', () => {
            this.goToNext(this.container, this.items);
        })
    }

    goPreBtnWork() {
        this.goPreBtn.addEventListener('click', () => {
            this.goToPre(this.container, this.items);
        })
    }

再想想有没有什么改进的地方

1.插件化
我们可以将切换按钮变成独立的插件插入到我们的轮播图中,将插件与组件之间通过依赖注入的方式建立联系

//在js文件中写入以下内容
class btnPrePlugin {
    action(slider) {
        const preBtn = slider.container.querySelector(`.goPreBtn`);
        if (preBtn) {
            preBtn.addEventListener('click', (e) => {
                slider.autoPlayStop()
                slider.goToPre(slider.container, slider.items);
                slider.autoPlayStart()
                e.preventDefault()
            })
        }
    }
}
class btnNextPlugin {
    action(slider) {
        const nextBtn = slider.container.querySelector(`.goNextBtn`);
        if (nextBtn) {
            nextBtn.addEventListener('click', (e) => {
                slider.autoPlayStop()
                slider.goToNext(slider.container, slider.items);
                slider.autoPlayStart()
                e.preventDefault()
            })
        }
    }
}

2.模板化
我们再想想还有什么能优化的?我们可以将HTML模板化,更易于扩展 下面是将图片展示列表的部分模板化

class Slider {
    constructor(sliderBoxId, imageData) {
        this.container = document.getElementById(sliderBoxId);
        this.timer = undefined;
        this.imgs = imageData.data
        this.container.innerHTML += this.render()
        this.items = this.container.querySelectorAll('.slider-list_item,.slider-list_item-selected');
    }

    render() {
        const sliderList = this.imgs.map(img =>
            `
            <li class="slider-list_item">
                <img src="${img}" />
            </li>
            `.trim())
        return `<ul>${sliderList.join('')}</ul>`
    }
    ...
 }

同样我们可以对按钮插件进行同样操作

render() {
        return `<button class='slider-list-btn goNext(Pre)Btn'>></button>`
    }

收尾部分

const slider = new Slider('my-slider', imageData)
const pre = new btnPrePlugin();
const next = new btnNextPlugin()
slider.registerAction(pre, next)
slider.autoPlayStart()

这样我们就可以完成一个简单的轮播图组件啦!

写在结尾

这次月影老师对于js讲解的课程让我受益匪浅,对于编写js代码有了一个全新的视角,很开心能够学到今天的知识,并自己尝试写了一个很简单的demo,有写的不好的地方希望大家能够帮我指出,感谢各位大佬!