123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- <template>
- <div class="home" @mousedown="onMouseDown" @mousemove="onMouseMove" @mouseup="onMouseUp" @mouseleave="onMouseLeave"
- @touchstart.passive="onTouchStart" @touchmove.prevent="onTouchMove" @touchend="onTouchEnd"
- @touchcancel="onTouchCancel" @wheel.passive="onWheel">
- <div ref="hcon$" class="h-con" :style="{
- left: `-${translateLength}px`,
- }">
- <div class="h-left">
- <img draggable="false" :src="$getImageUrl('h-left.jpg')" alt="">
- <div class="l-con">
- <img draggable="false" class="title" :src="$getImageUrl('title.png')" alt="">
- </div>
- </div>
- <div class="h-right">
- <ul>
- <li v-for="(item, idx) in list" :key="item.id">
- <img @click="onClickItem(item)" draggable="false" class="title" :src="$getImageUrl(`home-img/${idx + 1}.png`)"
- alt="">
- </li>
- </ul>
- </div>
- <img @click="isShowCR = true" draggable="false" class="menu" :src="$getImageUrl('menu.png')" alt="">
- </div>
- <teleport to='body'>
- <Transition>
- <CulturalRelic @close="isShowCR = ''" v-if="isShowCR" />
- </Transition>
- <Transition>
- <TwoDetail :data="current" @close="current = ''" v-if="current && current.isTwo" />
- </Transition>
-
- <Transition>
- <ThreeDetail :data="current" @close="current = ''" v-if="current && !current.isTwo" />
- </Transition>
- </teleport>
- </div>
- </template>
- <script setup>
- import { onBeforeUnmount, onMounted, ref } from "vue"
- import TwoDetail from "@/components/detail/TwoDetail.vue";
- import ThreeDetail from "@/components/detail/ThreeDetail.vue";
- import CulturalRelic from "@/views/cultural-relic.vue"
- import { two, three } from "@/data/category";
- let list = three.data.concat(two.data.map(item => {
- return { ...item, isTwo: true }
- }))
- console.log('result:', list);
- const isMouseDown = ref(false);
- const lastMoveEventTimeStamp = ref(0);
- const moveSpeed = ref(0);
- const lastTouchPos = ref(0);
- const maxTranslateLength = ref(0);
- // 动画帧相关
- const lastAnimationTimeStamp = ref(0);
- const animationFrameId = ref(0);
- const isShowCR = ref('');
- const current = ref('')
- const isMove = ref(false)
- // 镜头平移相关
- const translateLength = ref(0);
- const hcon$ = ref(null)
- const onClickItem = (item) => {
- if (!isMove.value) {
- current.value = item
- }
- }
- const animationFrameTask = () => {
- const timeStamp = Date.now()
- const timeElapsed = timeStamp - lastAnimationTimeStamp.value
- // 速度减慢
- if (moveSpeed.value > 0) {
- moveSpeed.value -= 0.003 * timeElapsed
- if (moveSpeed.value < 0) {
- moveSpeed.value = 0
- }
- } else if (moveSpeed.value < 0) {
- moveSpeed.value += 0.003 * timeElapsed
- if (moveSpeed.value > 0) {
- moveSpeed.value = 0
- }
- }
- // 根据速度更新距离
- translateLength.value += moveSpeed.value * timeElapsed
- if (translateLength.value < 0) {
- translateLength.value = 0
- } else if (translateLength.value > maxTranslateLength.value) {
- translateLength.value = maxTranslateLength.value
- moveSpeed.value = 0
- }
- lastAnimationTimeStamp.value = timeStamp
- animationFrameId.value = requestAnimationFrame(animationFrameTask)
- }
- const calcTranslateLimit = () => {
- maxTranslateLength.value = hcon$.value.clientWidth - window.innerWidth
- }
- const onMouseDown = () => {
- isMouseDown.value = true
- moveSpeed.value = 0
- lastMoveEventTimeStamp.value = 0
- lastAnimationTimeStamp.value = Date.now()
- }
- const onMouseMove = (e) => {
- if (isMouseDown.value) {
- // 有些pc端浏览器比如firefox会有两次事件时间戳相同的情况发生。
- if (lastMoveEventTimeStamp.value && (e.timeStamp - lastMoveEventTimeStamp.value > 1)) {
- isMove.value = true
- // 更新speed
- const currentMoveSpeed = - e.movementX / (e.timeStamp - lastMoveEventTimeStamp.value)
- moveSpeed.value = moveSpeed.value * 0.9 + currentMoveSpeed * 0.1
- }
- lastMoveEventTimeStamp.value = e.timeStamp
- }
- }
- const onMouseUp = () => {
- isMouseDown.value = false
- setTimeout(() => {
- isMove.value = false
- });
- }
- const onMouseLeave = () => {
- isMouseDown.value = false
- setTimeout(() => {
- isMove.value = false
- });
- }
- const onTouchStart = (e) => {
- isMouseDown.value = true
- moveSpeed.value = 0
- lastMoveEventTimeStamp.value = 0
- lastAnimationTimeStamp.value = Date.now()
- lastTouchPos.value = e.changedTouches[0].clientX
- }
- const onTouchMove = (e) => {
- if (isMouseDown.value && e.changedTouches.length === 1) {
- // 疯狂操作的极端情况下两个时间戳之间的时差会不合理,甚至为0
- if (lastMoveEventTimeStamp.value && (e.timeStamp - lastMoveEventTimeStamp.value > 1)) {
- // 更新speed
- isMove.value = true
- const currentMoveSpeed = - (e.changedTouches[0].clientX - lastTouchPos.value) / (e.timeStamp - lastMoveEventTimeStamp.value) * 1.5
- moveSpeed.value = moveSpeed.value * 0.9 + currentMoveSpeed * 0.1
- lastTouchPos.value = e.changedTouches[0].clientX
- }
- lastMoveEventTimeStamp.value = e.timeStamp
- }
- }
- const onTouchEnd = () => {
- isMouseDown.value = false
- setTimeout(() => {
- isMove.value = false
- });
- }
- const onTouchCancel = () => {
- isMouseDown.value = false
- setTimeout(() => {
- isMove.value = false
- });
- }
- const onWheel = (e) => {
- translateLength.value += e.deltaY
- if (translateLength.value < 0) {
- translateLength.value = 0
- } else if (translateLength.value > maxTranslateLength.value) {
- translateLength.value = maxTranslateLength.value
- moveSpeed.value = 0
- }
- }
- onMounted(() => {
- animationFrameId.value = requestAnimationFrame(animationFrameTask)
- window.addEventListener('resize', calcTranslateLimit)
- calcTranslateLimit()
- document.onreadystatechange = () => {
- if (document.readyState === 'complete') {
- // 页面上所有资源加载完成后执行的逻辑
- console.log('所有资源加载完成');
- calcTranslateLimit()
- }
- };
- })
- onBeforeUnmount(() => {
- document.onreadystatechange = null
- window.removeEventListener('resize', calcTranslateLimit)
- })
- </script>
- <style lang="less" scoped>
- .home {
- // background-image: url('@/assets/images/bg-top.png');
- height: 100%;
- width: 100%;
- .h-con {
- height: 100%;
- display: flex;
- width: max-content;
- position: relative;
- .h-left {
- height: 100%;
- position: relative;
- width: max-content;
- >img {
- height: 100%;
- }
- .l-con {
- .logo {
- position: absolute;
- left: 1rem;
- top: 1rem;
- width: 16%;
- }
- .title {
- position: absolute;
- left: 50%;
- top: 50%;
- width: 70%;
- transform: translate(-50%, -50%);
- }
- }
- }
- .h-right {
- background-image: url('@/assets/images/bg-top.jpg');
- background-repeat: no-repeat;
- background-size: auto 80%;
- background-color: #dddad1;
- background-position: 0 0;
- height: 100%;
- position: relative;
- font-size: 0;
- user-select: none;
- &::after {
- width: 100%;
- position: absolute;
- bottom: 0;
- content: '';
- display: inline-block;
- height: 20%;
- box-sizing: border-box;
- border-top: 2rem solid #8B8980;
- background-image: linear-gradient(180deg, #93918A 0%, #AAA89F 63%);
- }
- >ul {
- height: 100%;
- position: relative;
- z-index: 999;
- display: flex;
- align-items: flex-end;
- padding-left: 10rem;
- margin-bottom: 10rem;
- >li {
- list-style: none;
- margin: 0 6rem;
- >img {
- max-width: 80%;
- cursor: pointer;
- }
- }
- }
- }
- }
- }
- .menu{
- position: fixed;
- right: 2rem;
- top: 2rem;
- width: 3%;
- cursor: pointer;
- z-index: 999;
- }
- </style>
|