|
@@ -0,0 +1,286 @@
|
|
|
|
+<template>
|
|
|
|
+ <div class="hotspot-detail-2">
|
|
|
|
+ <div
|
|
|
|
+ class="painting-wrap"
|
|
|
|
+ :style="{
|
|
|
|
+ clipPath: `rect(0 100% ${AnimationProgress.value}% 0)`,
|
|
|
|
+ }"
|
|
|
|
+ >
|
|
|
|
+ <img
|
|
|
|
+ class="painting-border"
|
|
|
|
+ src="@/assets/images/painting-border.png"
|
|
|
|
+ alt=""
|
|
|
|
+ draggable="false"
|
|
|
|
+ >
|
|
|
|
+ <img
|
|
|
|
+ class="painting"
|
|
|
|
+ src="@/assets/images/home-painting.jpg"
|
|
|
|
+ alt=""
|
|
|
|
+ draggable="false"
|
|
|
|
+ >
|
|
|
|
+ <Transition name="fade-out">
|
|
|
|
+ <img
|
|
|
|
+ v-show="isAnimating"
|
|
|
|
+ class="bottom-border-for-animation"
|
|
|
|
+ :style="{
|
|
|
|
+ bottom: `${100 - AnimationProgress.value}%`,
|
|
|
|
+ }"
|
|
|
|
+ src="@/assets/images/painting-border-bottom.png"
|
|
|
|
+ alt=""
|
|
|
|
+ draggable="false"
|
|
|
|
+ >
|
|
|
|
+ </Transition>
|
|
|
|
+ </div>
|
|
|
|
+ <div
|
|
|
|
+ class="fixed-desc"
|
|
|
|
+ :style="{
|
|
|
|
+ opacity: isAnimating ? AnimationProgress.value / 100 : fixedDescOpacity,
|
|
|
|
+ }"
|
|
|
|
+ >
|
|
|
|
+ <div class="inner-wrap">
|
|
|
|
+ <h3>修篁树石图</h3>
|
|
|
|
+ <p>李衎(元)</p>
|
|
|
|
+ <p>轴 绢本 墨笔</p>
|
|
|
|
+ <p>南京博物院藏</p>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ <OperationTip
|
|
|
|
+ v-if="store.state.isStartupInvisible"
|
|
|
|
+ class="operation-tip"
|
|
|
|
+ :is-show="isShowOperationTip"
|
|
|
|
+ />
|
|
|
|
+ <div
|
|
|
|
+ ref="descEl"
|
|
|
|
+ class="desc"
|
|
|
|
+ :style="{
|
|
|
|
+ backdropFilter: `blur(${descBlurScale}px)`,
|
|
|
|
+ backgroundColor: `rgba(0, 0, 0, ${descBgAlpha})`,
|
|
|
|
+ pointerEvents: isAnimating ? 'none' : null,
|
|
|
|
+ }"
|
|
|
|
+ >
|
|
|
|
+ <h3>作品简介:</h3>
|
|
|
|
+ <p
|
|
|
|
+ v-for="(item, index) in homepagePaintingDesc"
|
|
|
|
+ :key="index"
|
|
|
|
+ >
|
|
|
|
+ {{ item }}
|
|
|
|
+ </p>
|
|
|
|
+ <h3>作者简介:</h3>
|
|
|
|
+ <p
|
|
|
|
+ v-for="(item, index) in homepageAuthorDesc"
|
|
|
|
+ :key="index"
|
|
|
|
+ >
|
|
|
|
+ {{ item }}
|
|
|
|
+ </p>
|
|
|
|
+ <div class="bottom-mask" />
|
|
|
|
+ </div>
|
|
|
|
+ <BtnBack
|
|
|
|
+ @click="emit('close')"
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script setup>
|
|
|
|
+import { ref, computed, watch, onMounted, inject, onUnmounted } from "vue"
|
|
|
|
+import { useRoute, useRouter } from "vue-router"
|
|
|
|
+import { useStore } from "vuex"
|
|
|
|
+import useSizeAdapt from "@/useFunctions/useSizeAdapt"
|
|
|
|
+import TWEEN from '@tweenjs/tween.js'
|
|
|
|
+import { progressProps } from "element-plus"
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+const route = useRoute()
|
|
|
|
+const router = useRouter()
|
|
|
|
+const store = useStore()
|
|
|
|
+
|
|
|
|
+const $env = inject('$env')
|
|
|
|
+
|
|
|
|
+const emit = defineEmits(['close'])
|
|
|
|
+
|
|
|
|
+const {
|
|
|
|
+ windowSizeInCssForRef,
|
|
|
|
+ windowSizeWhenDesignForRef,
|
|
|
|
+} = useSizeAdapt()
|
|
|
|
+
|
|
|
|
+const homepagePaintingDesc = configText.homepagePaintingDesc
|
|
|
|
+const homepageAuthorDesc = configText.homepageAuthorDesc
|
|
|
|
+
|
|
|
|
+const isAnimating = ref(true)
|
|
|
|
+
|
|
|
|
+/** 卷轴展开动画的tweening */
|
|
|
|
+const AnimationProgress = ref({
|
|
|
|
+ value: 7
|
|
|
|
+})
|
|
|
|
+const tween = new TWEEN.Tween(AnimationProgress.value)
|
|
|
|
+tween.to({
|
|
|
|
+ value: 100,
|
|
|
|
+}, 3000)
|
|
|
|
+tween.easing(TWEEN.Easing.Cubic.InOut)
|
|
|
|
+let animationRequestId = null
|
|
|
|
+const animate = () => {
|
|
|
|
+ animationRequestId = requestAnimationFrame(animate)
|
|
|
|
+ TWEEN.update()
|
|
|
|
+}
|
|
|
|
+tween.onUpdate(function (object) {
|
|
|
|
+ console.log(object.value)
|
|
|
|
+})
|
|
|
|
+onMounted(() => {
|
|
|
|
+ tween.start()
|
|
|
|
+ animate()
|
|
|
|
+})
|
|
|
|
+tween.onComplete(() => {
|
|
|
|
+ isAnimating.value = false
|
|
|
|
+ cancelAnimationFrame(animationRequestId)
|
|
|
|
+})
|
|
|
|
+onUnmounted(() => {
|
|
|
|
+ tween.stop()
|
|
|
|
+ cancelAnimationFrame(animationRequestId)
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+const descEl = ref(null)
|
|
|
|
+const descElScrollTop = ref(0)
|
|
|
|
+onMounted(() => {
|
|
|
|
+ descEl.value.addEventListener('scroll', (e) => {
|
|
|
|
+ descElScrollTop.value = descEl.value.scrollTop
|
|
|
|
+ })
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+const isShowOperationTip = ref(true)
|
|
|
|
+watch(descElScrollTop, (v) => {
|
|
|
|
+ if (v > 0) {
|
|
|
|
+ isShowOperationTip.value = false
|
|
|
|
+ }
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+const descBlurScale = computed(() => {
|
|
|
|
+ let ret = 0
|
|
|
|
+ if (descElScrollTop.value < window.innerHeight * 0.3) {
|
|
|
|
+ ret = descElScrollTop.value / (window.innerHeight * 0.3) * 20
|
|
|
|
+ } else {
|
|
|
|
+ ret = 20
|
|
|
|
+ }
|
|
|
|
+ return ret
|
|
|
|
+})
|
|
|
|
+const descBgAlpha = computed(() => {
|
|
|
|
+ let ret = 0
|
|
|
|
+ if (descElScrollTop.value < window.innerHeight * 0.3) {
|
|
|
|
+ ret = descElScrollTop.value / (window.innerHeight * 0.3) * 0.3
|
|
|
|
+ } else {
|
|
|
|
+ ret = 0.3
|
|
|
|
+ }
|
|
|
|
+ return ret
|
|
|
|
+})
|
|
|
|
+const fixedDescOpacity = computed(() => {
|
|
|
|
+ let ret = 1
|
|
|
|
+ if (descElScrollTop.value < window.innerHeight * 0.3) {
|
|
|
|
+ ret = 1 - descElScrollTop.value / (window.innerHeight * 0.3)
|
|
|
|
+ } else {
|
|
|
|
+ ret = 0
|
|
|
|
+ }
|
|
|
|
+ return ret
|
|
|
|
+})
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style lang="less" scoped>
|
|
|
|
+.hotspot-detail-2{
|
|
|
|
+ position: absolute;
|
|
|
|
+ left: 0;
|
|
|
|
+ top: 0;
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 100%;
|
|
|
|
+ backdrop-filter: blur(calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef')));
|
|
|
|
+ >.painting-wrap{
|
|
|
|
+ position: absolute;
|
|
|
|
+ left: 50%;
|
|
|
|
+ top: 44%;
|
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
|
+ width: calc(356 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
|
|
|
|
+ height: calc(602 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
|
|
|
|
+ overflow: hidden;
|
|
|
|
+ >img.painting-border{
|
|
|
|
+ position: absolute;
|
|
|
|
+ left: 0;
|
|
|
|
+ top: 0;
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 100%;
|
|
|
|
+ }
|
|
|
|
+ >img.painting{
|
|
|
|
+ position: absolute;
|
|
|
|
+ left: 50%;
|
|
|
|
+ top: 50%;
|
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
|
+ width: 90%;
|
|
|
|
+ }
|
|
|
|
+ >img.bottom-border-for-animation{
|
|
|
|
+ position: absolute;
|
|
|
|
+ left: 0;
|
|
|
|
+ width: 100%;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ >.fixed-desc{
|
|
|
|
+ position: absolute;
|
|
|
|
+ left: 50%;
|
|
|
|
+ bottom: 2%;
|
|
|
|
+ transform: translateX(-50%);
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 20%;
|
|
|
|
+ display: flex;
|
|
|
|
+ justify-content: center;
|
|
|
|
+ align-items: center;
|
|
|
|
+ >.inner-wrap{
|
|
|
|
+ text-align: center;
|
|
|
|
+ >h3{
|
|
|
|
+ font-family: KaiTi, KaiTi;
|
|
|
|
+ font-weight: 400;
|
|
|
|
+ font-size: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
|
|
|
|
+ color: #FFFFFF;
|
|
|
|
+ margin-bottom: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
|
|
|
|
+ }
|
|
|
|
+ >p{
|
|
|
|
+ font-family: KaiTi, KaiTi;
|
|
|
|
+ font-weight: 400;
|
|
|
|
+ font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
|
|
|
|
+ color: rgba(255, 255, 255, 0.8);
|
|
|
|
+ line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
|
|
|
|
+ margin-bottom: calc(6 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ >.operation-tip{
|
|
|
|
+ position: absolute;
|
|
|
|
+ right: calc(49 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
|
|
|
|
+ bottom: calc(39 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
|
|
|
|
+ }
|
|
|
|
+ >.desc{
|
|
|
|
+ position: absolute;
|
|
|
|
+ left: 0;
|
|
|
|
+ top: 0;
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 100%;
|
|
|
|
+ padding-top: 100vh;
|
|
|
|
+ color: white;
|
|
|
|
+ overflow: auto;
|
|
|
|
+ padding-left: calc(37 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
|
|
|
|
+ padding-right: calc(37 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
|
|
|
|
+ font-family: KaiTi, KaiTi;
|
|
|
|
+ color: #FFFFFF;
|
|
|
|
+ >h3{
|
|
|
|
+ margin-top: 1em;
|
|
|
|
+ margin-bottom: 0.5em;
|
|
|
|
+ font-weight: 600;
|
|
|
|
+ }
|
|
|
|
+ >p{
|
|
|
|
+ font-weight: 400;
|
|
|
|
+ font-size: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
|
|
|
|
+ line-height: calc(25 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
|
|
|
|
+ text-align: justified;
|
|
|
|
+ margin-bottom: 0.5em;
|
|
|
|
+ }
|
|
|
|
+ >.bottom-mask{
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 10vh;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+</style>
|