762 lines
19 KiB
Vue
762 lines
19 KiB
Vue
<template>
|
|
<div
|
|
v-if="state.info.id"
|
|
ref="dvCaricatureWrap"
|
|
class="caricature-wrap overflow-y-auto"
|
|
@touchstart="onTouchStart"
|
|
@touchmove="onTouchMove"
|
|
@scroll="onContentScroll"
|
|
>
|
|
<Transition name="top">
|
|
<div v-show="visibleHead" class="nav" @click.stop="visibleHead = false">
|
|
<SvgIcon name="back_white" class="back" @click.stop="$router.go(-1)" />
|
|
<span class="title">{{ currentItem.name }}</span>
|
|
<div class="right flex-vcenter">
|
|
<div
|
|
class="collect"
|
|
:class="{ collected: historyData.mediaStatus?.hasCollected }"
|
|
@click.stop="onToogleCollected"
|
|
>
|
|
<SvgIcon name="acg-collect-img-0" class="svg-icon" v-if="!historyData.mediaStatus?.hasCollected" />
|
|
<SvgIcon name="acg-collect-img-1" class="svg-icon" style="color: #f52c56" v-else />
|
|
</div>
|
|
<SvgIcon class="share" name="acg-share1" @click.stop="openShare" />
|
|
</div>
|
|
<!-- <SvgIcon class="back right" name="acg_catalogue" @click.stop="visibleCatalogue = true" /> -->
|
|
</div>
|
|
</Transition>
|
|
<div class="like-box" :class="isToolShow ? 'top150' : ''" v-show="visibleHead" @click.stop="onToogleLiked">
|
|
<SvgIcon v-if="historyData?.mediaStatus?.hasLiked" name="acg-heart-1" />
|
|
<SvgIcon v-else name="acg-heart-0" />
|
|
喜欢
|
|
</div>
|
|
<div class="list" @click="onClick">
|
|
<ImgObserver
|
|
v-for="(url, index) in currentEpisode"
|
|
class="item"
|
|
:style="getImgHeight(url)"
|
|
:class="{ move: visibleCatalogue }"
|
|
:key="url"
|
|
:index="index"
|
|
:url="url"
|
|
:init="index - currentProgress <= 1"
|
|
@updateIndex="updateIndex"
|
|
@updateSize="updateSize"
|
|
></ImgObserver>
|
|
</div>
|
|
<div
|
|
v-show="running"
|
|
class="running-box"
|
|
@click.stop="
|
|
{
|
|
running = false;
|
|
visibleHead = true;
|
|
}
|
|
"
|
|
>
|
|
<img class="running" src="@/assets/gif/running.gif" />
|
|
</div>
|
|
<Transition name="bottom">
|
|
<div v-show="visibleHead && !running" ref="bottomRef" class="action">
|
|
<div class="box">
|
|
<div class="func" @click.stop="visibleCatalogue = true">
|
|
<SvgIcon class="icon" name="acg_catalogue" />
|
|
目录
|
|
</div>
|
|
<div class="func" @click.stop="visibleComment = true">
|
|
<SvgIcon class="icon" name="acg_comment" />
|
|
评论
|
|
</div>
|
|
<div class="func" @click.stop="isToolShow = !isToolShow">
|
|
<SvgIcon class="icon" :name="isToolShow ? 'ddown' : 'acg_progress'" />
|
|
进度
|
|
</div>
|
|
<div class="func" @click.stop="running = true">
|
|
<SvgIcon class="icon" name="acg_automatic" />
|
|
自动
|
|
</div>
|
|
<!-- <div class="prev" @click.stop="switchEpisodeNumber(-1)">
|
|
<SvgIcon class="icon" name="acg_prev" />
|
|
上一话
|
|
</div>
|
|
<div class="next" @click.stop="switchEpisodeNumber(1)">
|
|
<SvgIcon class="icon" name="acg_prev" />
|
|
下一话
|
|
</div> -->
|
|
</div>
|
|
<Transition name="van-slide-up">
|
|
<div v-show="isToolShow && !running" class="tools">
|
|
<div class="prev" @click.stop="switchEpisodeNumber(-1)">
|
|
<SvgIcon class="icon" name="backWhite" />
|
|
<span>上一篇</span>
|
|
</div>
|
|
<div class="slider">
|
|
<van-slider
|
|
style="--van-slider-button-background: #ffd300"
|
|
:model-value="progressRatio"
|
|
@update:model-value="(v) => (progressRatio = v)"
|
|
active-color="#FFD300"
|
|
inactive-color="#fff3"
|
|
button-size="12px"
|
|
bar-height="4px"
|
|
@change="reposition"
|
|
></van-slider>
|
|
</div>
|
|
<div class="next" @click.stop="switchEpisodeNumber(1)">
|
|
<SvgIcon class="icon" name="backWhite" />
|
|
<span>下一篇</span>
|
|
</div>
|
|
</div>
|
|
</Transition>
|
|
</div>
|
|
</Transition>
|
|
|
|
<!-- <div v-show="!visibleHead" class="tips">
|
|
第{{ state.episodeNumber }}话 {{ currentProgress }}/{{ currentEpisode.length }}
|
|
</div> -->
|
|
</div>
|
|
<Loading v-else />
|
|
<van-popup v-model:show="visibleCatalogue" position="left" :style="{ width: '50%', height: '100%' }">
|
|
<div class="play-list-box">
|
|
<div class="header">
|
|
<!-- <SvgIcon class="close" name="popup_close" @click.stop="visibleCatalogue = false" /> -->
|
|
<div class="header-title ellipsis">{{ historyData.title }}</div>
|
|
<div class="sort flex-center-between">
|
|
<span class="menu-info">
|
|
共{{ historyData.totalEpisode }}话 {{ getUpdateStatusText(historyData.updateStatus) }}
|
|
</span>
|
|
<span class="btn" @click="sort = !sort">
|
|
<SvgIcon v-show="sort" class="section" name="acg_sort_0" />
|
|
<SvgIcon v-show="!sort" class="section" name="acg_sort_1" />
|
|
<span>{{ sort ? '正序' : '倒序' }}</span>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="list overflow-y-auto">
|
|
<PullRefresh :params="moreParams" @onLoad="onLoad" @onRefresh="onRefresh" finishedText="">
|
|
<div
|
|
:id="`section_${item.episodeNumber}`"
|
|
class="item"
|
|
:class="{ active: item.episodeNumber === state.episodeNumber }"
|
|
v-for="item in autoList"
|
|
:key="item.id"
|
|
@click="switchEpisodeNumberCatalogue(item)"
|
|
>
|
|
{{ item.episodeNumber }}.{{ item.name }}
|
|
</div>
|
|
</PullRefresh>
|
|
</div>
|
|
</div>
|
|
</van-popup>
|
|
<PayForWatch
|
|
v-if="state.info.id"
|
|
ref="dvPayForWatch"
|
|
:isOpen="visiblePayForWatch"
|
|
:info="state.validateItem.id ? state.validateItem : state.info"
|
|
@close="closePayForWatch"
|
|
@buySuccess="beforeBuySuccess"
|
|
></PayForWatch>
|
|
|
|
<AppSharePopup
|
|
:is-open="visibleShare"
|
|
coverType="portrait"
|
|
@close="visibleShare = false"
|
|
:cover="historyData.verticalCover || state.info.cover"
|
|
/>
|
|
|
|
<CommentBox
|
|
v-if="state.info.id"
|
|
ref="dvComment"
|
|
class="comment"
|
|
:isOpen="visibleComment"
|
|
objType="cartoon"
|
|
@close="visibleComment = false"
|
|
:showCollected="false"
|
|
></CommentBox>
|
|
</template>
|
|
<script lang="ts">
|
|
export default {
|
|
name: 'AcgImageDetailWatch',
|
|
};
|
|
</script>
|
|
<script lang="ts" setup>
|
|
import { ref, watch, computed, onDeactivated, onUnmounted, onBeforeUnmount, provide, reactive, toRaw } from 'vue';
|
|
import PayForWatch from '../components/pay/PayForWatch.vue';
|
|
import mediaContentInfo from '../utils/mediaContentInfo';
|
|
import ImgObserver from '../components/ImgObserver.vue';
|
|
import { HistoryVideoType } from '@/enums/app';
|
|
import { showToast } from 'vant';
|
|
import { Pay_emit } from '../utils/pay-mitt';
|
|
import type { PayInfo } from '../utils/pay-mitt';
|
|
import { handleCollected, Collected_emit } from '../utils/collect';
|
|
import CommunityApi from '@/service/community';
|
|
import { getUpdateStatusText } from '../utils/common';
|
|
import { debounce } from '@/utils';
|
|
// import { useGlobalStore } from '@/stores/global';
|
|
// const globalStore = useGlobalStore();
|
|
const running = ref(false);
|
|
const isToolShow = ref(false);
|
|
const visibleHead = ref(true);
|
|
const progressRatio = ref(0);
|
|
const contentMaxScrollTop = ref(0);
|
|
const contentScrollTop = ref(0);
|
|
const visibleSides = ref(true);
|
|
const bottomRef = ref();
|
|
const {
|
|
state,
|
|
currentItem,
|
|
visibleCatalogue,
|
|
dvPayForWatch,
|
|
visiblePayForWatch,
|
|
closePayForWatch,
|
|
buySuccess,
|
|
switchEpisodeNumber,
|
|
autoList,
|
|
moreParams,
|
|
onLoad,
|
|
onRefresh,
|
|
switchEpisodeNumberCatalogue,
|
|
historyData,
|
|
addHistoryReadData,
|
|
sort,
|
|
} = mediaContentInfo({ isGetHistoryInit: true, dbType: HistoryVideoType.AcgImage });
|
|
provide('historyData', historyData);
|
|
const dvCaricatureWrap = ref();
|
|
const currentProgress = ref(1);
|
|
const currentEpisode = computed(() => {
|
|
return state.info.urlSet || [];
|
|
});
|
|
const reposition = () => {
|
|
if (dvCaricatureWrap.value) {
|
|
dvCaricatureWrap.value.scrollTop = (contentMaxScrollTop.value * progressRatio.value) / 100;
|
|
}
|
|
};
|
|
const currentHistoryReadData = computed(() => {
|
|
const arr = historyData.value.historyReadData || [];
|
|
return arr.find((item) => item.episodeNumber === state.episodeNumber) || { scrollTop: 0, imgs: {} };
|
|
});
|
|
watch(
|
|
dvCaricatureWrap,
|
|
() => {
|
|
dvCaricatureWrap.value.scrollTop = currentHistoryReadData.value.scrollTop || 0;
|
|
},
|
|
{
|
|
once: true,
|
|
},
|
|
);
|
|
const onContentScroll = (e: Event) => {
|
|
const target = e.target as HTMLElement;
|
|
contentScrollTop.value = target.scrollTop;
|
|
contentMaxScrollTop.value = target.scrollHeight - target.offsetHeight;
|
|
if (contentMaxScrollTop.value > 0) {
|
|
progressRatio.value = (contentScrollTop.value / contentMaxScrollTop.value) * 100;
|
|
}
|
|
const progress =
|
|
contentMaxScrollTop.value <= 0 ? 100 : Math.max(1, Math.min(100, Math.ceil((contentScrollTop.value / contentMaxScrollTop.value) * 100)));
|
|
addHistoryReadData(state.episodeNumber, {
|
|
progress,
|
|
scrollTop: contentScrollTop.value,
|
|
});
|
|
const isEnd = contentScrollTop.value + 10 >= contentMaxScrollTop.value;
|
|
if (isEnd) {
|
|
console.log('阅读结束')
|
|
running.value = false;
|
|
visibleSides.value = true;
|
|
bottomRef.value?.showTool();
|
|
return;
|
|
}
|
|
if (!running.value) {
|
|
if (contentScrollTop.value < 100) {
|
|
visibleSides.value = true;
|
|
}
|
|
// visibleSides.value = contentScrollTop.value < 100
|
|
}
|
|
};
|
|
const getImgHeight = (url: string) => {
|
|
const imgs = (currentHistoryReadData.value.imgs || {})[url];
|
|
const { width = 0, height = 0 } = imgs || {};
|
|
if (width && height) {
|
|
return {
|
|
height: (window.innerWidth / width) * height + 'px',
|
|
};
|
|
}
|
|
return {};
|
|
};
|
|
const updateIndex = ({ index, url }: { index: number; url: string }) => {
|
|
let progress = 0;
|
|
if (dvCaricatureWrap.value.scrollTop === 0) {
|
|
progress = 1;
|
|
} else {
|
|
progress = Number(index) + 1;
|
|
}
|
|
currentProgress.value = progress;
|
|
addHistoryReadData(state.episodeNumber, {
|
|
progress: Math.ceil((progress / currentEpisode.value.length) * 100),
|
|
progressUrl: url,
|
|
scrollTop: dvCaricatureWrap.value.scrollTop,
|
|
});
|
|
};
|
|
const updateSize = (imgObj: any) => {
|
|
addHistoryReadData(state.episodeNumber, {}, imgObj);
|
|
};
|
|
|
|
watch(
|
|
() => state.episodeNumber,
|
|
(num) => {
|
|
addHistoryReadData(num, { progress: 1 });
|
|
if (dvCaricatureWrap.value) {
|
|
dvCaricatureWrap.value.scrollTop = 0;
|
|
}
|
|
visibleHead.value = true;
|
|
},
|
|
);
|
|
addHistoryReadData(state.episodeNumber + 1, {});
|
|
|
|
onBeforeUnmount(() => {
|
|
addHistoryReadData(state.episodeNumber, {
|
|
scrollTop: dvCaricatureWrap.value.scrollTop,
|
|
});
|
|
|
|
addHistoryReadData(state.episodeNumber + 1, {});
|
|
});
|
|
// 点赞
|
|
const onToogleLiked = () => {
|
|
const zan = !historyData.value.mediaStatus.hasLiked;
|
|
|
|
(zan ? CommunityApi.zan : CommunityApi.cancleZan)(
|
|
zan
|
|
? {
|
|
type: 'image',
|
|
objID: historyData.value.id,
|
|
}
|
|
: {
|
|
type: 'image',
|
|
objIDs: [historyData.value.id],
|
|
},
|
|
).then(() => {
|
|
historyData.value.mediaStatus.hasLiked = zan;
|
|
});
|
|
};
|
|
const onClick = (e: MouseEvent) => {
|
|
if (running.value) {
|
|
visibleHead.value = !visibleHead.value;
|
|
return;
|
|
}
|
|
const { clientY } = e;
|
|
let scrollTop = 0;
|
|
const OneThird = window.innerHeight / 3.5;
|
|
if (clientY < OneThird) {
|
|
scrollTop = -300;
|
|
} else if (clientY > OneThird * 2) {
|
|
scrollTop = 300;
|
|
} else {
|
|
visibleHead.value = !visibleHead.value;
|
|
return;
|
|
}
|
|
|
|
if (scrollTop !== 0) {
|
|
visibleHead.value = false;
|
|
dvCaricatureWrap.value.scrollTo({ top: scrollTop + dvCaricatureWrap.value.scrollTop, behavior: 'smooth' });
|
|
}
|
|
};
|
|
let lastScrollTop = 0;
|
|
const onTouchStart = (e: TouchEvent) => {
|
|
const { clientY } = e.targetTouches[0];
|
|
lastScrollTop = clientY;
|
|
};
|
|
const onTouchMove = (e: TouchEvent) => {
|
|
const { clientY } = e.targetTouches[0];
|
|
const distance = lastScrollTop - clientY;
|
|
if (distance > 30) {
|
|
visibleHead.value = false;
|
|
return;
|
|
}
|
|
if (distance < -30) {
|
|
visibleHead.value = true;
|
|
return;
|
|
}
|
|
};
|
|
|
|
// watch(visibleCatalogue, (bool) => {
|
|
// if (bool) {
|
|
// visibleHead.value = false;
|
|
// }
|
|
// });
|
|
|
|
const scrollSpeed = 1;
|
|
let moveInterval = null as ReturnType<typeof setInterval> | null;
|
|
|
|
const cancelAutoMove = () => {
|
|
moveInterval && clearInterval(moveInterval);
|
|
moveInterval = null;
|
|
running.value = false;
|
|
};
|
|
|
|
const autoMove = () => {
|
|
const { scrollTop, scrollHeight } = dvCaricatureWrap.value;
|
|
|
|
if (scrollTop >= scrollHeight) {
|
|
// 停止自动移动
|
|
cancelAutoMove();
|
|
return;
|
|
}
|
|
|
|
let newPosition = scrollTop + scrollSpeed;
|
|
|
|
dvCaricatureWrap.value.scrollTo(0, newPosition);
|
|
};
|
|
|
|
onDeactivated(() => {
|
|
cancelAutoMove();
|
|
});
|
|
onUnmounted(() => {
|
|
cancelAutoMove();
|
|
});
|
|
|
|
watch(running, (bool) => {
|
|
if (bool) {
|
|
moveInterval = setInterval(autoMove, 10);
|
|
showToast({
|
|
message: '自动阅读模式',
|
|
onClose: () => {
|
|
if (moveInterval) {
|
|
visibleHead.value = false;
|
|
}
|
|
},
|
|
});
|
|
} else {
|
|
cancelAutoMove();
|
|
}
|
|
});
|
|
|
|
const beforeBuySuccess = (obj: PayInfo) => {
|
|
Pay_emit(historyData.value.id, obj);
|
|
buySuccess(obj.type);
|
|
};
|
|
|
|
// 收藏
|
|
const onToogleCollected = async () => {
|
|
try {
|
|
const {
|
|
id,
|
|
mediaStatus: { hasCollected },
|
|
} = historyData.value;
|
|
const tempIsCollect = !hasCollected;
|
|
handleCollected(id, tempIsCollect).then(() => {
|
|
historyData.value.mediaStatus.hasCollected = tempIsCollect;
|
|
Collected_emit(id, tempIsCollect);
|
|
});
|
|
} catch (e) {
|
|
console.log(e);
|
|
}
|
|
};
|
|
|
|
const visibleShare = ref(false);
|
|
const openShare = () => {
|
|
const { id, verticalCover, horizontalCover } = historyData.value;
|
|
let obj = {
|
|
id,
|
|
cover: verticalCover || horizontalCover,
|
|
};
|
|
// globalStore.setShareInfo(obj);
|
|
visibleShare.value = true;
|
|
};
|
|
|
|
const visibleComment = ref(false);
|
|
const dvComment = ref();
|
|
watch(dvComment, (el) => {
|
|
if (!el) return;
|
|
if (!state.info.id || !dvComment.value?.state) return;
|
|
console.log(state, 'state.info', state.validateItem);
|
|
dvComment.value.state.videoInfo = toRaw({
|
|
...state.info,
|
|
id: state.id,
|
|
});
|
|
dvComment.value.getCommentList();
|
|
});
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
@import '@/assets/styles/mixins.scss';
|
|
.caricature-wrap {
|
|
width: 100%;
|
|
height: 100%;
|
|
// @include SafeArea('padding', 'bottom', 60px);
|
|
.like-box {
|
|
position: fixed;
|
|
bottom: 81px;
|
|
right: 0;
|
|
z-index: 100;
|
|
border-radius: 999px 0px 0px 999px;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
width: 86px;
|
|
height: 40px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 12px;
|
|
color: #fff;
|
|
svg {
|
|
margin-right: 5px;
|
|
width: 24px;
|
|
height: 24px;
|
|
}
|
|
}
|
|
.top150 {
|
|
bottom: 150px !important;
|
|
}
|
|
.nav {
|
|
position: fixed;
|
|
left: 0;
|
|
top: 0;
|
|
z-index: 2;
|
|
width: 100%;
|
|
height: 44px;
|
|
background: #181824;
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0 6px;
|
|
font-size: 16px;
|
|
font-weight: 500;
|
|
color: #fff;
|
|
.back {
|
|
flex-shrink: 0;
|
|
width: 24px;
|
|
height: 24px;
|
|
flex-shrink: 0;
|
|
color: #fff;
|
|
margin-right: 4px;
|
|
}
|
|
.title {
|
|
flex: 1;
|
|
text-align: left;
|
|
}
|
|
.right {
|
|
flex-shrink: 0;
|
|
margin-left: 4px;
|
|
.collect {
|
|
svg {
|
|
width: 24px;
|
|
height: 24px;
|
|
}
|
|
}
|
|
.share {
|
|
width: 19px;
|
|
height: 19px;
|
|
margin: 0 16px 0 12px;
|
|
}
|
|
}
|
|
}
|
|
> .list {
|
|
padding-top: 1px;
|
|
.item {
|
|
width: 100%;
|
|
min-height: 200px;
|
|
height: auto;
|
|
|
|
:deep(.animationImg) {
|
|
overflow: visible;
|
|
.loading {
|
|
height: 200px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.action {
|
|
position: fixed;
|
|
box-sizing: content-box;
|
|
@include SafeArea('padding', 'bottom', 0);
|
|
// left: 88px;
|
|
// right: 88px;
|
|
height: 48px;
|
|
background: #000;
|
|
width: 100%;
|
|
left: 0;
|
|
bottom: 0;
|
|
transition: all 0.3s;
|
|
|
|
.box {
|
|
z-index: 2;
|
|
border-radius: 100px;
|
|
padding: 12px 16px;
|
|
// background: rgba(0, 0, 0, 0.60)
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
|
|
> div {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
color: rgba(255, 255, 255, 0.45);
|
|
font-size: 12px;
|
|
.icon {
|
|
width: 24px;
|
|
height: 24px;
|
|
color: rgba(255, 255, 255, 0.9);
|
|
}
|
|
|
|
&.next .icon {
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
&.disabled {
|
|
color: rgba(0, 0, 0, 0.4);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// .tips {
|
|
// position: fixed;
|
|
// @include SafeAreaFixed('bottom', 40px);
|
|
// right: 20px;
|
|
// border-radius: 8px;
|
|
// background: rgba(0, 0, 0, 0.6);
|
|
// padding: 8px 12px;
|
|
// color: #f1f1f1;
|
|
// font-size: 14px;
|
|
// font-weight: 500;
|
|
// }
|
|
}
|
|
|
|
.play-list-box {
|
|
position: relative;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: #0f0f0f;
|
|
display: flex;
|
|
flex-direction: column;
|
|
color: rgba(255, 255, 255, 0.9);
|
|
.header {
|
|
padding-top: 85px;
|
|
width: 100%;
|
|
.close {
|
|
width: 14px;
|
|
height: 14px;
|
|
}
|
|
.header-title {
|
|
width: 100%;
|
|
text-indent: 16px;
|
|
font-size: 18px;
|
|
font-weight: 900;
|
|
font-family: Roboto;
|
|
}
|
|
.sort {
|
|
flex-shrink: 0;
|
|
margin: 16px 0 14px;
|
|
padding: 8px 16px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
color: #141414;
|
|
background: #f68804;
|
|
|
|
.btn {
|
|
display: flex;
|
|
align-items: center;
|
|
.section {
|
|
width: 20px;
|
|
height: 20px;
|
|
margin-right: 4px;
|
|
}
|
|
}
|
|
.menu-info {
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
}
|
|
}
|
|
}
|
|
|
|
.list {
|
|
flex: 1;
|
|
.item {
|
|
width: 100%;
|
|
height: 19px;
|
|
line-height: 19px;
|
|
padding: 0 16px;
|
|
margin-bottom: 11px;
|
|
color: rgba(255, 255, 255, 0.55);
|
|
font-size: 16px;
|
|
font-weight: 400;
|
|
@include textEllipsis();
|
|
&.active {
|
|
color: #f68804;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.running-box {
|
|
background-color: #fff;
|
|
padding: 10px;
|
|
border-radius: 50%;
|
|
position: fixed;
|
|
bottom: 50px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
z-index: 100;
|
|
.running {
|
|
width: 36px;
|
|
height: 36px;
|
|
}
|
|
}
|
|
.tools {
|
|
position: absolute;
|
|
top: -70px;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 70px;
|
|
padding: 0 16px;
|
|
color: #fff;
|
|
background-color: #000;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
|
|
.prev,
|
|
.next {
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
font-size: 12px;
|
|
line-height: 18px;
|
|
|
|
.icon {
|
|
width: 24px;
|
|
height: 24px;
|
|
margin-bottom: 4px;
|
|
}
|
|
}
|
|
|
|
.next .icon {
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
.slider {
|
|
width: 245px;
|
|
align-self: center;
|
|
}
|
|
}
|
|
.top-enter-active,
|
|
.top-leave-active,
|
|
.bottom-enter-active,
|
|
.bottom-leave-active {
|
|
will-change: transform;
|
|
transition: transform 0.4s ease;
|
|
}
|
|
|
|
.top-enter-from,
|
|
.top-leave-to {
|
|
transform: translateY(-100%);
|
|
}
|
|
|
|
.bottom-enter-from,
|
|
.bottom-leave-to {
|
|
transform: translateY(200%);
|
|
}
|
|
</style>
|