388 lines
9.6 KiB
Plaintext
388 lines
9.6 KiB
Plaintext
<div class="w-video_data video_data-widget-8" data-subpart-id="{{subpart-id}}">
|
||
<h3 class="widget-title"><span>{{widget-title}}</span></h3>
|
||
|
||
<div class="vw3-carousel">
|
||
<button class="vw3-prev" title="上一組" aria-label="上一組" type="button">
|
||
<i class="fa fa-angle-left" aria-hidden="true"></i>
|
||
</button>
|
||
|
||
<div class="vw3-track-wrap">
|
||
<ul class="video_data_wrap vw3-track" data-list="videos" data-level="0">
|
||
<li class="video_data vw3-slide" data-video-url="{{video_url}}" data-video-webm-url="{{video_webm_url}}" data-type="{{video_type}}">
|
||
<a href="{{video_show_url}}" title="{{video_title_escape}}">
|
||
<div class="video_linkwrapper3">
|
||
<div class="videohover">
|
||
<div class="view_info"><span>{{view_count}}</span></div>
|
||
<div class="Video__Player"><button class="Video__PlayerButton" type="button"></button></div>
|
||
</div>
|
||
<img class="video_snapshot" src="{{snapshot_url}}" alt="{{video_title_escape}}">
|
||
</div>
|
||
</a>
|
||
<div class="video_info">
|
||
<div class="video_title">
|
||
<a class="video_link" href="{{video_show_url}}" title="{{video_title_escape}}"><h4>{{video_title}}</h4></a>
|
||
</div>
|
||
<div class="video_desc">
|
||
<a class="video_link" href="{{video_show_url}}" title="{{video_title_escape}}">{{video_desc}}</a>
|
||
</div>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<button class="vw3-next" title="下一組" aria-label="下一組" type="button">
|
||
<i class="fa fa-angle-right" aria-hidden="true"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<style>
|
||
.video_data-widget-8 {
|
||
position: relative;
|
||
|
||
.widget-title { margin-bottom: 1rem; }
|
||
|
||
/* 外層輪播框 */
|
||
.vw3-carousel {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
position: relative;
|
||
}
|
||
|
||
/* 可視區域 */
|
||
.vw3-track-wrap {
|
||
overflow: hidden;
|
||
flex: 1;
|
||
}
|
||
|
||
/* 滑動軌道 */
|
||
.vw3-track {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 1rem;
|
||
list-style: none;
|
||
margin: 0;
|
||
padding: 0;
|
||
transition: transform 0.4s ease;
|
||
}
|
||
|
||
/* 所有 slide 共用 */
|
||
.vw3-slide {
|
||
flex-shrink: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
/* 第一張大卡:40% 相對容器 */
|
||
.vw3-slide:nth-child(1) {
|
||
width: 40%;
|
||
position: relative;
|
||
|
||
.video_linkwrapper3 { margin-bottom: 0; }
|
||
|
||
.video_info {
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
padding: 2rem 1rem 1rem;
|
||
background: linear-gradient(to top, rgba(0,0,0,0.7) 0%, transparent 100%);
|
||
border-radius: 0 0 14px 14px;
|
||
z-index: 10;
|
||
margin: 0;
|
||
}
|
||
|
||
.video_title h4 {
|
||
color: #fff;
|
||
font-size: 1.15rem;
|
||
font-weight: 500;
|
||
margin: 0 0 0.2rem;
|
||
}
|
||
|
||
.video_desc,
|
||
.video_desc a {
|
||
color: rgba(255,255,255,0.85);
|
||
font-size: 0.85rem;
|
||
}
|
||
}
|
||
|
||
/* 後續小卡:各約 20% */
|
||
.vw3-slide:nth-child(n+2) {
|
||
width: calc(20% - 0.75rem);
|
||
|
||
.video_info {
|
||
padding: 0.5rem 0 0;
|
||
margin: 0;
|
||
}
|
||
|
||
.video_title h4 {
|
||
font-size: 0.95rem;
|
||
font-weight: 500;
|
||
color: #1a1a1a;
|
||
margin: 0 0 0.2rem;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 2;
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.video_desc,
|
||
.video_desc a {
|
||
font-size: 0.82rem;
|
||
color: #666;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 2;
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
}
|
||
}
|
||
|
||
/* 圖片共用 */
|
||
.video_linkwrapper3 {
|
||
position: relative;
|
||
aspect-ratio: 16 / 9;
|
||
overflow: hidden;
|
||
border-radius: 14px;
|
||
box-shadow: 0 2px 12px rgba(0,0,0,0.1);
|
||
transition: transform 0.22s ease, box-shadow 0.22s ease;
|
||
|
||
&:hover {
|
||
transform: translateY(-4px);
|
||
box-shadow: 0 8px 24px rgba(0,0,0,0.18);
|
||
}
|
||
|
||
img {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
display: block;
|
||
}
|
||
}
|
||
|
||
/* 播放按鈕 */
|
||
.Video__Player {
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
z-index: 10;
|
||
}
|
||
|
||
.Video__PlayerButton {
|
||
width: 48px;
|
||
height: 48px;
|
||
border-radius: 50%;
|
||
background: rgba(255,255,255,0.85);
|
||
border: none;
|
||
cursor: pointer;
|
||
position: relative;
|
||
|
||
&::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 54%;
|
||
transform: translate(-50%, -50%);
|
||
width: 0;
|
||
height: 0;
|
||
border-style: solid;
|
||
border-width: 8px 0 8px 16px;
|
||
border-color: transparent transparent transparent #1a1a1a;
|
||
}
|
||
|
||
&:hover { background: #fff; }
|
||
}
|
||
|
||
/* 左右箭頭 */
|
||
.vw3-prev,
|
||
.vw3-next {
|
||
flex-shrink: 0;
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: 50%;
|
||
background: rgba(0,0,0,0.15);
|
||
color: #fff;
|
||
border: none;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 1.2rem;
|
||
transition: background 0.2s;
|
||
z-index: 10;
|
||
|
||
&:hover { background: rgba(0,0,0,0.4); }
|
||
&:focus { outline: 2px solid #2980b9; outline-offset: 2px; }
|
||
&:disabled { opacity: 0.3; cursor: default; }
|
||
}
|
||
|
||
/* view_info */
|
||
.view_info {
|
||
position: absolute;
|
||
top: 10px;
|
||
left: 10px;
|
||
background: rgba(0,0,0,0.75);
|
||
color: #fff;
|
||
font-size: 0.8rem;
|
||
padding: 2px 8px;
|
||
border-radius: 3px;
|
||
z-index: 10;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
|
||
/* RWD */
|
||
@media(max-width: 768px) {
|
||
.vw3-slide:nth-child(1) { width: 100%; }
|
||
.vw3-slide:nth-child(n+2) { width: calc(50% - 0.5rem); }
|
||
}
|
||
|
||
@media(max-width: 480px) {
|
||
.vw3-slide:nth-child(n+2) { width: 100%; }
|
||
}
|
||
}
|
||
</style>
|
||
|
||
<script>
|
||
$(document).ready(function() {
|
||
var $widget = $('[data-subpart-id="{{subpart-id}}"]');
|
||
var $trackWrap = $widget.find('.vw3-track-wrap');
|
||
var $track = $widget.find('.vw3-track');
|
||
var $prevBtn = $widget.find('.vw3-prev');
|
||
var $nextBtn = $widget.find('.vw3-next');
|
||
|
||
var originalSlides = $widget.find('.vw3-slide').toArray();
|
||
var total = originalSlides.length;
|
||
if (total === 0) return;
|
||
|
||
var currentIndex = 0; // 目前第一個顯示的 slide index(在 originalSlides 裡)
|
||
|
||
// 重建 track:把所有 slide 克隆三份(前後各補一輪),讓循環無縫
|
||
function buildTrack() {
|
||
$track.empty();
|
||
// 補後一輪(讓往右循環)
|
||
$(originalSlides).each(function() {
|
||
$track.append($(this).clone().addClass('vw3-clone'));
|
||
});
|
||
// 原始
|
||
$(originalSlides).each(function() {
|
||
$track.append($(this).clone());
|
||
});
|
||
// 補前一輪(讓往左循環)
|
||
$(originalSlides).each(function() {
|
||
$track.append($(this).clone().addClass('vw3-clone'));
|
||
});
|
||
}
|
||
|
||
function getVisibleCount() {
|
||
return $(window).width() < 1024 ? 1 : 4;
|
||
}
|
||
|
||
function isMobile() {
|
||
return $(window).width() < 1024;
|
||
}
|
||
|
||
// 更新每個 slide 的寬度
|
||
function updateWidths() {
|
||
var $allSlides = $track.find('.vw3-slide');
|
||
var wrapWidth = $trackWrap.width();
|
||
var gap = 16;
|
||
var visibleCount = getVisibleCount();
|
||
var mobile = isMobile();
|
||
|
||
// 先全部清除大卡樣式
|
||
$allSlides.find('.video_info').css({
|
||
'color' : '',
|
||
'position' : '',
|
||
'bottom' : '',
|
||
'width' : '',
|
||
'padding' : '',
|
||
'background-image' : '',
|
||
'border-radius' : ''
|
||
});
|
||
$allSlides.find('.video_title h4').css({
|
||
'color' : '',
|
||
'font-size' : ''
|
||
});
|
||
|
||
if (mobile) {
|
||
// 手機:一次一則,全寬,不套大卡樣式
|
||
$allSlides.css('width', wrapWidth + 'px');
|
||
} else {
|
||
// 桌機:第一張 40%,其餘平分
|
||
var bigWidth = wrapWidth * 0.4;
|
||
var smallTotal = wrapWidth - bigWidth - gap * (visibleCount - 1);
|
||
var smallWidth = smallTotal / (visibleCount - 1);
|
||
|
||
$allSlides.css('width', smallWidth + 'px');
|
||
|
||
var firstVisibleIdx = total + currentIndex;
|
||
var $firstSlide = $allSlides.eq(firstVisibleIdx);
|
||
|
||
$firstSlide.css('width', bigWidth + 'px');
|
||
|
||
$firstSlide.find('.video_info').css({
|
||
'color' : '#fff',
|
||
'position' : 'absolute',
|
||
'bottom' : '0',
|
||
'width' : '100%',
|
||
'padding' : '2em',
|
||
'background-image' : 'linear-gradient(180deg, transparent 0, #00000066 40%, #000000a3)',
|
||
'border-radius' : '0 0 14px 14px'
|
||
});
|
||
|
||
$firstSlide.find('.video_title h4').css({
|
||
'color' : '#fff',
|
||
'font-size' : '1.5em'
|
||
});
|
||
}
|
||
}
|
||
|
||
// 計算 track 的 translateX,讓第一個顯示的 slide 對齊左邊
|
||
function getOffset(targetIdx) {
|
||
var $allSlides = $track.find('.vw3-slide');
|
||
var offset = 0;
|
||
var gap = 16;
|
||
for (var i = 0; i < targetIdx; i++) {
|
||
offset += parseFloat($allSlides.eq(i).css('width')) + gap;
|
||
}
|
||
return offset;
|
||
}
|
||
|
||
function goTo(newIndex, animate) {
|
||
currentIndex = ((newIndex % total) + total) % total;
|
||
|
||
updateWidths();
|
||
|
||
var targetIdx = total + currentIndex; // 中間那組的 index
|
||
var offset = getOffset(targetIdx);
|
||
|
||
if (animate === false) {
|
||
$track.css('transition', 'none');
|
||
$track.css('transform', 'translateX(-' + offset + 'px)');
|
||
$track[0].offsetHeight; // force reflow
|
||
$track.css('transition', '');
|
||
} else {
|
||
$track.css('transform', 'translateX(-' + offset + 'px)');
|
||
}
|
||
}
|
||
|
||
// 初始化
|
||
buildTrack();
|
||
goTo(0, false);
|
||
|
||
$prevBtn.on('click', function() {
|
||
goTo(currentIndex - 1, true);
|
||
});
|
||
|
||
$nextBtn.on('click', function() {
|
||
goTo(currentIndex + 1, true);
|
||
});
|
||
|
||
$(window).on('resize', function() {
|
||
goTo(currentIndex, false);
|
||
});
|
||
});
|
||
</script>
|