|
@@ -0,0 +1,338 @@
|
|
|
+<template>
|
|
|
+ <div
|
|
|
+ class="home"
|
|
|
+ >
|
|
|
+ <div class="lion-male">
|
|
|
+ <img
|
|
|
+ class="lion"
|
|
|
+ src="@/assets/images/lion-male.png"
|
|
|
+ alt=""
|
|
|
+ draggable="false"
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ <button
|
|
|
+ class="lion-female"
|
|
|
+ @click="isHideMenu = !isHideMenu"
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ class="lion"
|
|
|
+ src="@/assets/images/lion-female.png"
|
|
|
+ alt=""
|
|
|
+ draggable="false"
|
|
|
+ >
|
|
|
+ </button>
|
|
|
+ <menu :class="{hide: isHideMenu}">
|
|
|
+ <div
|
|
|
+ v-for="(item1, idx) in menu"
|
|
|
+ :key="idx"
|
|
|
+ class="level1"
|
|
|
+ >
|
|
|
+ <h2>第{{ idx + 1 }}章 {{ item1.name }}</h2>
|
|
|
+ <div
|
|
|
+ v-for="(item2, idx) in item1.children"
|
|
|
+ :key="idx"
|
|
|
+ class="level2"
|
|
|
+ >
|
|
|
+ <h3> {{ item2.name }}</h3>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </menu>
|
|
|
+
|
|
|
+ <button
|
|
|
+ v-for="(item, idx) in menu"
|
|
|
+ :key="idx"
|
|
|
+ class="label"
|
|
|
+ :style="{
|
|
|
+ left: labelPosList.value[idx]?.x + 'px' || '-500px',
|
|
|
+ bottom: labelPosList.value[idx]?.y + 'px' || '-500px',
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ :style="{
|
|
|
+ letterSpacing: (6 / item.name.length - 1) * 20 + 'px',
|
|
|
+ marginTop: (6 / item.name.length - 1) * 20 + 'px',
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ {{ item.name }}
|
|
|
+ </div>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { onMounted, onUnmounted, watch, ref, reactive, computed } from "vue"
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'HomeView',
|
|
|
+ setup() {
|
|
|
+ const bgImgWidth = 1920
|
|
|
+ const bgImgHeight = 1080
|
|
|
+ const labelPosList = reactive({ value: [] })
|
|
|
+ function computeActualWindowRatio() {
|
|
|
+ labelPosList.value = []
|
|
|
+ for (const iterator of menu) {
|
|
|
+ labelPosList.value.push(getLabelPos(iterator.pos))
|
|
|
+ }
|
|
|
+ console.log(labelPosList)
|
|
|
+ }
|
|
|
+ onMounted(() => {
|
|
|
+ computeActualWindowRatio()
|
|
|
+ window.addEventListener('resize', computeActualWindowRatio)
|
|
|
+ })
|
|
|
+ onUnmounted(() => {
|
|
|
+ window.removeEventListener('resize', computeActualWindowRatio)
|
|
|
+ })
|
|
|
+ // true: 实际窗口更宽扁,背景图与实际窗口等宽,上下被裁减
|
|
|
+ // false: 实际窗口更窄高,背景图与实际窗口等高,左右被裁减
|
|
|
+
|
|
|
+ function getLabelPos(posRaw) {
|
|
|
+ if (window.innerWidth / window.innerHeight > bgImgWidth / bgImgHeight) {
|
|
|
+ const scale = window.innerWidth / bgImgWidth
|
|
|
+ return {
|
|
|
+ x: posRaw.x * scale,
|
|
|
+ y: posRaw.y * scale - (bgImgHeight * scale - window.innerHeight) / 2,
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ const scale = window.innerHeight / bgImgHeight
|
|
|
+ return {
|
|
|
+ x: posRaw.x * scale - (bgImgWidth * scale - window.innerWidth) / 2,
|
|
|
+ y: posRaw.y * scale,
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const isHideMenu = ref(true)
|
|
|
+ const menu = reactive([
|
|
|
+ {
|
|
|
+ name: '桃花源里人家',
|
|
|
+ pos: {
|
|
|
+ x: 540,
|
|
|
+ y: 273,
|
|
|
+ },
|
|
|
+
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ name: '文化溯源',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '画里乡村',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '水口园林',
|
|
|
+ },
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '牌坊',
|
|
|
+ pos: {
|
|
|
+ x: 248,
|
|
|
+ y: 414,
|
|
|
+ },
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ name: '认识牌坊',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '牌坊形制',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '牌坊构造',
|
|
|
+ },
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '祠堂',
|
|
|
+ pos: {
|
|
|
+ x: 1247,
|
|
|
+ y: 591,
|
|
|
+ },
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ name: '认识祠堂',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '祠堂的建筑艺术 ①',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '祠堂的建筑艺术 ②',
|
|
|
+ },
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '民居',
|
|
|
+ pos: {
|
|
|
+ x: 1389,
|
|
|
+ y: 355,
|
|
|
+ },
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ name: '认识民居',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '民居的营造 ①',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '民居的营造 ②',
|
|
|
+ },
|
|
|
+ ]
|
|
|
+ }, {
|
|
|
+ name: '匠心独运',
|
|
|
+ pos: {
|
|
|
+ x: 928,
|
|
|
+ y: 657,
|
|
|
+ },
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ name: '榫卯技艺',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '雕刻艺术 ①',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '雕刻艺术 ②',
|
|
|
+ },
|
|
|
+ ]
|
|
|
+ }, {
|
|
|
+ name: '拾遗',
|
|
|
+ pos: {
|
|
|
+ x: 746,
|
|
|
+ y: 446,
|
|
|
+ },
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ name: '其他建筑类型鉴赏',
|
|
|
+ },
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ ])
|
|
|
+
|
|
|
+ return {
|
|
|
+ labelPosList,
|
|
|
+ isHideMenu,
|
|
|
+ menu,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ ...mapState([
|
|
|
+ ]),
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ console.log(process.env)
|
|
|
+ this.$mitt.emit('test', { msg: 'home mounted' })
|
|
|
+ },
|
|
|
+ unmounted() {
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ ...mapMutations([
|
|
|
+ ]),
|
|
|
+
|
|
|
+ },
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="less" scoped>
|
|
|
+.home {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ background-image: url(@/assets/images/bg-home.jpg);
|
|
|
+ background-size: cover;
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ background-position: center center;
|
|
|
+ position: relative;
|
|
|
+ >.lion-male {
|
|
|
+ position: absolute;
|
|
|
+ width: 219px;
|
|
|
+ height: 206px;
|
|
|
+ left: 78px;
|
|
|
+ bottom: 48px;
|
|
|
+ >img {
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ top: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ >.lion-female {
|
|
|
+ position: absolute;
|
|
|
+ width: 150px;
|
|
|
+ height: 193px;
|
|
|
+ right: 0;
|
|
|
+ top: 129px;
|
|
|
+ >img {
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ top: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ >menu {
|
|
|
+ position: absolute;
|
|
|
+ padding-top: 35px;
|
|
|
+ padding-left: 66px;
|
|
|
+ padding-bottom: 25px;
|
|
|
+ width: 360px;
|
|
|
+ height: 765px;
|
|
|
+ top: 12px;
|
|
|
+ right: 22px;
|
|
|
+ background-image: url(@/assets/images/bg-menu.png);
|
|
|
+ background-size: contain;
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ background-position: center center;
|
|
|
+ counter-reset: lalala;
|
|
|
+ transition: all 1s;
|
|
|
+ >.level1 {
|
|
|
+ font-size: 24px;
|
|
|
+ font-family: Source Han Sans CN-Bold, Source Han Sans CN;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #2D241D;
|
|
|
+ line-height: 1.3;
|
|
|
+ margin-bottom: 24px;
|
|
|
+ cursor: pointer;
|
|
|
+ >.level2 {
|
|
|
+ font-size: 18px;
|
|
|
+ font-family: Source Han Sans CN-Regular, Source Han Sans CN;
|
|
|
+ font-weight: 400;
|
|
|
+ color: #2D241D;
|
|
|
+ line-height: 1.3;
|
|
|
+ margin-bottom: 3px;
|
|
|
+ >h3 {
|
|
|
+ counter-increment: lalala;
|
|
|
+ &::before {
|
|
|
+ display: inline-block;
|
|
|
+ content: '第' counter(lalala) '课';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.hide {
|
|
|
+ transform: translateX(110%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ >.label {
|
|
|
+ width: 55px;
|
|
|
+ height: 267px;
|
|
|
+ background-image: url(@/assets/images/label-bg.png);
|
|
|
+ background-size: cover;
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ background-position: center center;
|
|
|
+ position: absolute;
|
|
|
+ font-size: 26px;
|
|
|
+ font-family: Source Han Sans CN-Regular, Source Han Sans CN;
|
|
|
+ font-weight: 400;
|
|
|
+ color: #2D241D;
|
|
|
+ writing-mode: vertical-lr;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ >div {
|
|
|
+ transform: translateX(-3px);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|