123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621 |
- <template>
- <div
- class="home"
- @mousedown="onMouseDown"
- @mousemove="onMouseMove"
- @mouseup="onMouseUp"
- @mouseleave="onMouseLeave"
- @wheel.passive="onWheel"
- @dragstart.prevent
- >
- <div
- ref="landscape-wrap"
- class="landscape-wrap"
- :style="{
- left: landscapePositionleft,
- }"
- >
- <img
- v-for="index in 3"
- :key="index"
- class="landscape"
- src="@/assets/landscape.png"
- alt=""
- @dragstart.prevent
- >
- </div>
- <div
- class="people-far-wrap"
- :style="{
- right: peopleFarPositionRight,
- }"
- >
- <img
- class="people-far"
- :class="peopleFarColorStatus"
- src="@/assets/people-far-serial-frame-400-600-60.png"
- alt=""
- @dragstart.prevent
- >
- <HotSpot
- v-if="[3].includes(tourState) || ([0].includes(tourState) && maskOpacity === 0)"
- class="hot-spot"
- @click="onClickPeopleFarHotSpot"
- />
- </div>
- <div
- class="people-near-wrap"
- :style="{
- left: peopleNearPositionLeft,
- }"
- >
- <img
- class="people-near"
- src="@/assets/people-near.png"
- alt=""
- @dragstart.prevent
- >
- <img
- v-show="[0, 1].includes(tourState)"
- ref="treasure"
- class="treasure"
- :style="{
- height: treasureInitialHeightPercent + '%',
- opacity: treasureOpacity,
- }"
- src="@/assets/treasure.png"
- alt=""
- @dragstart.prevent
- >
- </div>
- <img
- class="introduce"
- :style="{
- left: introducePositionLeft,
- }"
- src="@/assets/introduce.png"
- alt=""
- @dragstart.prevent
- >
- <div
- v-if="[0, 1, 2].includes(tourState) && maskOpacity !== 0"
- class="fade-mask"
- :style="{
- opacity: maskOpacity,
- }"
- >
- <img
- v-show="[2].includes(tourState)"
- src="@/assets/treasure-last-frame.jpg"
- alt=""
- >
- </div>
- <div
- v-show="[1].includes(tourState)"
- class="treasure-frames-wrap"
- >
- <img
- v-for="index of treasureFrameTotalNum"
- v-show="treasureFrameCurNum === index - 1 ||
- treasureFrameCurNum - 1 === index - 1
- "
- :key="index"
- class="treasure-frame"
- :src="require(`@/assets/treasure-frames/合成 1_${(index-1).toString().padStart(5, '0')}.jpg`)"
- alt=""
- @load="onTreasureFrameLoad(index - 1)"
- @error="onTreasureFrameError(index - 1)"
- >
- <div
- class="text1"
- :style="{opacity: text1Opacity}"
- >
- <span class="title">宋清瓷团花粉盒</span><br>
- <span>约公元前1220年<br>口径13.5cm 底径8cm 高6cm</span>
- </div>
- <div
- class="text2"
- :style="{opacity: text2Opacity}"
- >
- 此展品为宋代文物。子母口,浅腹,平底,盖面平;盒为子口,内有三个小碟;胎灰白,坚硬,施青色釉,口沿与底部无釉。现收藏于松阳县博物馆。
- </div>
- </div>
- </div>
- </template>
- <script>
- const initialPeopleNearPositionLeft = '25%'
- const initPeopleFarPositionRight = '10%'
- const landscapeSpeedRate = 0.02
- const peopleFarSpeedRate = 0.4
- const peopleNearSpeedRate = 0.6
- const introduceSpeedRate = 0.6
- const treasureFadeInProgressRightBorder = 3000
- const treasureDisplayProgressRightBorder = 6000
- const treasureFadeOutProgressRightBorder = 2000
- const translateLengthRightBorder = 900
- const treasureFrameTotalNum = 125
- const treasureInitialHeightPercent = 9
- const treasureFinalHeightPercent = 116
- export default {
- name: 'HomeView',
- components: {
- },
- data() {
- return {
- // 鼠标拖拽相关
- isMouseDown: false,
- lastMoveEventTimeStamp: 0,
- moveSpeed: 0,
- // 动画帧相关
- lastAnimationTimeStamp: 0,
- animationFrameId: null,
- tourState: 0, // 0:文物淡入过渡阶段;1:文物三维展示阶段;2:文物渐出过渡阶段;3:镜头平移阶段
- // 镜头平移相关
- translateLength: 0,
- landscapePositionleft: '18.491%',
- peopleFarPositionRight: initPeopleFarPositionRight,
- peopleNearPositionLeft: initialPeopleNearPositionLeft,
- introducePositionLeft: '3.347%',
- // 文物淡入相关
- treasureFadeInProgress: 0,
- treasureFadeInProgressRightBorder,
- treasureFadeInInitialLeft: 0,
- treasureFadeInInitialTop: 0,
- treasureFadeInFinalLeft: 0,
- treasureFadeInFinalTop: 0,
- treasureInitialHeightPercent,
- // 文物展示相关
- treasureDisplayProgress: 0,
- treasureFrameTotalNum,
- treasureFrameCurNum: 0,
- treasureFrameStateList: new Array(treasureFrameTotalNum),
- // 文物淡出相关
- treasureFadeOutProgress: 0,
- treasureFadeOutProgressRightBorder,
- // 远处人物变色相关
- peopleFarColorStatus: 'no-color', // 'no-color', 'color'
- isPeopleFarColorChanging: false,
- }
- },
- computed: {
- treasureOpacity() {
- if (this.tourState === 0) {
- if (this.treasureFadeInProgress > treasureFadeInProgressRightBorder / 2) {
- return 1
- } else {
- return this.treasureFadeInProgress / (treasureFadeInProgressRightBorder / 2)
- }
- } else if (this.tourState === 2) {
- if (this.treasureFadeOutProgress < treasureFadeOutProgressRightBorder / 2) {
- return 1
- } else {
- return 1 - (this.treasureFadeOutProgress - treasureFadeOutProgressRightBorder / 2) / (treasureFadeOutProgressRightBorder / 2)
- }
- } else {
- return 0
- }
- },
- maskOpacity() {
- if (this.tourState === 0) {
- if (this.treasureFadeInProgress > treasureFadeInProgressRightBorder / 2) {
- return 1
- } else {
- return this.treasureFadeInProgress / (treasureFadeInProgressRightBorder / 2)
- }
- } else if (this.tourState === 2) {
- if (this.treasureFadeOutProgress < treasureFadeOutProgressRightBorder / 2) {
- return 1
- } else {
- return 1 - (this.treasureFadeOutProgress - treasureFadeOutProgressRightBorder / 2) / (treasureFadeOutProgressRightBorder / 2)
- }
- } else {
- return 1
- }
- },
- text1Opacity() {
- if (this.tourState === 1) {
- if (this.treasureDisplayProgress < treasureDisplayProgressRightBorder * 0.1) {
- return this.treasureDisplayProgress / (treasureDisplayProgressRightBorder * 0.1)
- } else if (this.treasureDisplayProgress >= treasureDisplayProgressRightBorder * 0.1 && this.treasureDisplayProgress < treasureDisplayProgressRightBorder * 0.4) {
- return 1
- } else if (this.treasureDisplayProgress >= treasureDisplayProgressRightBorder * 0.4 && this.treasureDisplayProgress < treasureDisplayProgressRightBorder * 0.5) {
- return 1 - (this.treasureDisplayProgress - treasureDisplayProgressRightBorder * 0.4) / (treasureDisplayProgressRightBorder * (0.5 - 0.4))
- } else {
- return 0
- }
- } else {
- return 0
- }
- },
- text2Opacity() {
- if (this.tourState === 1) {
- if (this.treasureDisplayProgress < treasureDisplayProgressRightBorder * 0.5) {
- return 0
- } else if (this.treasureDisplayProgress >= treasureDisplayProgressRightBorder * 0.5 && this.treasureDisplayProgress < treasureDisplayProgressRightBorder * 0.6) {
- return (this.treasureDisplayProgress - treasureDisplayProgressRightBorder * 0.5) / (treasureDisplayProgressRightBorder * (0.6 - 0.5))
- } else if (this.treasureDisplayProgress >= treasureDisplayProgressRightBorder * 0.6 && this.treasureDisplayProgress < treasureDisplayProgressRightBorder * 0.9) {
- return 1
- } else {
- return 1 - (this.treasureDisplayProgress - treasureDisplayProgressRightBorder * 0.9) / (treasureDisplayProgressRightBorder * (1 - 0.9))
- }
- } else {
- return 0
- }
- },
- },
- watch: {
- tourState(vNew, vOld) {
- console.log('进入tourState ', vNew)
- if (vOld === 0 && vNew === 1) {
- this.treasureDisplayProgress += 0.001
- } else if (vOld === 1 && vNew === 2) {
- this.treasureFadeOutProgress += 0.001
- } else if (vOld === 2 && vNew === 3) {
- this.translateLength -= 0.001
- } else if (vOld === 3 && vNew === 2) {
- this.treasureFadeOutProgress -= 0.001
- } else if (vOld === 2 && vNew === 1) {
- this.treasureDisplayProgress -= 0.001
- } else if (vOld === 1 && vNew === 0) {
- this.treasureFadeInProgress -= 0.001
- }
- },
- treasureFadeInProgress: {
- handler(vNew, vOld) {
- if (vOld < this.treasureFadeInProgressRightBorder && vNew >= this.treasureFadeInProgressRightBorder && this.tourState === 0) {
- this.tourState = 1
- }
- if (this.treasureFadeInProgress > treasureFadeInProgressRightBorder / 2) {
- this.$refs.treasure.style.left = this.treasureFadeInInitialLeft + (this.treasureFadeInProgress - treasureFadeInProgressRightBorder / 2) / (treasureFadeInProgressRightBorder / 2) * (this.treasureFadeInFinalLeft - this.treasureFadeInInitialLeft) + 'px'
- this.$refs.treasure.style.top = this.treasureFadeInInitialTop + (this.treasureFadeInProgress - treasureFadeInProgressRightBorder / 2) / (treasureFadeInProgressRightBorder / 2) * (this.treasureFadeInFinalTop - this.treasureFadeInInitialTop) + 'px'
- this.$refs.treasure.style.transform = `translate(-50%, -50%) scale(${1 + (this.treasureFadeInProgress - treasureFadeInProgressRightBorder / 2) / (treasureFadeInProgressRightBorder / 2) * (treasureFinalHeightPercent / this.treasureInitialHeightPercent - 1)})`
- } else {
- this.$refs.treasure.style.left = this.treasureFadeInInitialLeft + 'px'
- this.$refs.treasure.style.top = this.treasureFadeInInitialTop + 'px'
- this.$refs.treasure.style.transform = `translate(-50%, -50%) scale(1)`
- }
- }
- },
- treasureDisplayProgress: {
- handler(vNew, vOld) {
- // 更新toureState
- if (vOld > 0 && vNew <= 0 && this.tourState === 1) {
- this.tourState = 0
- } else if (vOld < treasureDisplayProgressRightBorder && vNew >= treasureDisplayProgressRightBorder && this.tourState === 1) {
- this.tourState = 2
- }
- let idealCurNum = Math.round(this.treasureDisplayProgress / treasureDisplayProgressRightBorder * treasureFrameTotalNum)
- while (this.treasureFrameStateList[idealCurNum] === false) {
- idealCurNum--
- }
- this.treasureFrameCurNum = idealCurNum
- }
- },
- treasureFadeOutProgress: {
- handler(vNew, vOld) {
- if (vOld > 0 && vNew <= 0 && this.tourState === 2) {
- this.tourState = 1
- } else if (vOld < this.treasureFadeOutProgressRightBorder && vNew >= this.treasureFadeOutProgressRightBorder && this.tourState === 2) {
- this.tourState = 3
- }
- }
- },
- translateLength: {
- handler(vNew, vOld) {
- // const rightBorder = window.innerWidth * 2
- if (vOld < 0 && vNew >= 0 && this.tourState === 3) {
- this.tourState = 2
- }
- // if (vOld > -rightBorder && vNew <= -rightBorder && this.tourState === 3) {
- // this.tourState = 1
- // }
- this.landscapePositionleft = `calc(18.491% + ${vNew * landscapeSpeedRate}px)`
- this.peopleFarPositionRight = `calc(${initPeopleFarPositionRight} - ${vNew * peopleFarSpeedRate}px)`
- this.peopleNearPositionLeft = `calc(${initialPeopleNearPositionLeft} + ${vNew * peopleNearSpeedRate}px)`
- this.introducePositionLeft = `calc(3.347% + ${vNew * introduceSpeedRate}px)`
- }
- },
- },
- mounted() {
- this.animationFrameId = requestAnimationFrame(this.inertanceEffect)
- setTimeout(() => {
- this.treasureFadeInInitialLeft = this.$refs.treasure.offsetLeft
- this.treasureFadeInInitialTop = this.$refs.treasure.offsetTop
- this.treasureFadeInFinalLeft = window.innerWidth / 2 - this.$refs.treasure.offsetParent.offsetLeft
- this.treasureFadeInFinalTop = window.innerHeight / 2 - this.$refs.treasure.offsetParent.offsetTop
- }, 100)
- },
- unmounted() {
- cancelAnimationFrame(this.animationFrameId)
- },
- methods: {
- onMouseDown(e) {
- this.isMouseDown = true
- this.moveSpeed = 0
- this.lastMoveEventTimeStamp = 0
- this.lastAnimationTimeStamp = Date.now()
- },
- onMouseUp(e) {
- this.isMouseDown = false
- },
- onMouseLeave() {
- this.isMouseDown = false
- },
- onMouseMove(e) {
- if (this.isMouseDown) {
- if (this.lastMoveEventTimeStamp) {
- // 更新speed
- const currentMoveSpeed = e.movementX / (e.timeStamp - this.lastMoveEventTimeStamp)
- this.moveSpeed = this.moveSpeed * 0.9 + currentMoveSpeed * 0.1
- }
- this.lastMoveEventTimeStamp = e.timeStamp
- }
- },
- onWheel(e) {
- if (this.tourState === 0) {
- this.treasureFadeInProgress += e.deltaY
- if (this.treasureFadeInProgress < 0) {
- this.treasureFadeInProgress = 0
- this.moveSpeed = 0
- } else if (this.treasureFadeInProgress > this.treasureFadeInProgressRightBorder) {
- this.treasureFadeInProgress = this.treasureFadeInProgressRightBorder
- }
- } else if (this.tourState === 1) {
- this.treasureDisplayProgress += e.deltaY
- if (this.treasureDisplayProgress < 0) {
- this.treasureDisplayProgress = 0
- } else if (this.treasureDisplayProgress > treasureDisplayProgressRightBorder) {
- this.treasureDisplayProgress = treasureDisplayProgressRightBorder
- }
- } else if (this.tourState === 2) {
- this.treasureFadeOutProgress += e.deltaY
- if (this.treasureFadeOutProgress < 0) {
- this.treasureFadeOutProgress = 0
- } else if (this.treasureFadeOutProgress > this.treasureFadeOutProgressRightBorder) {
- this.treasureFadeOutProgress = this.treasureFadeOutProgressRightBorder
- }
- } else if (this.tourState === 3) {
- this.translateLength -= e.deltaY
- if (this.translateLength > 0) {
- this.translateLength = 0
- } else if (this.translateLength < -translateLengthRightBorder) {
- this.translateLength = -translateLengthRightBorder
- this.moveSpeed = 0
- }
- }
- },
- inertanceEffect() {
- const timeStamp = Date.now()
- const timeElapsed = timeStamp - this.lastAnimationTimeStamp
- // 速度减慢
- if (this.moveSpeed > 0) {
- this.moveSpeed -= 0.003 * timeElapsed
- if (this.moveSpeed < 0) {
- this.moveSpeed = 0
- }
- } else if (this.moveSpeed < 0) {
- this.moveSpeed += 0.003 * timeElapsed
- if (this.moveSpeed > 0) {
- this.moveSpeed = 0
- }
- }
- // 根据速度更新“距离”
- if (this.tourState === 0) {
- this.treasureFadeInProgress -= this.moveSpeed * timeElapsed
- if (this.treasureFadeInProgress < 0) {
- this.treasureFadeInProgress = 0
- this.moveSpeed = 0
- } else if (this.treasureFadeInProgress > this.treasureFadeInProgressRightBorder) {
- this.treasureFadeInProgress = this.treasureFadeInProgressRightBorder
- }
- } else if (this.tourState === 1) {
- this.treasureDisplayProgress -= this.moveSpeed * timeElapsed
- if (this.treasureDisplayProgress < 0) {
- this.treasureDisplayProgress = 0
- } else if (this.treasureDisplayProgress > treasureDisplayProgressRightBorder) {
- this.treasureDisplayProgress = treasureDisplayProgressRightBorder
- }
- } else if (this.tourState === 2) {
- this.treasureFadeOutProgress -= this.moveSpeed * timeElapsed
- if (this.treasureFadeOutProgress < 0) {
- this.treasureFadeOutProgress = 0
- } else if (this.treasureFadeOutProgress > this.treasureFadeOutProgressRightBorder) {
- this.treasureFadeOutProgress = this.treasureFadeOutProgressRightBorder
- }
- } else if (this.tourState === 3) {
- this.translateLength += this.moveSpeed * timeElapsed
- if (this.translateLength > 0) {
- this.translateLength = 0
- } else if (this.translateLength < -translateLengthRightBorder) {
- this.translateLength = -translateLengthRightBorder
- this.moveSpeed = 0
- }
- }
- this.lastAnimationTimeStamp = timeStamp
- this.animationFrameId = requestAnimationFrame(this.inertanceEffect)
- },
- onClickPeopleFarHotSpot() {
- if (this.isPeopleFarColorChanging) {
- return
- } else {
- if (this.peopleFarColorStatus === 'no-color') {
- this.peopleFarColorStatus = 'color'
- } else {
- this.peopleFarColorStatus = 'no-color'
- }
- this.isPeopleFarColorChanging = true
- setTimeout(() => {
- this.isPeopleFarColorChanging = false
- }, 2500)
- }
- },
- onTreasureFrameLoad(idx) {
- this.treasureFrameStateList[idx] = true
- },
- onTreasureFrameError(idx) {
- this.treasureFrameStateList[idx] = false
- },
- }
- }
- </script>
- <style lang="less" scoped>
- .home {
- width: 100%;
- height: 100%;
- background-image: url(@/assets/background.jpg);
- background-repeat: repeat;
- background-size: contain;
- position: relative;
- overflow: hidden;
- .landscape-wrap {
- position: absolute;
- height: 30%;
- top: 0;
- display: flex;
- > .landscape {
- height: 100%;
- }
- }
- > .people-far-wrap {
- position: absolute;
- top: 20%;
- height: 630px;
- width: 420px;
- overflow: hidden;
- > .people-far {
- position: absolute;
- height: 100%;
- transition-property: left;
- transition-duration: 2.5s;
- transition-timing-function: steps(59, jump-end);
- &.no-color {
- left: 0;
- }
- &.color {
- left: calc(-100% * 59)
- }
- }
- > .hot-spot {
- position: absolute;
- left: 52%;
- transform: translateX(-50%);
- top: 17%;
- }
- }
- > .people-near-wrap {
- position: absolute;
- bottom: -13%;
- height: 100vh;
- > .people-near {
- height: 100%;
- }
- > .treasure {
- position: absolute;
- left: 49%;
- top: 32.5%;
- z-index: 2;
- transform: translate(-50%, -50%);
- }
- }
- .introduce {
- position: absolute;
- top: 5%;
- width: 13.727%;
- }
- .fade-mask {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- background-color: #bfbfa7;
- z-index: 1;
- img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- }
- }
- .treasure-frames-wrap {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 3;
- > img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- }
- > .text1 {
- color: #fff;
- position: absolute;
- top: 5%;
- left: 3%;
- .title {
- font-size: 24px;
- font-weight: bold;
- line-height: 2;
- }
- span {
- font-size: 18px;
- line-height: 1.5;
- }
- }
- > .text2 {
- color: #fff;
- position: absolute;
- bottom: 5%;
- right: 3%;
- width: 30%;
- font-size: 18px;
- line-height: 1.5;
- }
- }
- @media screen and (max-height: 810px) {
- .people-far-wrap {
- height: 540px;
- width: 360px;
- }
- }
- @media screen and (max-height: 720px) {
- .people-far-wrap {
- height: 480px;
- width: 320px;
- }
- }
- @media screen and (max-height: 630px) {
- .people-far-wrap {
- height: 420px;
- width: 280px;
- }
- }
- @media screen and (max-height: 540px) {
- .people-far-wrap {
- height: 360px;
- width: 240px;
- }
- }
- }
- </style>
|