Last active
May 6, 2020 08:17
-
-
Save LeoOnTheEarth/27e5c116c4189ad3b3f7f5dff4e8f1b6 to your computer and use it in GitHub Desktop.
EasyCoverFlow, example: https://codepen.io/LeoOnTheEarth/pen/WNNYvgm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** Basic Theme Styles **/ | |
.easy-cover-flow { | |
overflow: hidden; | |
position: relative; | |
margin: 0 auto; | |
} | |
.easy-cover-flow .item { | |
position: absolute; | |
top: 0; | |
left: 0; | |
opacity: 0; | |
transition: all 0.3s ease-in-out; | |
} | |
.easy-cover-flow .item.item-hide { | |
transform: scale(0); | |
} | |
/** End of Basic Theme Styles **/ | |
/** Demo Theme Styles **/ | |
.easy-cover-flow.theme-default { | |
width: 100%; | |
height: 420px; | |
} | |
.easy-cover-flow.theme-default .item { | |
width: 48%; | |
} | |
.easy-cover-flow.theme-default .item img { | |
width: 100%; | |
height: 100%; | |
} | |
.easy-cover-flow.theme-default .item.item-hide { | |
transform: scale(0); | |
} | |
.easy-cover-flow.theme-default .item-1 { | |
transform: translate3d(0, 0, 0) scale(0.85); | |
transform-origin: 100% 50%; | |
opacity: 0.8; | |
z-index: 4; | |
} | |
.easy-cover-flow.theme-default .item-2 { | |
transform: translate3d(50%, 0, 0) scale(1); | |
opacity: 1; | |
z-index: 5; | |
} | |
.easy-cover-flow.theme-default .item-3 { | |
transform: translate3d(90%, 0, 0) scale(0.85); | |
transform-origin: 100% 50%; | |
opacity: 1; | |
z-index: 4; | |
} | |
@media screen and (min-width: 641px) { | |
.easy-cover-flow.theme-default { | |
width: 100%; | |
height: 471px; | |
} | |
.easy-cover-flow.theme-default .item { | |
width: 27%; | |
} | |
.easy-cover-flow.theme-default .item-1 { | |
transform: translate3d(0, 0, 0) scale(0.8); | |
transform-origin: 100% 50%; | |
opacity: 0.8; | |
z-index: 2; | |
} | |
.easy-cover-flow.theme-default .item-2 { | |
transform: translate3d(40%, 0, 0) scale(0.85); | |
transform-origin: 100% 50%; | |
opacity: 1; | |
z-index: 3; | |
} | |
.easy-cover-flow.theme-default .item-3 { | |
transform: translate3d(80%, 0, 0) scale(0.9); | |
transform-origin: 100% 50%; | |
opacity: 1; | |
z-index: 4; | |
} | |
.easy-cover-flow.theme-default .item-4 { | |
transform: translate3d(130%, 0, 0) scale(1); | |
opacity: 1; | |
z-index: 5; | |
} | |
.easy-cover-flow.theme-default .item-5 { | |
transform: translate3d(170%, 0, 0) scale(0.9); | |
transform-origin: 100% 50%; | |
opacity: 1; | |
z-index: 4; | |
} | |
.easy-cover-flow.theme-default .item-6 { | |
transform: translate3d(210%, 0, 0) scale(0.85); | |
transform-origin: 100% 50%; | |
opacity: 1; | |
z-index: 3; | |
} | |
.easy-cover-flow.theme-default .item-7 { | |
transform: translate3d(250%, 0, 0) scale(0.8); | |
transform-origin: 100% 50%; | |
opacity: 0.8; | |
z-index: 2; | |
} | |
} | |
@media screen and (min-width: 1201px) { | |
.easy-cover-flow.theme-default { | |
width: 1200px; | |
height: 471px; | |
} | |
.easy-cover-flow.theme-default .item { | |
width: auto; | |
} | |
} | |
/** End of Demo Theme Styles **/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @param {Object?} options | |
* | |
* @return {jQuery} | |
*/ | |
function initialEasyCoverFlow(options) { | |
options = $.extend({ | |
/** | |
* @var {Number|Function} | |
*/ | |
itemCount: function () { | |
if ($(window).width() > 640) { | |
return 7; | |
} | |
return 3; | |
} | |
}, typeof options === 'object' ? options : {}); | |
// 是否有觸發滑動事件 | |
var isTouching = false; | |
function getItemCount($node) { | |
var itemCount = parseInt($node.data('item-count')); | |
if (!itemCount) { | |
if (typeof options.itemCount === 'function') { | |
itemCount = options.itemCount(); | |
} else { | |
itemCount = options.itemCount; | |
} | |
} | |
return itemCount; | |
} | |
/** | |
* @param {jQuery} $target | |
*/ | |
function getIndexes($target) { | |
return { | |
lastItemIndex: getItemCount($target), | |
middleItemIndex: $target.data('middle-item-index'), | |
leftLastItemIndex: $target.data('left-last-item-index'), | |
rightFirstItemIndex: $target.data('right-first-item-index'), | |
}; | |
} | |
/** | |
* @param {jQuery} $target | |
*/ | |
function getItems($target) { | |
var indexes = getIndexes($target); | |
return { | |
$first: $target.find('.item:first'), | |
$last: $target.find('.item:nth-child(' + indexes.lastItemIndex + ')'), | |
$selected: $target.find('.item:nth-child(' + indexes.middleItemIndex + ')'), | |
$leftLast: $target.find('.item:nth-child(' + indexes.leftLastItemIndex + ')'), | |
$rightFirst: $target.find('.item:nth-child(' + indexes.rightFirstItemIndex + ')'), | |
}; | |
} | |
/** | |
* @param {jQuery} $target | |
* @param {Number} diff -1: right -> left, 1: left -> right | |
*/ | |
function updateItemIndexes($target, diff) { | |
var $items = $target.find('.item'); | |
var maxIndex = $items.length; | |
$items.each(function (i, item) { | |
var $item = $(item); | |
var index = $item.data('item-index'); | |
var newIndex = index + diff; | |
newIndex = 0 >= newIndex ? $items.length : newIndex; | |
newIndex = maxIndex < newIndex ? 1 : newIndex; | |
$item.data('item-index', newIndex); | |
$item.removeClass('item-' + index).addClass('item-' + newIndex); | |
}); | |
} | |
function showPrevious($target, onFinished) { | |
var itemCount = getItemCount($target); | |
var nextItemIndex = itemCount + 1 > $target.find('.item').length ? 1 : itemCount + 1; | |
var $next = $target.find('.item:nth-child(' + nextItemIndex + ')'); | |
var $items = getItems($target); | |
updateItemIndexes($target, -1); | |
setTimeout(function () { | |
$items.$first.addClass('item-hide'); | |
$items.$selected.removeClass('selected'); | |
$items.$rightFirst.addClass('selected'); | |
$next.removeClass('item-hide'); | |
setTimeout(function () { | |
$target.append($items.$first); | |
if (typeof onFinished === 'function') { | |
onFinished(); | |
} | |
}, 300); | |
}, 0); | |
} | |
function showNext($target, onFinished) { | |
var $next = $target.find('.item:nth-last-child(1)'); | |
var $items = getItems($target); | |
updateItemIndexes($target, 1); | |
$target.prepend($next); | |
setTimeout(function () { | |
$next.removeClass('item-hide'); | |
$items.$last.addClass('item-hide'); | |
$items.$selected.removeClass('selected'); | |
$items.$leftLast.addClass('selected'); | |
setTimeout(function () { | |
if (typeof onFinished === 'function') { | |
onFinished(); | |
} | |
}, 300); | |
}, 0); | |
} | |
function initialEasyCoverFlowNodes($node) { | |
var itemCount = getItemCount($node); | |
$node.find('.item').each(function (i, item) { | |
var $item = $(item); | |
var index = i + 1; | |
if (index > itemCount) { | |
$item.addClass('item-hide'); | |
} else { | |
$item.removeClass('item-hide'); | |
} | |
$item.addClass('item-' + index.toString()); | |
$item.data('item-index', index); | |
}); | |
var middleItemIndex = itemCount % 2 ? parseInt(itemCount / 2) + 1 : parseInt(itemCount / 2); | |
var leftLastItemIndex = middleItemIndex - 1; | |
var rightFirstItemIndex = middleItemIndex + 1; | |
$node.data('middle-item-index', middleItemIndex); | |
$node.data('left-last-item-index', leftLastItemIndex); | |
$node.data('right-first-item-index', rightFirstItemIndex); | |
$node.find('.item.selected').removeClass('selected'); | |
$node.find('.item.left-last').removeClass('left-last'); | |
$node.find('.item.right-first').removeClass('right-first'); | |
$node.find('.item:nth-child(' + middleItemIndex + ')').addClass('selected'); | |
$node.find('.item:nth-child(' + leftLastItemIndex + ')').addClass('left-last'); | |
$node.find('.item:nth-child(' + rightFirstItemIndex + ')').addClass('right-first'); | |
var touchStartPositionX = 0; | |
$node.on('touchstart', function (event) { | |
if (!isTouching && 0 === touchStartPositionX && 1 === event.changedTouches.length) { | |
touchStartPositionX = event.changedTouches[0].pageX; | |
} | |
}); | |
$node.on('touchend', function (event) { | |
if (!isTouching && 1 === event.changedTouches.length) { | |
var touchEndPositionX = event.changedTouches[0].pageX; | |
isTouching = true; | |
if (touchEndPositionX - touchStartPositionX > 30) { | |
showNext($node, function () { | |
isTouching = false; | |
}); | |
} else if (touchEndPositionX - touchStartPositionX < -30) { | |
showPrevious($node, function () { | |
isTouching = false; | |
}); | |
} else { | |
isTouching = false; | |
} | |
touchStartPositionX = 0; | |
} | |
}); | |
} | |
$('.easy-cover-flow').each(function () { | |
initialEasyCoverFlowNodes($(this)); | |
}); | |
var buttonClicked = false; | |
$('.easy-cover-flow-control.previous').on('click', function () { | |
if (buttonClicked) { | |
return; | |
} | |
buttonClicked = true; | |
showPrevious($($(this).data('easy-cover-flow')), function () { | |
buttonClicked = false; | |
}); | |
}); | |
$('.easy-cover-flow-control.next').on('click', function () { | |
if (buttonClicked) { | |
return; | |
} | |
buttonClicked = true; | |
showNext($($(this).data('easy-cover-flow')), function () { | |
buttonClicked = false; | |
}); | |
}); | |
$(window).on('resize', function () { | |
if (typeof options.itemCount === 'function') { | |
$('.easy-cover-flow').each(function () { | |
initialEasyCoverFlowNodes($(this)); | |
}); | |
} | |
}); | |
} | |
initialEasyCoverFlow(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | |
<title>Carousel</title> | |
<style type="text/css"> | |
* { | |
margin: 0; | |
padding: 0; | |
} | |
</style> | |
<link rel="stylesheet" href="easy-cover-flow.css"> | |
</head> | |
<body> | |
<div class="demo"> | |
<!-- 必要屬性: class="easy-cover-flow theme-default" id="my-easy-cover-flow" --> | |
<div class="easy-cover-flow theme-default" id="my-easy-cover-flow"> | |
<!-- 必要屬性: class="item" 裏頭的 img 圖片會自動縮放 --> | |
<div class="item"><img src="https://picsum.photos/327/469?random=2" /></div> | |
<div class="item"><img src="https://picsum.photos/327/469?random=3" /></div> | |
<div class="item"><img src="https://picsum.photos/327/469?random=4" /></div> | |
<div class="item"><img src="https://picsum.photos/327/469?random=5" /></div> | |
<div class="item"><img src="https://picsum.photos/327/469?random=6" /></div> | |
<div class="item"><img src="https://picsum.photos/327/469?random=1" /></div> | |
<div class="item"><img src="https://picsum.photos/327/469?random=7" /></div> | |
<div class="item"><img src="https://picsum.photos/327/469?random=8" /></div> | |
<div class="item"><img src="https://picsum.photos/327/469?random=9" /></div> | |
<div class="item"><img src="https://picsum.photos/327/469?random=10" /></div> | |
<div class="item"><img src="https://picsum.photos/327/469?random=11" /></div> | |
</div> | |
</div> | |
<div> | |
<!-- 必要屬性: class="easy-cover-flow-control previous" data-easy-cover-flow="#my-easy-cover-flow" --> | |
<button type="button" class="easy-cover-flow-control previous" data-easy-cover-flow="#my-easy-cover-flow">prev</button> | |
<!-- 必要屬性: class="easy-cover-flow-control next" data-easy-cover-flow="#my-easy-cover-flow" --> | |
<button type="button" class="easy-cover-flow-control next" data-easy-cover-flow="#my-easy-cover-flow">next</button> | |
</div> | |
<script src="https://code.jquery.com/jquery-3.5.1.min.js" | |
integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" | |
crossorigin="anonymous"></script> | |
<script src="easy-cover-flow.js"></script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment