进行组件开发时我们不必依赖于任何框架,我们只需要使用原生JS,实现指向性,目标性极强的逻辑,比如我们开发轮播图组件,我们不需要复杂的运动框架,更不必复杂的选择器轮子。
组件的哲学和通用轮子不一样。通用轮子,要把所有浏览器、所有属性都要封装进来,注重复用、易用。组件开发只针对特定功能,下面是我写的一个简单的轮播图组件。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; } img { border: none; } .carousel { 560px; height: 300px; margin: 100px auto; border: 1px solid #000; position: relative; overflow: hidden; } .carousel .imageList ul { list-style: none; position: relative; } .carousel .imageList ul li { position: absolute; top: 0; left: 560px; 560px; height: 300px; } .carousel .imageList ul li.first { left: 0; } .btns a { position: absolute; 40px; height: 40px; top: 50%; margin-top: -20px; background-color: yellow; z-index: 999; } .btns a.leftBtn { left: 10px; } .btns a.rightBtn { right: 10px; } .circles { position: absolute; bottom: 10px; right: 10px; 150px; height: 18px; } .circles ol { list-style: none; } .circles ol li { float: left; 18px; height: 18px; margin-right: 10px; border-radius: 50%; background-color: pink; cursor: pointer; } .circles ol li.cur { background-color: purple; } </style> </head> <body> <div class="carousel" id="carousel"> </div> <script src='slider.js'></script> <script> var slider = new Slider({ 'containerId': 'carousel' }) </script> </body> </html>
// 需要接收一个JSON对象 // @param containerId 盒子ID // @param time 动画执行时长 // @param interval 动画间隔 // @param Tween 动画缓动公式 // @param autoPlay 动画是否自动轮播 // @param autoPlayTime 动画自动轮播时长 // 这里在封装组件时可以根据需求,添加任意参数比如是否不需要左右按钮,是否不需要圆点按钮。。。 function Slider(dataJson) { if (!dataJson) { throw new Error('请传入参数'); } this.container = document.querySelector('#' + dataJson.containerId) ? document.querySelector('#' + dataJson.containerId) : null; this._init(); this.leftBtn = this.container.querySelector('.leftBtn'); this.rightBtn = this.container.querySelector('.rightBtn'); this.imgList = this.container.querySelectorAll('.imageList li'); this.circleList = this.container.querySelectorAll('.circles li'); this.time = dataJson.time || 1000; this.interval = dataJson.interval || 10; this.Tween = dataJson.Tween || function(t, b, c, d) { if ((t /= d / 2) < 1) return c / 2 * t * t * t * t * t + b; return c / 2 * ((t -= 2) * t * t * t * t + 2) + b; } this.autoPlay = dataJson.autoPlay || 1; this.autoPlayTime = dataJson.autoPlayTime || 1800; this.now = 0; this.oldNow = NaN; this.timer = null; this.timer1 = null; this._bindEvent(); this._auto(); } Slider.prototype._init = function() { this.container.innerHTML = [ "<div class='btns'>", " <a href='javascript:;' class='leftBtn'></a>", " <a href='javascript:;' class='rightBtn'></a>", "</div>", "<div class='imageList'>", " <ul>", " <li class='first'><a href='#'><img src='images/0.jpg' alt='' /></a></li>", " <li><a href='#'><img src='images/1.jpg' alt='' /></a></li>", " <li><a href='#'><img src='images/2.jpg' alt='' /></a></li>", " <li><a href='#'><img src='images/3.jpg' alt='' /></a></li>", " <li><a href='#'><img src='images/4.jpg' alt='' /></a></li>", " </ul>", "</div>", "<div class='circles'>", " <ol>", " <li class='cur'></li>", " <li></li>", " <li></li>", " <li></li>", " <li></li>", " </ol>", "</div>" ].join(""); }; // 添加滚动下一张方法 Slider.prototype._next = function() { // 如果动画未执行完则直接退出 if (this.timer) { return; }; this.oldNow = this.now; this.now++; if (this.now > this.imgList.length - 1) { this.now = 0; } this._animate([{ 'obj': this.imgList[this.oldNow], 'startPosition': 0, 'endPosition': -560, }, { 'obj': this.imgList[this.now], 'startPosition': 560, 'endPosition': 0, }]); this._styleCut(this.now); }; // 添加滚动上一张方法 Slider.prototype._prev = function() { if (this.timer) { return; } this.oldNow = this.now; this.now--; if (this.now < 0) { this.now = this.imgList.length - 1; } this._animate([{ 'obj': this.imgList[this.oldNow], 'startPosition': 0, 'endPosition': 560, }, { 'obj': this.imgList[this.now], 'startPosition': -560, 'endPosition': 0, }]); this._styleCut(this.now); }; // 添加goto方法 Slider.prototype._goto = function(idx) { if (this.timer) { return; } this.oldNow = this.now; if (idx > this.now) { this.now = idx; this._animate([{ 'obj': this.imgList[this.oldNow], 'startPosition': 0, 'endPosition': -560, }, { 'obj': this.imgList[this.now], 'startPosition': 560, 'endPosition': 0, }]) } else if (idx < this.now) { this.now = idx; this._animate([{ 'obj': this.imgList[this.oldNow], 'startPosition': 0, 'endPosition': 560, }, { 'obj': this.imgList[this.now], 'startPosition': -560, 'endPosition': 0, }]) } }; // 添加动画函数 Slider.prototype._animate = function(dataArr) { // 声明当前帧 var currentFrame = 0; // 声明总帧率 var allFrame = this.time / this.interval; // 计算变化量 var delta = dataArr[0].endPosition - dataArr[0].startPosition; var self = this; clearInterval(this.timer) this.timer = setInterval(function() { currentFrame++; if (currentFrame >= allFrame) { clearInterval(self.timer); self.timer = null; } // 老图移出新图进入 for (var i = 0; i < dataArr.length; i++) { dataArr[i].obj.style.left = self.Tween(currentFrame, dataArr[i]['startPosition'], delta, allFrame) + 'px'; } }, this.interval) } // 圆点样式切换 Slider.prototype._styleCut = function(idx) { for (var i = 0; i < this.circleList.length; i++) { this.circleList[i].className = ""; } this.circleList[idx].className = "cur"; }; // 是否自动轮播 Slider.prototype._auto = function() { // 如果用户不要自动轮播直接退出 if (!this.autoPlay) { return; } var self = this; this.timer1 = setInterval(function() { self._next(); }, this.autoPlayTime) }; // 事件绑定 Slider.prototype._bindEvent = function() { var self = this; this.rightBtn.addEventListener('click', function() { self._next(); }); this.leftBtn.addEventListener('click', function() { self._prev(); }); // 圆点按钮绑定 for (var i = 0; i < this.circleList.length; i++) { this.circleList[i].index = i; this.circleList[i].addEventListener('click', function() { // 不允许用户连续点击不同的按钮 if (self.timer) { return; } self._goto(this.index); self._styleCut(this.index); }) } this.container.addEventListener('mouseover', function() { clearInterval(self.timer1); }); this.container.addEventListener('mouseout', function() { self._auto(); }) };