カルーセル(マウスカーソルの位置によって向きを変え自動移動)
マウスカーソルの位置によって向きを変え自動移動するカルーセルを実装する方法をご紹介します。
- ※ IE9以上対応。
- ※ ページ読み込み時はマウスの座標が取得できないので、方向を定めることはできません。
デモ
カルーセル要素の表示領域の半分を基準にマウスカーソルの前後で左方向、右方向にスライドします。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
サンプルコード
HTML
<div id="carousel">
<ul>
<li>1</li>
<li class="even">2</li>
<li>3</li>
<li class="even">4</li>
<li>5</li>
<li class="even">6</li>
<li>7</li>
<li class="even">8</li>
</ul>
</div>
CSS
#carousel {
overflow:hidden;
width:500px; /* 表示領域 */
}
#carousel ul {
position:relative;
overflow:hidden;
margin:0;
padding:0;
list-style:none;
}
#carousel ul li {
float:left;
margin:0;
padding:15px 0;
width:100px; /* アイテムの幅 */
background-color:#ccc;
font-size:16px;
text-align:center;
}
#carousel ul li.even {
background-color:#eee;
}
JavaScript
(function() {
/**
* 1回に移動する量
*/
var movePos = 5;
window.addEventListener('DOMContentLoaded', function() {
var listElem = document.querySelector('#carousel > ul');
if (!listElem) return;
var itemElems = listElem.childNodes,
listWidth = listElem.parentNode.offsetWidth,
listHalfWidth = listWidth / 2,
cloneElems = [],
sizes = [],
direction = '';
// アイテム要素の複製と幅の取得
itemElems.forEach(function(elem) {
if (elem.nodeType > 1) return false;
cloneElems.push(elem.cloneNode(true));
var style = document.defaultView.getComputedStyle(elem, '');
sizes.push(
parseInt(style['margin-left']) +
parseInt(style['margin-right']) +
elem.offsetWidth
);
});
var size = sizes.reduce(function(a, x) { return a + x; }),
defPos = size * -1,
currentPos = defPos,
maxPos = defPos * 2;
// 幅の設定
listElem.style.width = (size * 3) + 'px';
// 複製アイテムを前に出力
cloneElems.reverse().forEach(function(elem) {
var cloneElem = elem.cloneNode(true);
cloneElem.classList.add('clone-before');
listElem.insertBefore(cloneElem, listElem.firstChild);
});
// 複製アイテムを後に出力
cloneElems.reverse().forEach(function(elem) {
var cloneElem = elem.cloneNode(true);
cloneElem.classList.add('clone-after');
listElem.appendChild(cloneElem);
});
// マウスカーソルの座標によるスライドする方向を設定
window.addEventListener('mousemove', function(event) {
var mouseX = event.clientX,
listPosX = listElem.parentNode.getBoundingClientRect().left;
direction = listPosX + listHalfWidth < mouseX ? 'lr' : 'rl';
});
// スライド動作
setInterval(function() {
if (direction === 'lr') {
currentPos -= movePos;
if (currentPos <= maxPos) currentPos = defPos;
} else {
currentPos += movePos;
if (currentPos >= 0) currentPos = defPos;
}
listElem.style.left = currentPos + 'px';
}, 24);
});
})();
カルーセルの中央にいくにしたがって移動する速度を遅くするには、次の64行目から67行目ようにマウスカーソルと中央の間の距離を中央にいくにしたがって0になるようにして、その値を移動量に乗算することで実装できます。
JavaScript
(function() {
/**
* 1回に移動する量
*/
var movePos = 5;
window.addEventListener('DOMContentLoaded', function() {
var listElem = document.querySelector('#carousel > ul');
if (!listElem) return;
var itemElems = listElem.childNodes,
listWidth = listElem.parentNode.offsetWidth,
listHalfWidth = listWidth / 2,
cloneElems = [],
sizes = [],
direction = '',
currentMovePos = movePos;
// アイテム要素の複製と幅の取得
itemElems.forEach(function(elem) {
if (elem.nodeType > 1) return false;
cloneElems.push(elem.cloneNode(true));
var style = document.defaultView.getComputedStyle(elem, '');
sizes.push(
parseInt(style['margin-left']) +
parseInt(style['margin-right']) +
elem.offsetWidth
);
});
var size = sizes.reduce(function(a, x) { return a + x; }),
defPos = size * -1,
currentPos = defPos,
maxPos = defPos * 2;
// 幅の設定
listElem.style.width = (size * 3) + 'px';
// 複製アイテムを前に出力
cloneElems.reverse().forEach(function(elem) {
var cloneElem = elem.cloneNode(true);
cloneElem.classList.add('clone-before');
listElem.insertBefore(cloneElem, listElem.firstChild);
});
// 複製アイテムを後に出力
cloneElems.reverse().forEach(function(elem) {
var cloneElem = elem.cloneNode(true);
cloneElem.classList.add('clone-after');
listElem.appendChild(cloneElem);
});
// マウスカーソルの座標によるスクロール方向を設定
window.addEventListener('mousemove', function(event) {
var mouseX = event.clientX,
listPosX = listElem.parentNode.getBoundingClientRect().left;
direction = listPosX + listHalfWidth < mouseX ? 'lr' : 'rl';
var ratio = Math.abs(1 - ((mouseX - listPosX) / listHalfWidth));
if (ratio > 1) ratio = 1;
currentMovePos = movePos * ratio;
});
// スクロール動作
setInterval(function() {
if (direction === 'lr') {
currentPos -= currentMovePos;
if (currentPos <= maxPos) currentPos = defPos;
} else {
currentPos += currentMovePos;
if (currentPos >= 0) currentPos = defPos;
}
listElem.style.left = currentPos + 'px';
}, 24);
});
})();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8