PaintingDetailForZhuQin.vue 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. <template>
  2. <div class="painting-detail-for-zhu-qin">
  3. <div
  4. class="painting-wrap"
  5. :style="{
  6. clipPath: `inset(0% ${100 - AnimationProgress.value}% 0% 0%)`,
  7. }"
  8. >
  9. <img
  10. class="painting-border"
  11. src="@/assets/images/painting-border-horiz.png"
  12. alt=""
  13. draggable="false"
  14. >
  15. <img
  16. class="painting"
  17. :src="imgUrlSmall"
  18. alt=""
  19. draggable="false"
  20. >
  21. <img
  22. class="right-border-for-animation"
  23. :style="{
  24. right: `calc(${100 - AnimationProgress.value}% - 2px)`,
  25. }"
  26. src="@/assets/images/painting-border-right.png"
  27. alt=""
  28. draggable="false"
  29. >
  30. </div>
  31. <div
  32. class="bottom-text"
  33. :style="{
  34. opacity: isAnimating ? AnimationProgress.value / 100 : 1,
  35. }"
  36. >
  37. <p class="size">
  38. 33.8×55.4厘米
  39. </p>
  40. <p class="location">
  41. 大都会艺术博物馆藏
  42. </p>
  43. </div>
  44. <div
  45. class="right-text"
  46. :style="{
  47. opacity: isAnimating ? AnimationProgress.value / 100 : 1,
  48. }"
  49. >
  50. <img
  51. class="title"
  52. src="@/assets/images/title-zhu-qin.png"
  53. alt=""
  54. draggable="false"
  55. >
  56. <p class="subtitle subtitle-1">
  57. <span>卷</span> <span>绢本</span> <span>设色</span>
  58. </p>
  59. <p class="subtitle subtitle-2">
  60. <span>宋</span> <span>赵佶</span><img
  61. class="pin-yin"
  62. src="@/assets/images/pin-yin-jí.png"
  63. alt=""
  64. draggable="false"
  65. >
  66. </p>
  67. </div>
  68. <button
  69. class="view-img"
  70. :style="{
  71. opacity: isAnimating ? AnimationProgress.value / 100 : 1,
  72. }"
  73. @click="showBigPainting"
  74. >
  75. <img
  76. class=""
  77. src="@/assets/images/painting-box-img/big-view.png"
  78. alt=""
  79. draggable="false"
  80. >
  81. </button>
  82. <BtnBack
  83. @click="router.go(-1)"
  84. />
  85. </div>
  86. </template>
  87. <script setup>
  88. import { ref, computed, watch, onMounted, inject, onUnmounted } from "vue"
  89. import { useRoute, useRouter } from "vue-router"
  90. import { useStore } from "vuex"
  91. import TWEEN from '@tweenjs/tween.js'
  92. import { api as viewerApi } from 'v-viewer'
  93. import { useWindowSize } from "@vueuse/core"
  94. const route = useRoute()
  95. const router = useRouter()
  96. const store = useStore()
  97. const $env = inject('$env')
  98. const windowHeightDesign = 1080 - 71 - 37 // 设计稿里视口高度。注意要减去上下边栏
  99. const { width: windowWidth, height: windowHeight } = useWindowSize()
  100. const isAnimating = ref(true)
  101. /** 卷轴展开动画的tweening */
  102. const AnimationProgress = ref({
  103. value: 7
  104. })
  105. const tween = new TWEEN.Tween(AnimationProgress.value)
  106. tween.to({
  107. value: 100,
  108. }, 3000)
  109. tween.easing(TWEEN.Easing.Cubic.InOut)
  110. let animationRequestId = null
  111. const animate = () => {
  112. animationRequestId = requestAnimationFrame(animate)
  113. TWEEN.update()
  114. }
  115. // tween.onUpdate(function (object) {
  116. // console.log(object.value)
  117. // })
  118. onMounted(() => {
  119. tween.start()
  120. animate()
  121. })
  122. tween.onComplete(() => {
  123. isAnimating.value = false
  124. cancelAnimationFrame(animationRequestId)
  125. })
  126. onUnmounted(() => {
  127. tween.stop()
  128. cancelAnimationFrame(animationRequestId)
  129. })
  130. const imgUrlSmall = `${$env.BASE_URL}configMultiMedia/paintings/竹禽图卷.jpg`
  131. const imgUrl = `${$env.BASE_URL}configMultiMedia/paintings-big/竹禽图卷.jpg`
  132. function showBigPainting() {
  133. viewerApi({
  134. images: [imgUrl],
  135. })
  136. }
  137. </script>
  138. <style lang="less" scoped>
  139. .painting-detail-for-zhu-qin{
  140. position: absolute;
  141. left: 0;
  142. top: 0;
  143. width: 100%;
  144. height: 100%;
  145. background-image: url(@/assets/images/painting-detail-bg.jpg);
  146. background-size: cover;
  147. background-repeat: no-repeat;
  148. background-position: center center;
  149. ::-webkit-scrollbar { width: 0; height: 0; }
  150. >.painting-wrap{
  151. position: absolute;
  152. left: 50%;
  153. top: calc(50% - 18px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  154. transform: translate(-50%, -50%);
  155. width: calc(810px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  156. height: calc(443px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  157. overflow: hidden;
  158. >img.painting-border{
  159. position: absolute;
  160. left: 0;
  161. top: 0;
  162. width: 100%;
  163. height: 100%;
  164. }
  165. >img.painting{
  166. position: absolute;
  167. top: 50%;
  168. left: calc(116px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  169. transform: translate(0, -50%);
  170. width: calc(634px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  171. height: calc(387px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  172. object-fit: contain;
  173. }
  174. >img.right-border-for-animation{
  175. position: absolute;
  176. top: 0;
  177. height: 100%;
  178. }
  179. }
  180. >.bottom-text{
  181. position: absolute;
  182. left: 50%;
  183. top: calc(50% + 236px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  184. transform: translateX(-50%);
  185. >p{
  186. text-align: center;
  187. font-family: KaiTi, KaiTi;
  188. font-weight: 400;
  189. font-size: calc(24px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  190. color: #E1EDD9;
  191. line-height: calc(28px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  192. white-space: pre;
  193. margin-bottom: 0.2em;
  194. }
  195. }
  196. >.right-text{
  197. position: absolute;
  198. top: calc(310px / v-bind('windowHeightDesign') * v-bind('windowHeight'));;
  199. left: calc(50% + 405px / v-bind('windowHeightDesign') * v-bind('windowHeight') + 5vw);
  200. display: flex;
  201. align-items: center;
  202. >img.title{
  203. height: calc(302px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  204. }
  205. >p{
  206. font-family: KaiTi, KaiTi;
  207. font-weight: 400;
  208. font-size: calc(32px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  209. color: #E1EDD9;
  210. line-height: calc(38px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  211. writing-mode: vertical-lr;
  212. letter-spacing: 0.2em;
  213. }
  214. >p:nth-of-type(1) {
  215. margin-left: calc(30px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  216. }
  217. >p:nth-of-type(2) {
  218. margin-left: calc(12px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  219. >img.pin-yin{
  220. position: absolute;
  221. bottom: calc(115px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  222. right: calc(-6px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  223. width: calc(9px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  224. height: calc(13px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  225. }
  226. }
  227. }
  228. >button.view-img{
  229. position: absolute;
  230. left: calc(35px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  231. bottom: calc(55px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  232. width: calc(48px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  233. height: calc(48px / v-bind('windowHeightDesign') * v-bind('windowHeight'));
  234. >img{
  235. width: 100%;
  236. height: 100%;
  237. }
  238. }
  239. }
  240. </style>