HomeView.vue 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084
  1. <template>
  2. <div
  3. class="home"
  4. >
  5. <div class="bg-mask" />
  6. <Transition name="fade-out">
  7. <Startup
  8. v-if="!store.state.haveShownStartup"
  9. class="startup"
  10. />
  11. </Transition>
  12. <!-- 标题 -->
  13. <div
  14. class="title-wrap"
  15. :style="{
  16. opacity: titleOpacity,
  17. }"
  18. >
  19. <img
  20. class="title"
  21. src="@/assets/images/home-title.png"
  22. alt=""
  23. draggable="false"
  24. >
  25. <div class="sub-text">
  26. 南京博物院<br>
  27. 绢本 墨笔<br>
  28. 元 李衎<br>
  29. </div>
  30. </div>
  31. <!-- 画作 -->
  32. <div
  33. class="painting-wrap"
  34. :style="{
  35. top: `${paintingTop / windowSizeWhenDesignForRef * windowSizeInCssForRef.substring(0, windowSizeInCssForRef.length - 2)}px`,
  36. width: `${paintingWidth / windowSizeWhenDesignForRef * windowSizeInCssForRef.substring(0, windowSizeInCssForRef.length - 2)}px`,
  37. height: `${paintingHeight / windowSizeWhenDesignForRef * windowSizeInCssForRef.substring(0, windowSizeInCssForRef.length - 2)}px`,
  38. }"
  39. >
  40. <div
  41. class="size-sign-h"
  42. :style="{
  43. opacity: sizeOpacity,
  44. }"
  45. >
  46. <img
  47. class=""
  48. src="@/assets/images/size-sign-h.png"
  49. alt=""
  50. draggable="false"
  51. >
  52. <span>100.6cm</span>
  53. </div>
  54. <div
  55. class="size-sign-v"
  56. :style="{
  57. opacity: sizeOpacity,
  58. }"
  59. >
  60. <img
  61. class=""
  62. src="@/assets/images/size-sign-v.png"
  63. alt=""
  64. draggable="false"
  65. >
  66. <span>151.7cm</span>
  67. </div>
  68. <img
  69. class="painting-border"
  70. src="@/assets/images/painting-border-new.png"
  71. alt=""
  72. draggable="false"
  73. >
  74. <img
  75. class="painting"
  76. src="@/assets/images/home-painting.jpg"
  77. alt=""
  78. draggable="false"
  79. >
  80. <img
  81. class="painting-stem"
  82. :style="{
  83. opacity: stemOpacity,
  84. }"
  85. src="@/assets/images/home-painting-stem.png"
  86. alt=""
  87. draggable="false"
  88. >
  89. <img
  90. class="painting-leaf"
  91. :style="{
  92. opacity: leafOpacity,
  93. }"
  94. src="@/assets/images/home-painting-leaf.png"
  95. alt=""
  96. draggable="false"
  97. >
  98. <img
  99. class="painting-stone"
  100. :style="{
  101. opacity: stoneOpacity,
  102. }"
  103. src="@/assets/images/home-painting-stone.png"
  104. alt=""
  105. draggable="false"
  106. >
  107. </div>
  108. <!-- 热点层 -->
  109. <div
  110. class="hotspot-wrap"
  111. :style="{
  112. top: `${paintingTop / windowSizeWhenDesignForRef * windowSizeInCssForRef.substring(0, windowSizeInCssForRef.length - 2)}px`
  113. }"
  114. >
  115. <HotspotForHomepage
  116. v-show="isShowHotspot"
  117. class="hotspot-1"
  118. @click="isShowHotspotDetail1 = true"
  119. />
  120. <HotspotForHomepage
  121. v-show="isShowHotspot"
  122. class="hotspot-2"
  123. @click="showBigPainting"
  124. />
  125. <HotspotForHomepage
  126. v-show="isShowHotspot"
  127. class="hotspot-3"
  128. @click="isShowHotspotDetail3 = true"
  129. />
  130. </div>
  131. <!-- 文字介绍 -->
  132. <div
  133. ref="longDesc"
  134. v-touch:swipe.left="onSwipeLeft"
  135. v-touch:swipe.right="onSwipeRight"
  136. class="long-desc"
  137. :style="{
  138. top: `${(paintingTop + paintingHeight + 53) / windowSizeWhenDesignForRef * windowSizeInCssForRef.substring(0, windowSizeInCssForRef.length - 2)}px`,
  139. opacity: longDescOpacity,
  140. }"
  141. >
  142. <h3>作品简介:</h3>
  143. <p
  144. v-for="(item, index) in homepagePaintingDesc"
  145. :key="index"
  146. >
  147. {{ item }}
  148. </p>
  149. <h3>作者简介:</h3>
  150. <p
  151. v-for="(item, index) in homepageAuthorDesc"
  152. :key="index"
  153. >
  154. {{ item }}
  155. </p>
  156. </div>
  157. <div
  158. class="fixed-desc detail-desc-stem"
  159. :style="{
  160. top: `${(paintingTop + 550) / windowSizeWhenDesignForRef * windowSizeInCssForRef.substring(0, windowSizeInCssForRef.length - 2)}px`,
  161. opacity: stemOpacity,
  162. }"
  163. >
  164. {{ detailDescStem }}
  165. </div>
  166. <div
  167. class="fixed-desc detail-desc-leaf"
  168. :style="{
  169. top: `${(paintingTop + 550) / windowSizeWhenDesignForRef * windowSizeInCssForRef.substring(0, windowSizeInCssForRef.length - 2)}px`,
  170. opacity: leafOpacity,
  171. }"
  172. >
  173. {{ detailDescLeaf }}
  174. </div>
  175. <div
  176. class="fixed-desc detail-desc-stone"
  177. :style="{
  178. top: `${(paintingTop + 550) / windowSizeWhenDesignForRef * windowSizeInCssForRef.substring(0, windowSizeInCssForRef.length - 2)}px`,
  179. opacity: stoneOpacity,
  180. }"
  181. >
  182. {{ detailDescStone }}
  183. </div>
  184. <div
  185. class="fixed-desc summary-desc"
  186. :style="{
  187. top: `${(paintingTop + 550) / windowSizeWhenDesignForRef * windowSizeInCssForRef.substring(0, windowSizeInCssForRef.length - 2)}px`,
  188. opacity: summaryOpacity,
  189. }"
  190. >
  191. {{ summaryDesc }}
  192. </div>
  193. <div class="progress-bar">
  194. <div class="bar-artwork-desc" />
  195. <img
  196. class="progress-bar-node-1"
  197. src="@/assets/images/progress-bar-node-1.png"
  198. alt=""
  199. draggable="false"
  200. >
  201. <div class="bar-author-desc" />
  202. <img
  203. class="progress-bar-node-2"
  204. src="@/assets/images/progress-bar-node-2.png"
  205. alt=""
  206. draggable="false"
  207. >
  208. <div class="bar-artwork-enjoy" />
  209. <img
  210. class="progress-bar-node-3"
  211. src="@/assets/images/progress-bar-node-3.png"
  212. alt=""
  213. draggable="false"
  214. >
  215. <div
  216. class="mask"
  217. :style="{
  218. width: `${(1 - scrollerElScrollTop / summaryHideAt) * 100}%`,
  219. }"
  220. />
  221. </div>
  222. <OperationTip
  223. v-if="isStartupOver"
  224. class="operation-tip"
  225. text="了解作品"
  226. direction="h"
  227. :is-show="isShowOperationTip"
  228. />
  229. <div
  230. ref="scrollerEl"
  231. v-touch:swipe.left="onSwipeLeft"
  232. v-touch:swipe.right="onSwipeRight"
  233. class="scroller"
  234. >
  235. <div
  236. class="inner"
  237. :style="{
  238. height: summaryHideAt + windowHeight + 'px',
  239. }"
  240. />
  241. </div>
  242. <!-- 热点详情页 -->
  243. <Transition name="fade-in-out">
  244. <HotspotDetail1
  245. v-if="isShowHotspotDetail1"
  246. class="hotspot-detail"
  247. @close="isShowHotspotDetail1 = false"
  248. />
  249. </Transition>
  250. <!-- <Transition name="fade-in-out">
  251. <PaintingDetail
  252. v-if="isShowPaintingDetail"
  253. :thumb="require(`@/assets/images/home-painting.jpg`)"
  254. :title="'修篁树石图'"
  255. :author="'李衎'"
  256. :age="'元'"
  257. :subtitle="'轴 绢本 墨笔'"
  258. :location="'南京博物院藏'"
  259. :painting-desc="homepagePaintingDesc.join('\n\n')"
  260. :author-desc="homepageAuthorDesc.join('\n\n')"
  261. :big-painting="require(`@/assets/images/home-painting-big.jpg`)"
  262. :need-operation-tip="true"
  263. class="hotspot-detail painting-detail"
  264. @close="isShowPaintingDetail = false"
  265. />
  266. </Transition> -->
  267. <Transition name="fade-in-out">
  268. <HotspotDetail3
  269. v-if="isShowHotspotDetail3"
  270. class="hotspot-detail"
  271. @close="isShowHotspotDetail3 = false"
  272. />
  273. </Transition>
  274. <Transition name="fade-in">
  275. <video
  276. v-if="isShowVideoFadeToNextPage"
  277. ref="videoFadeToNextPageEl"
  278. class="fade-to-next-page"
  279. src="@/assets/videos/fade-from-home-to-more-content.mp4"
  280. playsinline
  281. webkit-playsinline="true"
  282. x5-video-player-type="h5"
  283. @ended="router.push({
  284. name: 'MoreContent',
  285. })"
  286. />
  287. </Transition>
  288. <Transition name="fade-in">
  289. <BtnSkip
  290. v-if="isShowSkip"
  291. @click="router.push({
  292. name: 'MoreContent',
  293. })"
  294. />
  295. </Transition>
  296. <BtnClickMe
  297. class="go-next-page"
  298. text="点击继续"
  299. :is-show="isShowBtnGoNextPage"
  300. @click="onClickGoNextPage"
  301. />
  302. </div>
  303. </template>
  304. <script setup>
  305. import { ref, computed, watch, onMounted, inject, onBeforeUnmount, onUnmounted, nextTick } from "vue"
  306. import { useRoute, useRouter } from "vue-router"
  307. import { useStore } from "vuex"
  308. import Startup from '@/views/StartupView.vue'
  309. import useSizeAdapt from "@/useFunctions/useSizeAdapt"
  310. import HotspotDetail1 from '@/views/HotspotDetail1.vue'
  311. // import PaintingDetail from '@/views/PaintingDetail.vue'
  312. import HotspotDetail3 from '@/views/HotspotDetail3.vue'
  313. import { api as viewerApi } from 'v-viewer'
  314. import { useWindowSize } from '@vueuse/core'
  315. const { width: windowWidth, height: windowHeight } = useWindowSize()
  316. const route = useRoute()
  317. const router = useRouter()
  318. const store = useStore()
  319. const $env = inject('$env')
  320. const {
  321. windowSizeInCssForRef,
  322. windowSizeWhenDesignForRef,
  323. } = useSizeAdapt()
  324. const homepagePaintingDesc = configText.homepagePaintingDesc
  325. const homepageAuthorDesc = configText.homepageAuthorDesc
  326. const detailDescStem = configText.homepagePaintingDetailDescStem
  327. const detailDescLeaf = configText.homepagePaintingDetailDescLeaf
  328. const detailDescStone = configText.homepagePaintingDetailDescStone
  329. const summaryDesc = configText.homepagePaintingSummary
  330. const scrollerEl = ref(null)
  331. const scrollerElScrollTop = ref(0)
  332. function onScroll() {
  333. scrollerElScrollTop.value = scrollerEl.value.scrollTop
  334. // console.log('当前高度', scrollerElScrollTop.value / scrollerEl.value.scrollHeight )
  335. }
  336. onMounted(() => {
  337. scrollerEl.value.addEventListener('scroll', onScroll)
  338. })
  339. onBeforeUnmount(() => {
  340. scrollerEl.value.removeEventListener('scroll', onScroll)
  341. })
  342. const isShowOperationTip = ref(true)
  343. watch(scrollerElScrollTop, (v) => {
  344. if (v > 0) {
  345. isShowOperationTip.value = false
  346. }
  347. })
  348. const haveShownStartup = computed(() => {
  349. return store.state.haveShownStartup
  350. })
  351. const isStartupOver = ref(false)
  352. const unwatch = watch(haveShownStartup, (v) => {
  353. if (v) {
  354. setTimeout(() => {
  355. isStartupOver.value = true
  356. }, 2000)
  357. unwatch()
  358. }
  359. })
  360. const titleHideAt = window.innerHeight * 0
  361. const titleHideFinishAt = window.innerHeight * 0.75
  362. const titleOpacity = computed(() => {
  363. let ret = null
  364. if (scrollerElScrollTop.value <= titleHideAt) {
  365. ret = 1
  366. } else {
  367. ret = 1 - (scrollerElScrollTop.value - titleHideAt) / (titleHideFinishAt - titleHideAt)
  368. }
  369. return ret
  370. })
  371. const paintingMoveUpAt = window.innerHeight * 0
  372. const paintingTopInitial = 236
  373. const paintingMoveUpFinishAt = paintingMoveUpAt + window.innerHeight * 1
  374. const paintingTopMovedUp = 41
  375. const paintingMoveDownAt = paintingMoveUpFinishAt + window.innerHeight * 0.5
  376. const paintingMoveDownFinishAt = paintingMoveDownAt + window.innerHeight * 0.25
  377. const paingtingTopMovedDown = 90
  378. const paintingTop = computed(() => {
  379. let ret = null
  380. if (scrollerElScrollTop.value <= paintingMoveUpAt) {
  381. ret = paintingTopInitial
  382. } else if (scrollerElScrollTop.value > paintingMoveUpAt && scrollerElScrollTop.value <= paintingMoveUpFinishAt) {
  383. ret = (scrollerElScrollTop.value - paintingMoveUpAt) / (paintingMoveUpFinishAt - paintingMoveUpAt) * (paintingTopMovedUp - paintingTopInitial) + paintingTopInitial
  384. } else if (scrollerElScrollTop.value > paintingMoveUpFinishAt && scrollerElScrollTop.value <= paintingMoveDownAt) {
  385. ret = paintingTopMovedUp
  386. } else if (scrollerElScrollTop.value > paintingMoveDownAt && scrollerElScrollTop.value <= paintingMoveDownFinishAt) {
  387. ret = (scrollerElScrollTop.value - paintingMoveDownAt) / (paintingMoveDownFinishAt - paintingMoveDownAt) * (paingtingTopMovedDown - paintingTopMovedUp) + paintingTopMovedUp
  388. } else {
  389. ret = paingtingTopMovedDown
  390. }
  391. return ret
  392. })
  393. const paintingWidthInitial = 308
  394. const paintingWidthMovedUp = 250
  395. const paintingWidthMovedDown = 308
  396. const paintingWidth = computed(() => {
  397. let ret = null
  398. if (scrollerElScrollTop.value <= paintingMoveUpAt) {
  399. ret = paintingWidthInitial
  400. } else if (scrollerElScrollTop.value > paintingMoveUpAt && scrollerElScrollTop.value <= paintingMoveUpFinishAt) {
  401. ret = (scrollerElScrollTop.value - paintingMoveUpAt) / (paintingMoveUpFinishAt - paintingMoveUpAt) * (paintingWidthMovedUp - paintingWidthInitial) + paintingWidthInitial
  402. } else if (scrollerElScrollTop.value > paintingMoveUpFinishAt && scrollerElScrollTop.value <= paintingMoveDownAt) {
  403. ret = paintingWidthMovedUp
  404. } else if (scrollerElScrollTop.value > paintingMoveDownAt && scrollerElScrollTop.value <= paintingMoveDownFinishAt) {
  405. ret = (scrollerElScrollTop.value - paintingMoveDownAt) / (paintingMoveDownFinishAt - paintingMoveDownAt) * (paintingWidthMovedDown - paintingWidthMovedUp) + paintingWidthMovedUp
  406. } else {
  407. ret = paintingWidthMovedDown
  408. }
  409. return ret
  410. })
  411. const paintingHeightInitial = 523
  412. const paintingHeightMovedUp = 425
  413. const paintingHeightMovedDown = 523
  414. const paintingHeight = computed(() => {
  415. let ret = null
  416. if (scrollerElScrollTop.value <= paintingMoveUpAt) {
  417. ret = paintingHeightInitial
  418. } else if (scrollerElScrollTop.value > paintingMoveUpAt && scrollerElScrollTop.value <= paintingMoveUpFinishAt) {
  419. ret = (scrollerElScrollTop.value - paintingMoveUpAt) / (paintingMoveUpFinishAt - paintingMoveUpAt) * (paintingHeightMovedUp - paintingHeightInitial) + paintingHeightInitial
  420. } else if (scrollerElScrollTop.value > paintingMoveUpFinishAt && scrollerElScrollTop.value <= paintingMoveDownAt) {
  421. ret = paintingHeightMovedUp
  422. } else if (scrollerElScrollTop.value > paintingMoveDownAt && scrollerElScrollTop.value <= paintingMoveDownFinishAt) {
  423. ret = (scrollerElScrollTop.value - paintingMoveDownAt) / (paintingMoveDownFinishAt - paintingMoveDownAt) * (paintingHeightMovedDown - paintingHeightMovedUp) + paintingHeightMovedUp
  424. } else {
  425. ret = paintingHeightMovedDown
  426. }
  427. return ret
  428. })
  429. const longDesc = ref(null)
  430. const longDescShowFinishAt = window.innerHeight * 0.25
  431. const longDescHideAt = longDescShowFinishAt + window.innerHeight * 1
  432. const longDescHideFinishAt = longDescHideAt + window.innerHeight * 0.25
  433. const longDescOpacity = computed(() => {
  434. let ret = null
  435. if (scrollerElScrollTop.value <= longDescShowFinishAt) {
  436. ret = 1 - (longDescShowFinishAt - scrollerElScrollTop.value) / (longDescShowFinishAt)
  437. } else if (scrollerElScrollTop.value > longDescShowFinishAt && scrollerElScrollTop.value < longDescHideAt) {
  438. ret = 1
  439. } else {
  440. ret = 1 - (scrollerElScrollTop.value - longDescHideAt) / (longDescHideFinishAt - longDescHideAt)
  441. }
  442. return ret
  443. })
  444. watch(scrollerElScrollTop, (vNew, vOld) => {
  445. if (vNew > paintingMoveUpFinishAt) {
  446. // longDesc.value.scrollTop = vNew - paintingMoveUpFinishAt
  447. } else if (vNew < vOld && vNew <= paintingMoveUpFinishAt) {
  448. // longDesc.value.scrollTop = 0
  449. }
  450. })
  451. const stemShowAt = longDescHideFinishAt + window.innerHeight * 0
  452. const stemShowFinishAt = stemShowAt + window.innerHeight * 0.25
  453. const stemHideAt = stemShowFinishAt + window.innerHeight * 0.3
  454. const stemHideFisishAt = stemHideAt + window.innerHeight * 0.25
  455. const stemOpacity = computed(() => {
  456. let ret = null
  457. if (scrollerElScrollTop.value <= stemShowAt) {
  458. ret = 0
  459. } else if (scrollerElScrollTop.value > stemShowAt && scrollerElScrollTop.value < stemShowFinishAt) {
  460. ret = (scrollerElScrollTop.value - stemShowAt) / (stemShowFinishAt - stemShowAt)
  461. } else if (scrollerElScrollTop.value >= stemShowFinishAt && scrollerElScrollTop.value <= stemHideAt) {
  462. ret = 1
  463. } else if (scrollerElScrollTop.value > stemHideAt && scrollerElScrollTop.value < stemHideFisishAt) {
  464. ret = 1 - (scrollerElScrollTop.value - stemHideAt) / (stemHideFisishAt - stemHideAt)
  465. } else {
  466. ret = 0
  467. }
  468. return ret
  469. })
  470. const leafShowAt = stemHideFisishAt + (0 * window.innerHeight)
  471. const leafShowFinishAt = leafShowAt + (0.25 * window.innerHeight)
  472. const leafHideAt = leafShowFinishAt + (0.3 * window.innerHeight)
  473. const leafHideFisishAt = leafHideAt + (0.25 * window.innerHeight)
  474. const leafOpacity = computed(() => {
  475. let ret = null
  476. if (scrollerElScrollTop.value <= leafShowAt) {
  477. ret = 0
  478. } else if (scrollerElScrollTop.value > leafShowAt && scrollerElScrollTop.value < leafShowFinishAt) {
  479. ret = (scrollerElScrollTop.value - leafShowAt) / (leafShowFinishAt - leafShowAt)
  480. } else if (scrollerElScrollTop.value >= leafShowFinishAt && scrollerElScrollTop.value <= leafHideAt) {
  481. ret = 1
  482. } else if (scrollerElScrollTop.value > leafHideAt && scrollerElScrollTop.value < leafHideFisishAt) {
  483. ret = 1 - (scrollerElScrollTop.value - leafHideAt) / (leafHideFisishAt - leafHideAt)
  484. } else {
  485. ret = 0
  486. }
  487. return ret
  488. })
  489. const stoneShowAt = leafHideFisishAt + (0 * window.innerHeight)
  490. const stoneShowFinishAt = stoneShowAt + (0.25 * window.innerHeight)
  491. const stoneHideAt = stoneShowFinishAt + (0.3 * window.innerHeight)
  492. const stoneHideFinishAt = stoneHideAt + (0.25 * window.innerHeight)
  493. const stoneOpacity = computed(() => {
  494. let ret = null
  495. if (scrollerElScrollTop.value <= stoneShowAt) {
  496. ret = 0
  497. } else if (scrollerElScrollTop.value > stoneShowAt && scrollerElScrollTop.value < stoneShowFinishAt) {
  498. ret = (scrollerElScrollTop.value - stoneShowAt) / (stoneShowFinishAt - stoneShowAt)
  499. } else if (scrollerElScrollTop.value >= stoneShowFinishAt && scrollerElScrollTop.value <= stoneHideAt) {
  500. ret = 1
  501. } else if (scrollerElScrollTop.value > stoneHideAt && scrollerElScrollTop.value < stoneHideFinishAt) {
  502. ret = 1 - (scrollerElScrollTop.value - stoneHideAt) / (stoneHideFinishAt - stoneHideAt)
  503. } else {
  504. ret = 0
  505. }
  506. return ret
  507. })
  508. const summaryShowAt = stoneHideFinishAt + window.innerHeight * 0
  509. const summaryShowFinishAt = summaryShowAt + window.innerHeight * 0.25
  510. const summaryHideAt = summaryShowFinishAt + window.innerHeight * 0.3
  511. const summaryHideFisishAt = summaryHideAt + window.innerHeight * 0.25
  512. const summaryOpacity = computed(() => {
  513. let ret = null
  514. if (scrollerElScrollTop.value <= summaryShowAt) {
  515. ret = 0
  516. } else if (scrollerElScrollTop.value > summaryShowAt && scrollerElScrollTop.value < summaryShowFinishAt) {
  517. ret = (scrollerElScrollTop.value - summaryShowAt) / (summaryShowFinishAt - summaryShowAt)
  518. } else if (scrollerElScrollTop.value >= summaryShowFinishAt && scrollerElScrollTop.value <= summaryHideAt) {
  519. ret = 1
  520. } else if (scrollerElScrollTop.value > summaryHideAt && scrollerElScrollTop.value < summaryHideFisishAt) {
  521. ret = 1 - (scrollerElScrollTop.value - summaryHideAt) / (summaryHideFisishAt - summaryHideAt)
  522. } else {
  523. ret = 0
  524. }
  525. return ret
  526. })
  527. const sizeShowAt = stemShowAt
  528. const sizeShowFinishAt = stemShowFinishAt
  529. const sizeHideAt = stoneHideAt
  530. const sizeHideFisishAt = stoneHideFinishAt
  531. const sizeOpacity = computed(() => {
  532. let ret = null
  533. if (scrollerElScrollTop.value <= sizeShowAt) {
  534. ret = 0
  535. } else if (scrollerElScrollTop.value > sizeShowAt && scrollerElScrollTop.value < sizeShowFinishAt) {
  536. ret = (scrollerElScrollTop.value - sizeShowAt) / (sizeShowFinishAt - sizeShowAt)
  537. } else if (scrollerElScrollTop.value >= sizeShowFinishAt && scrollerElScrollTop.value <= sizeHideAt) {
  538. ret = 1
  539. } else if (scrollerElScrollTop.value > sizeHideAt && scrollerElScrollTop.value < sizeHideFisishAt) {
  540. ret = 1 - (scrollerElScrollTop.value - sizeHideAt) / (sizeHideFisishAt - sizeHideAt)
  541. } else {
  542. ret = 0
  543. }
  544. return ret
  545. })
  546. const isShowHotspot = computed(() => {
  547. let ret = null
  548. if (scrollerElScrollTop.value <= sizeShowAt) {
  549. ret = false
  550. } else {
  551. return true
  552. }
  553. return ret
  554. })
  555. const isShowHotspotDetail1 = ref(false)
  556. // const isShowPaintingDetail = ref(false)
  557. const isShowHotspotDetail3 = ref(false)
  558. function showBigPainting() {
  559. viewerApi({
  560. images: [require(`@/assets/images/home-painting-big.jpg`)],
  561. })
  562. }
  563. /**
  564. * 跳转新页面
  565. */
  566. const videoFadeToNextPageEl = ref(null)
  567. const isShowVideoFadeToNextPage = ref(false)
  568. const isShowSkip = ref(false)
  569. // const fingerPosYWhenTouchStart = ref(0)
  570. // const isAtBottomWhenTouchStart = ref(false)
  571. // const handletouchstart = (event) => {
  572. // fingerPosYWhenTouchStart.value = event.changedTouches[0].pageY
  573. // if (Math.abs(scrollerEl.value.scrollTop + scrollerEl.value.clientHeight - scrollerEl.value.scrollHeight) <= 1) {
  574. // isAtBottomWhenTouchStart.value = true
  575. // } else {
  576. // isAtBottomWhenTouchStart.value = false
  577. // }
  578. // }
  579. // const touchMove = (event) => {
  580. // let currentY = event.changedTouches[0].pageY
  581. // let tY = currentY - fingerPosYWhenTouchStart.value
  582. // if (tY < -1 && isAtBottomWhenTouchStart.value) {
  583. // isShowVideoFadeToNextPage.value = true
  584. // nextTick(() => {
  585. // videoFadeToNextPageEl.value.play()
  586. // })
  587. // setTimeout(() => {
  588. // isShowSkip.value = true
  589. // }, 2000)
  590. // }
  591. // }
  592. const isShowBtnGoNextPage = ref(false)
  593. watch(scrollerElScrollTop, (v) => {
  594. if (Math.abs(v + windowHeight.value - scrollerEl.value.scrollHeight) < 3) {
  595. isShowBtnGoNextPage.value = true
  596. } else {
  597. isShowBtnGoNextPage.value = false
  598. }
  599. })
  600. // const lastX = ref(0)
  601. // function isDesktopUsingViewportWidth() {
  602. // return window.matchMedia('(min-width: 769px)').matches
  603. // }
  604. // 开始滑动
  605. // const handletouchstart = (event) => {
  606. // // pc端通过mouse移动
  607. // if (isDesktopUsingViewportWidth) {
  608. // lastX.value = event.pageX
  609. // } else {
  610. // lastX.value = event.changedTouches[0].pageX
  611. // }
  612. // }
  613. const direction = ref(null)
  614. // 监听活动
  615. // const touchMove = (event) => {
  616. // let currentX = event.changedTouches[0].pageX
  617. // let tx = currentX - lastX.value
  618. // if (tx < -30) {
  619. // // 右滑
  620. // direction.value = 'right'
  621. // // 页面2--600,页面3--1000
  622. // } else if (tx > 30) {
  623. // // 左滑
  624. // direction.value = 'left'
  625. // } else {
  626. // direction.value = null
  627. // }
  628. // }
  629. function smoothScrollTo(element, finalPosition, duration = 500, startTime = performance.now()) {
  630. const currentTime = performance.now()
  631. const timeElapsed = currentTime - startTime
  632. const progress = Math.min(timeElapsed / duration, 1) // 确保进度不超过1
  633. const currentPos = element.scrollTop
  634. const newPos = currentPos + (finalPosition - currentPos) * progress
  635. element.scrollTop = newPos
  636. if (progress < 1 && finalPosition == scrollerPositionList[curStep.value] * scrollerEl.value.scrollHeight) {
  637. console.log('最后位置', finalPosition)
  638. requestAnimationFrame(() => smoothScrollTo(element, finalPosition, duration, startTime))
  639. }
  640. }
  641. const curStep = ref(0)
  642. const scrollerPositionList = [0, 0.17, 0.33, 0.46, 0.62, 1]
  643. const scrollerPositionTimeRight = [6000, 6000, 15000, 15000, 15000, 4000]
  644. const scrollerPositionTimeLeft = [6000, 6000, 15000, 15000, 15000, 15000]
  645. // const handletouchend = () => {
  646. // if (direction.value == 'right' && curStep.value < scrollerPositionList.length - 1) {
  647. // curStep.value ++
  648. // console.log('right', curStep.value)
  649. // const pp = scrollerPositionList[curStep.value]
  650. // const startTime = performance.now()
  651. // requestAnimationFrame(() => {smoothScrollTo(scrollerEl.value, pp * scrollerEl.value.scrollHeight, scrollerPositionTimeRight[curStep.value], startTime)})
  652. // } else if (direction.value == 'left' && curStep.value > 0) {
  653. // curStep.value --
  654. // const pp = scrollerPositionList[curStep.value] * scrollerEl.value.scrollHeight
  655. // const startTime = performance.now()
  656. // requestAnimationFrame(() => {smoothScrollTo(scrollerEl.value, pp, scrollerPositionTimeLeft[curStep.value], startTime)})
  657. // }
  658. // direction.value = null
  659. // }
  660. const onSwipeLeft = () => {
  661. if (curStep.value < scrollerPositionList.length - 1) {
  662. console.log('右滑下一步', curStep.value)
  663. curStep.value ++
  664. console.log('right', curStep.value)
  665. const pp = scrollerPositionList[curStep.value]
  666. const startTime = performance.now()
  667. requestAnimationFrame(() => {smoothScrollTo(scrollerEl.value, pp * scrollerEl.value.scrollHeight, scrollerPositionTimeRight[curStep.value], startTime)})
  668. }
  669. }
  670. const onSwipeRight = () => {
  671. if (curStep.value > 0) {
  672. console.log('左滑返回', curStep.value)
  673. curStep.value --
  674. const pp = scrollerPositionList[curStep.value] * scrollerEl.value.scrollHeight
  675. const startTime = performance.now()
  676. requestAnimationFrame(() => {smoothScrollTo(scrollerEl.value, pp, scrollerPositionTimeLeft[curStep.value], startTime)})
  677. }
  678. }
  679. function onClickGoNextPage() {
  680. isShowBtnGoNextPage.value = false
  681. isShowVideoFadeToNextPage.value = true
  682. nextTick(() => {
  683. videoFadeToNextPageEl.value.play()
  684. })
  685. setTimeout(() => {
  686. isShowSkip.value = true
  687. }, 2000)
  688. }
  689. </script>
  690. <style lang="less" scoped>
  691. .home {
  692. width: 100%;
  693. height: 100%;
  694. background-image: url(@/assets/images/home-painting-line-small.jpg);
  695. background-size: cover;
  696. background-repeat: no-repeat;
  697. background-position: center center;
  698. // 滚动条,只设置某一项可能导致不生效。
  699. ::-webkit-scrollbar {
  700. width: 0;
  701. height: 0;
  702. }
  703. >.bg-mask {
  704. position: absolute;
  705. left: 0;
  706. top: 0;
  707. width: 100%;
  708. height: 100%;
  709. background: rgba(60, 89, 71, 0.65);
  710. backdrop-filter: blur(calc(22 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef')));
  711. }
  712. >.startup {
  713. z-index: 10;
  714. }
  715. >.title-wrap {
  716. position: absolute;
  717. left: 50%;
  718. top: calc(36 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  719. transform: translate(-50%);
  720. width: calc(43 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  721. height: calc(180 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  722. z-index: 5;
  723. >img.title {
  724. position: absolute;
  725. left: 0;
  726. top: 0;
  727. width: 100%;
  728. height: 100%;
  729. }
  730. >.sub-text {
  731. position: absolute;
  732. left: 110%;
  733. top: 46%;
  734. transform: translateY(-50%);
  735. writing-mode: vertical-lr;
  736. font-family: KaiTi, KaiTi;
  737. font-weight: 400;
  738. font-size: calc(18 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  739. color: #FFFFFF;
  740. line-height: calc(21 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  741. white-space: pre;
  742. letter-spacing: 0.2em;
  743. text-align: center;
  744. }
  745. }
  746. >.painting-wrap {
  747. position: absolute;
  748. left: 50%;
  749. transform: translate(-50%, 0);
  750. >.size-sign-h {
  751. position: absolute;
  752. left: 50%;
  753. top: 0;
  754. transform: translate(-50%, -105%);
  755. width: calc(245 / 308 * 100%);
  756. >img {
  757. width: 100%;
  758. }
  759. >span {
  760. position: absolute;
  761. left: 50%;
  762. top: 50%;
  763. transform: translate(-50%, -50%);
  764. font-family: KaiTi, KaiTi;
  765. font-weight: 400;
  766. font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  767. color: #FFFFFF;
  768. line-height: calc(23 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  769. text-shadow: 0px 0px calc(4 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef')) #F8DD86;
  770. }
  771. }
  772. >.size-sign-v {
  773. position: absolute;
  774. right: 0;
  775. top: 54%;
  776. transform: translate(80%, -50%);
  777. height: calc(371 / 523 * 100%);
  778. >img {
  779. height: 100%;
  780. }
  781. >span {
  782. position: absolute;
  783. left: 50%;
  784. top: 50%;
  785. transform: translate(-50%, -50%);
  786. font-family: KaiTi, KaiTi;
  787. font-weight: 400;
  788. font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  789. color: #FFFFFF;
  790. line-height: calc(23 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  791. text-shadow: 0px 0px calc(4 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef')) #F8DD86;
  792. writing-mode: vertical-lr;
  793. }
  794. }
  795. >img.painting-border {
  796. position: absolute;
  797. left: 0;
  798. top: 0;
  799. width: 100%;
  800. height: 100%;
  801. }
  802. >img.painting,
  803. img.painting-stem,
  804. img.painting-leaf,
  805. img.painting-stone {
  806. position: absolute;
  807. left: 50%;
  808. top: 54%;
  809. transform: translate(-50%, -50%);
  810. width: calc(245 / 308 * 100%);
  811. }
  812. }
  813. >.hotspot-wrap {
  814. position: absolute;
  815. left: 50%;
  816. transform: translate(-50%, 0);
  817. width: calc(309 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  818. height: calc(522 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  819. z-index: 7;
  820. pointer-events: none;
  821. &>div {
  822. z-index: 100;
  823. }
  824. >.hotspot-1 {
  825. position: absolute;
  826. top: calc(54 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  827. right: calc(0 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  828. pointer-events: initial;
  829. }
  830. >.hotspot-2 {
  831. position: absolute;
  832. left: calc(60 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  833. top: calc(222 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  834. pointer-events: initial;
  835. }
  836. >.hotspot-3 {
  837. position: absolute;
  838. bottom: calc(-10 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  839. right: calc(-10 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  840. pointer-events: initial;
  841. }
  842. }
  843. >.long-desc {
  844. position: absolute;
  845. left: 50%;
  846. bottom: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  847. width: calc(309 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  848. transform: translate(-50%, 0);
  849. color: white;
  850. overflow: auto;
  851. font-family: KaiTi, KaiTi;
  852. color: #FFFFFF;
  853. animation: none;
  854. z-index: 10;
  855. >h3 {
  856. font-size: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  857. margin-bottom: 0.5em;
  858. font-weight: 600;
  859. }
  860. >p {
  861. font-weight: 400;
  862. font-size: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  863. line-height: calc(25 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  864. text-align: justify;
  865. margin-bottom: 0.5em;
  866. }
  867. }
  868. >.fixed-desc {
  869. position: absolute;
  870. left: 50%;
  871. transform: translateX(-50%);
  872. width: calc(309 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  873. height: 20%;
  874. display: flex;
  875. justify-content: center;
  876. align-items: center;
  877. font-family: KaiTi, KaiTi;
  878. color: #FFFFFF;
  879. font-weight: 400;
  880. font-size: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  881. line-height: calc(25 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  882. text-align: justify;
  883. }
  884. >.progress-bar {
  885. position: absolute;
  886. left: 0;
  887. bottom: 0;
  888. width: 100%;
  889. height: 15px;
  890. >.bar-artwork-desc {
  891. position: absolute;
  892. left: 0;
  893. bottom: 0;
  894. right: 10px;
  895. height: 3px;
  896. background-color: #A9D185;
  897. }
  898. >img.progress-bar-node-1 {
  899. position: absolute;
  900. left: calc(0.6 * v-bind('longDescHideFinishAt') / v-bind('summaryHideAt') * 100%);
  901. bottom: 1px;
  902. width: 2.41px;
  903. height: 10.23px
  904. }
  905. >.bar-author-desc {
  906. position: absolute;
  907. left: 12px;
  908. bottom: 0;
  909. right: calc(v-bind('longDescHideFinishAt') / v-bind('summaryHideAt') * 100%);
  910. height: 3px;
  911. background: #A9D185;
  912. }
  913. >img.progress-bar-node-2 {
  914. position: absolute;
  915. left: calc(v-bind('longDescHideFinishAt') / v-bind('summaryHideAt') * 100%);
  916. bottom: 1px;
  917. width: 7.5px;
  918. height: 10.8px
  919. }
  920. >.bar-artwork-enjoy {
  921. position: absolute;
  922. left: calc(v-bind('stoneShowAt') / v-bind('summaryHideAt') * 100%);
  923. bottom: 0;
  924. right: 0;
  925. height: 3px;
  926. background: #A9D185;
  927. }
  928. >img.progress-bar-node-3 {
  929. position: absolute;
  930. right: 0;
  931. bottom: 1px;
  932. width: 9.7px;
  933. height: 10.8px
  934. }
  935. >.mask {
  936. position: absolute;
  937. right: 0;
  938. bottom: 0;
  939. height: 15px;
  940. background-color: #6e8175;
  941. }
  942. }
  943. >.operation-tip {
  944. position: absolute;
  945. left: 50%;
  946. transform: translateX(-50%);
  947. // bottom: calc(77 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  948. bottom: calc(30 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  949. }
  950. >.scroller {
  951. position: absolute;
  952. left: 0;
  953. top: 0;
  954. width: 100%;
  955. height: 100%;
  956. overflow: hidden;
  957. transition: transform 2s ease;
  958. >.inner {
  959. width: 100%;
  960. }
  961. }
  962. >.hotspot-detail {
  963. z-index: 10;
  964. }
  965. >.hotspot-detail.painting-detail {
  966. backdrop-filter: blur(calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef')));
  967. }
  968. >video.fade-to-next-page {
  969. position: absolute;
  970. left: 0;
  971. top: 0;
  972. width: 100%;
  973. height: 100%;
  974. object-fit: cover;
  975. z-index: 20;
  976. }
  977. >button.go-next-page {
  978. position: absolute;
  979. left: 50%;
  980. bottom: calc(25 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  981. z-index: 20;
  982. transform: translate(-50%, 0);
  983. }
  984. }
  985. </style>