PoemList.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. <template>
  2. <div class="poem-list-page">
  3. <Transition name="fade-in-out">
  4. <img
  5. v-if="getTypesettingIdx(currentPoem['类型']) === 1"
  6. class="bg"
  7. src="@/assets/images/poem-list-bg-1.jpg"
  8. alt=""
  9. draggable="false"
  10. >
  11. <img
  12. v-else-if="getTypesettingIdx(currentPoem['类型']) === 2"
  13. class="bg"
  14. src="@/assets/images/poem-list-bg-2.jpg"
  15. alt=""
  16. draggable="false"
  17. >
  18. <img
  19. v-else-if="getTypesettingIdx(currentPoem['类型']) === 3"
  20. class="bg"
  21. src="@/assets/images/poem-list-bg-3.jpg"
  22. alt=""
  23. draggable="false"
  24. >
  25. <img
  26. v-else
  27. class="bg"
  28. src="@/assets/images/poem-list-bg-4.jpg"
  29. alt=""
  30. draggable="false"
  31. >
  32. </Transition>
  33. <Swiper
  34. class="poem-list"
  35. :slides-per-view="1"
  36. direction="vertical"
  37. @swiper="onSwiper"
  38. @slideChange="onSlideChange"
  39. >
  40. <SwiperSlide
  41. v-for="(item, index) in poemList"
  42. :key="index"
  43. class="poem-item"
  44. :class="[`typesetting-${getTypesettingIdx(item['类型'])}`]"
  45. >
  46. <div class="inner-wrap">
  47. <div class="title-wrap">
  48. <h1>《{{ item['标题'] }}》</h1>
  49. <div class="sub-title">
  50. <span class="author">{{ item['作者'] }}</span>
  51. <span class="age">{{ item['朝代'] }}</span>
  52. </div>
  53. </div>
  54. <p>{{ item['正文'] }}</p>
  55. </div>
  56. </SwiperSlide>
  57. </Swiper>
  58. <BtnBack
  59. v-show="!isShowMenu"
  60. class="button-back"
  61. @click="emit('close')"
  62. />
  63. <OperationTip
  64. class="operation-tip"
  65. text="下一首"
  66. :is-show="isShowOperationTip"
  67. />
  68. <button
  69. v-show="!isShowMenu"
  70. class="menu-btn"
  71. @click="isShowMenu = true"
  72. >
  73. <img
  74. class=""
  75. src="@/assets/images/icon_menu.png"
  76. alt=""
  77. draggable="false"
  78. >
  79. </button>
  80. <Transition name="fade-in-out">
  81. <menu v-show="isShowMenu">
  82. <ul>
  83. <button
  84. v-for="(item, index) in menuList"
  85. :key="index"
  86. @click="onClickMenuItem(item)"
  87. >
  88. <img
  89. class="bg"
  90. :src="require(`@/assets/images/poem-menu-item-bg${item === currentPoem['朝代'] ? '-active' : ''}.png`)"
  91. alt=""
  92. draggable="false"
  93. :style="{
  94. transform: `rotate(${90 * (index % 5)}deg)`
  95. }"
  96. >
  97. <span>{{ item }}</span>
  98. </button>
  99. </ul>
  100. <button
  101. class="close"
  102. @click="isShowMenu = false"
  103. >
  104. <img
  105. class=""
  106. src="@/assets/images/icon_close.png"
  107. alt=""
  108. draggable="false"
  109. >
  110. </button>
  111. </menu>
  112. </Transition>
  113. </div>
  114. </template>
  115. <script setup>
  116. import { ref, computed, watch, onMounted, inject } from "vue"
  117. import { useRoute, useRouter } from "vue-router"
  118. import { useStore } from "vuex"
  119. import useSizeAdapt from "@/useFunctions/useSizeAdapt"
  120. const route = useRoute()
  121. const router = useRouter()
  122. const store = useStore()
  123. const $env = inject('$env')
  124. const {
  125. windowSizeInCssForRef,
  126. windowSizeWhenDesignForRef,
  127. } = useSizeAdapt()
  128. const emit = defineEmits(['close'])
  129. const poemList = configExcel['诗词']
  130. /**
  131. * 当前古诗
  132. */
  133. const currentIdx = ref(0)
  134. const currentPoem = computed(() => {
  135. return poemList[currentIdx.value]
  136. })
  137. /**
  138. * 排版
  139. */
  140. function getTypesettingIdx(poemType) {
  141. switch (poemType) {
  142. case '七绝':
  143. return 1
  144. case '七律':
  145. return 2
  146. case '五绝':
  147. return 3
  148. case '五律':
  149. return 4
  150. default:
  151. return 2
  152. }
  153. }
  154. /**
  155. * swiper
  156. */
  157. let swiper = null
  158. const onSwiper = (swiperP) => {
  159. swiper = swiperP
  160. }
  161. const onSlideChange = (e) => {
  162. currentIdx.value = e.activeIndex
  163. }
  164. /**
  165. * 操作提示
  166. */
  167. const isShowOperationTip = ref(true)
  168. watch(currentIdx, (v) => {
  169. if (isShowOperationTip.value) {
  170. isShowOperationTip.value = false
  171. }
  172. })
  173. /**
  174. * 目录
  175. */
  176. const isShowMenu = ref(false)
  177. const temp = configExcel['诗词'].map((item) => {
  178. return item['朝代']
  179. })
  180. const menuList = Array.from(new Set(temp))
  181. function onClickMenuItem(menuItemName) {
  182. const targetIdx = poemList.findIndex((item) => {
  183. return item['朝代'] === menuItemName
  184. })
  185. swiper.slideTo(targetIdx)
  186. isShowMenu.value = false
  187. }
  188. </script>
  189. <style lang="less" scoped>
  190. .poem-list-page{
  191. position: absolute;
  192. left: 0;
  193. top: 0;
  194. width: 100%;
  195. height: 100%;
  196. background-color: #dde6db;
  197. ::-webkit-scrollbar { width: 0; height: 0; }
  198. >.bg{
  199. position: absolute;
  200. left: 0;
  201. top: 0;
  202. width: 100%;
  203. height: 100%;
  204. object-fit: cover;
  205. }
  206. >.poem-list{
  207. position: absolute;
  208. left: 0;
  209. top: 0;
  210. width: 100%;
  211. height: 100%;
  212. overflow: auto;
  213. .poem-item{
  214. display: flex;
  215. justify-content: center;
  216. align-items: center;
  217. width: 100%;
  218. height: 100%;
  219. writing-mode: vertical-rl;
  220. position: relative;
  221. .inner-wrap{
  222. >.title-wrap{
  223. position: relative;
  224. width: fit-content;
  225. height: fit-content;
  226. >h1{
  227. font-family: KingHwa_OldSong, KingHwa_OldSong;
  228. font-weight: 400;
  229. font-size: calc(36 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  230. color: #476446;
  231. line-height: calc(36 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  232. white-space: pre;
  233. letter-spacing: 0.1em;
  234. }
  235. >.sub-title{
  236. position: absolute;
  237. left: 0;
  238. top: 50%;
  239. transform: translate(-140%, -50%);
  240. display: flex;
  241. align-items: center;
  242. >.author{
  243. white-space: pre;
  244. font-family: KaiTi, KaiTi;
  245. font-weight: 400;
  246. font-size: 20px;
  247. color: #476446;
  248. letter-spacing: 0.3em;
  249. margin-inline-end: calc(6 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  250. }
  251. >.age{
  252. display: inline-block;
  253. width: calc(21 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  254. height: calc(21 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  255. background-color: #b6a261;
  256. border-radius: 50%;
  257. display: flex;
  258. justify-content: center;
  259. align-items: center;
  260. font-family: KaiTi, KaiTi;
  261. font-weight: 400;
  262. font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  263. color: #FFFFFF;
  264. }
  265. }
  266. }
  267. >p{
  268. margin-right: calc(60 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  269. font-family: KaiTi, KaiTi;
  270. font-weight: 400;
  271. font-size: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  272. color: #476446;
  273. line-height: 1.8em;
  274. white-space: pre;
  275. letter-spacing: 0.2em;
  276. }
  277. }
  278. }
  279. .poem-item.typesetting-1{
  280. >.inner-wrap{
  281. transform: translate(10%, -20%);
  282. >p{
  283. margin-top: calc(232 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  284. }
  285. }
  286. }
  287. .poem-item.typesetting-2{
  288. >.inner-wrap{
  289. transform: translate(10%, -4%);
  290. >p{
  291. margin-top: calc(102 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  292. }
  293. }
  294. }
  295. .poem-item.typesetting-3{
  296. >.inner-wrap{
  297. transform: translate(0, -9%);
  298. >p{
  299. margin-top: calc(135 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  300. }
  301. }
  302. }
  303. .poem-item.typesetting-4{
  304. >.inner-wrap{
  305. transform: translate(10%, -10%);
  306. >p{
  307. margin-top: calc(200 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  308. }
  309. }
  310. }
  311. }
  312. >.button-back{
  313. z-index: 10;
  314. }
  315. >.operation-tip{
  316. position: absolute;
  317. left: 50%;
  318. bottom: calc(17 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  319. transform: translateX(-50%);
  320. z-index: 10;
  321. }
  322. >.menu-btn{
  323. position: absolute;
  324. right: calc(17 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  325. bottom: calc(17 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  326. z-index: 10;
  327. width: calc(30 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  328. height: calc(30 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  329. >img{
  330. width: calc(24 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  331. height: calc(24 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  332. }
  333. }
  334. >menu{
  335. position: absolute;
  336. left: 0;
  337. top: 0;
  338. width: 100%;
  339. height: 100%;
  340. background: rgba(38,55,38,0.6);
  341. border-radius: 0px 0px 0px 0px;
  342. backdrop-filter: blur(calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef')));
  343. z-index: 15;
  344. >ul{
  345. position: absolute;
  346. left: 50%;
  347. top: 50%;
  348. transform: translate(-50%, -50%);
  349. display: flex;
  350. flex-direction: column;
  351. justify-content: center;
  352. align-items: center;
  353. gap: calc(39 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  354. >button{
  355. width: calc(56 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  356. height: calc(56 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  357. font-family: KingHwa_OldSong, KingHwa_OldSong;
  358. font-weight: 400;
  359. font-size: calc(36 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  360. color: #FFFFFF;
  361. position: relative;
  362. >img.bg{
  363. position: absolute;
  364. left: 0;
  365. top: 0;
  366. width: 100%;
  367. height: 100%;
  368. }
  369. }
  370. }
  371. >button.close{
  372. position: absolute;
  373. right: calc(17 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  374. bottom: calc(17 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  375. z-index: 10;
  376. width: calc(30 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  377. height: calc(30 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  378. >img{
  379. width: calc(24 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  380. height: calc(24 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  381. }
  382. }
  383. }
  384. }
  385. </style>