Kaynağa Gözat

制作首页跟展馆页

zhibin 6 yıl önce
ebeveyn
işleme
9f292200f5

+ 16 - 0
src/App.vue

@@ -5,7 +5,23 @@
 </template>
 
 <script>
+import '@/assets/style/public.css'
+
 export default {
   name: 'App'
 }
 </script>
+
+<style scoped>
+#app {
+  width: 100%;
+  height: 100%;
+  background: url('~@/assets/images/background.png') no-repeat center center / cover;
+}
+
+@media (-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio: 2) {
+  #app {
+    background-image: url('~@/assets/images/background@2x.png');
+  }
+}
+</style>

BIN
src/assets/images/3.png


BIN
src/assets/images/3@2x.png


BIN
src/assets/images/background.png


BIN
src/assets/images/background@2x.png


BIN
src/assets/images/item1.png


BIN
src/assets/images/item1@2x.png


BIN
src/assets/images/item2.png


BIN
src/assets/images/item2@2x.png


BIN
src/assets/images/item3.png


BIN
src/assets/images/item3@2x.png


BIN
src/assets/images/item_top1.png


BIN
src/assets/images/item_top1@2x.png


BIN
src/assets/images/item_top2.png


BIN
src/assets/images/item_top2@2x.png


BIN
src/assets/images/item_top3.png


BIN
src/assets/images/item_top3@2x.png


BIN
src/assets/images/light.png


BIN
src/assets/images/light@2x.png


+ 22 - 0
src/assets/style/public.css

@@ -0,0 +1,22 @@
+html,body,h1,h2,h3,h4,h5,h6,div,dl,dt,dd,ul,ol,li,p,blockquote,pre,hr,figure,table,caption,th,td,form,fieldset,legend,input,button,textarea,menu{margin:0;padding:0;}
+header,footer,section,article,aside,nav,hgroup,address,figure,figcaption,menu,details{display:block;}
+table{border-collapse:collapse;border-spacing:0;}
+caption,th{text-align:left;font-weight:normal;}
+html,body,fieldset,img,iframe,abbr{border:0;}
+i,cite,em,var,address,dfn{font-style:normal;}
+[hidefocus],summary{outline:0;}
+li{list-style:none;}
+h1,h2,h3,h4,h5,h6,small{font-size:100%;}
+sup,sub{font-size:83%;}
+pre,code,kbd,samp{font-family:inherit;}
+q:before,q:after{content:none;}
+textarea{overflow:auto;resize:none;}
+label,summary{cursor:default;}
+a,button{cursor:pointer;}
+h1,h2,h3,h4,h5,h6,em,strong,b{font-weight:bold;}
+del,ins,u,s,a,a:hover{text-decoration:none;}
+body,textarea,input,button,select,keygen,legend{font:12px/1.14 'Microsoft YaHei',\5b8b\4f53;color:#333;outline:0;}
+body{background:#fff;}
+a,a:hover{color:#fff;}
+*{box-sizing: border-box}
+html, body {width: 100%; height: 100%}

+ 205 - 0
src/components/slide/index.vue

@@ -0,0 +1,205 @@
+<template>
+  <div class="slide-layout" ref="layout">
+    <div class="slide-content"
+      :class="{animation: !pauseAnimation}"
+      :style="{
+        transform: 'translateX(' + (left + activeLeft) + 'px)',
+        width: contentWidth + 'px',
+      }">
+      <div v-for="(item, i) in slideItems" :key="i"
+        class="slide-item"
+        :class="{active: i === showActive}"
+        :style="{width: itemWidth + 'px', transform: 'translateX(' + i + '00%)'}">
+        <slot name="item" :data="item" :active="i === showActive" :index="i - extend" />
+      </div>
+    </div>
+    <div class="slide-control" v-if="ctrl">
+      <slot v-for="(item, i) in items" name="ctrl-item" :index="i" :active="i === mapActive" />
+    </div>
+  </div>
+</template>
+
+<script>
+
+function extendItems (items, extend) {
+  let result = [...items]
+  if (items.length <= 1) return result
+
+  let insertBefore = items.length - 1
+  let insertAfter = 0
+
+  for (var i = 0; i < extend; i++) {
+    if (insertAfter >= items.length) {
+      insertAfter = 0
+    }
+    if (insertBefore < 0) {
+      insertBefore = items.length - 1
+    }
+
+    result.push(items[insertAfter])
+    result.unshift(items[insertBefore])
+    insertBefore--
+    insertAfter++
+  }
+
+  return result
+}
+
+export default {
+  name: 'slide',
+  props: {
+    items: {
+      default: () => [],
+      type: Array
+    },
+    ctrl: {
+      default: false
+    },
+    extend: {
+      default: 1,
+      type: Number
+    },
+    focus: {
+      default: 0,
+      type: Number
+    }
+  },
+  data () {
+    let slideItems = extendItems(this.items, this.extend)
+
+    return {
+      slideItems,
+      active: 0,
+      mapActive: 0,
+      animations: [],
+      pauseAnimation: true,
+      outWidth: window.outerWidth,
+      activeLeft: 0
+    }
+  },
+  computed: {
+    itemWidth () {
+      return this.outWidth
+    },
+    contentWidth () {
+      return this.slideItems.length * this.outWidth
+    },
+    showActive () {
+      return this.slideItems.length === 1 ? 0 : this.active + this.extend
+    },
+    left () {
+      return -this.showActive * this.itemWidth
+    }
+  },
+  watch: {
+    focus: {
+      immediate: true,
+      handler (newVal) {
+        this.active = newVal
+      }
+    },
+    active (newVal) {
+      let newActive = null
+      if (newVal === -1) {
+        newActive = this.items.length - 1
+      } else if (newVal >= this.items.length) {
+        newActive = 0
+      }
+      if (newActive !== null) {
+        this.mapActive = newActive
+
+        clearTimeout(this.timeout1)
+        this.timeout1 = setTimeout(() => {
+          this.pauseAnimation = true
+          setTimeout(() => {
+            this.active = newActive
+            setTimeout(() => {
+              this.pauseAnimation = false
+            }, 16)
+          })
+        }, 300)
+      } else {
+        this.mapActive = this.active
+      }
+    },
+    mapActive: {
+      immediate: true,
+      handler (newVal) {
+        this.$emit('slidechange', this.items[newVal], newVal)
+      }
+    }
+  },
+  methods: {
+    next () {
+      this.active++
+    },
+    prev () {
+      this.active--
+    },
+    startHandle (ev) {
+      this.pauseAnimation = true
+      this.startX = ev.touches[0].clientX
+    },
+    moveHandle (ev) {
+      this.activeLeft = ev.touches[0].clientX - this.startX
+    },
+    endHandle (ev) {
+      if (this.activeLeft > 100) {
+        this.prev()
+      } else if (this.activeLeft < -100) {
+        this.next()
+      }
+      this.pauseAnimation = false
+      this.activeLeft = 0
+    }
+  },
+  mounted () {
+    setTimeout(() => {
+      this.pauseAnimation = false
+    })
+    this.outWidth = this.$refs.layout.offsetWidth
+    this.startHandle = this.startHandle.bind(this)
+    this.moveHandle = this.moveHandle.bind(this)
+    this.endHandle = this.endHandle.bind(this)
+    this.$refs.layout.addEventListener('touchstart', this.startHandle, false)
+    this.$refs.layout.addEventListener('touchmove', this.moveHandle, false)
+    this.$refs.layout.addEventListener('touchend', this.endHandle, false)
+  },
+  beforeDestroy () {
+    this.$refs.layout.removeEventListener('touchstart', this.startHandle, false)
+    this.$refs.layout.removeEventListener('touchmove', this.moveHandle, false)
+    this.$refs.layout.removeEventListener('touchend', this.endHandle, false)
+  }
+}
+</script>
+
+<style scoped>
+.slide-layout {
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+}
+
+.slide-content {
+  height: 100%;
+  position: relative;
+}
+
+.slide-item {
+  height: 100%;
+  overflow: hidden;
+  position: absolute;
+  top: 0;
+}
+
+.animation {
+  transition: all .2s linear;
+}
+
+.slide-control {
+  position: absolute;
+  bottom: 7.5%;
+  left: 50%;
+  transform: translateX(-50%);
+}
+</style>

+ 33 - 0
src/pages/collection/index.vue

@@ -0,0 +1,33 @@
+<template>
+  <div class="layout" style="width: 80%; height: 80%">
+    <slide :items="items">
+      <div slot="item" slot-scope="{data}" class="item" @click="clickHandle(data)">
+        {{1}}
+      </div>
+    </slide>
+  </div>
+</template>
+
+<script>
+import slide from '@/components/slide'
+
+export default {
+  name: 'collection',
+  data () {
+    return {
+      items: [1, 2, 3]
+    }
+  },
+  methods: {
+    clickHandle () {
+    }
+  },
+  components: {slide}
+}
+</script>
+
+<style scoped>
+.item {
+  background-color: #fff;
+}
+</style>

+ 101 - 0
src/pages/exhibition/index.vue

@@ -0,0 +1,101 @@
+<template>
+  <div class="exh-layout">
+    <slide :items="items" class="slide-layout" :extend="3" :focus="focus" @slidechange="changeHandle">
+      <div slot="item"
+        slot-scope="{data, index}"
+        class="item"
+        @click="clickHandle(index)">
+        {{data}}
+      </div>
+    </slide>
+
+    <div class="ext-name">
+      <h3>{{title}}</h3>
+    </div>
+  </div>
+</template>
+
+<script>
+import slide from '@/components/slide'
+
+export default {
+  name: 'collection',
+  data () {
+    return {
+      items: ['展馆名称1', '展馆名称2', '展馆名称3'],
+      focus: 0,
+      title: ''
+    }
+  },
+  methods: {
+    clickHandle (index) {
+      if (this.focus === index) {
+        console.log(this.title)
+      } else {
+        this.focus = index
+      }
+    },
+    changeHandle (item) {
+      this.title = item
+    }
+  },
+  components: {slide}
+}
+</script>
+
+<style scoped>
+.exh-layout {
+  overflow: hidden;
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
+.slide-layout {
+  margin-top: 10%;
+  flex: 0 0 auto;
+}
+
+.ext-name {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.ext-name h3 {
+  font-size: 21px;
+  font-weight: 300;
+  color: #B48A4E
+}
+
+.item {
+  background-color: #fff;
+  height: 100%;
+  width: 100%;
+  border-radius: 8px;
+}
+
+</style>
+
+<style>
+.exh-layout .slide-layout {
+  width: 72% !important;
+  height: 68.4% !important;
+  overflow: initial !important;
+  margin-left:auto;
+  margin-right: auto;
+}
+
+.exh-layout .slide-layout .slide-item {
+  padding: 14px;
+}
+
+.exh-layout .slide-layout .slide-item.active {
+  padding: 0;
+}
+
+.exh-layout .slide-layout .animation .slide-item {
+  transition: all .3s linear;
+}
+</style>

+ 130 - 4
src/pages/home/index.vue

@@ -1,16 +1,142 @@
 <template>
-  <div class="hello">
+  <div class="layout">
+    <slide :items="items" :ctrl="true">
+      <div slot="item" slot-scope="{data}" class="item" @click="clickHandle(data)">
+        <div class="top">
+          <img :src="data.x.background" :srcset="data.x.background + ' 1x,' + data['2x'].background + ' 2x'">
+        </div>
+        <h3 class="title">{{data.title}}</h3>
+        <div class="content">
+          <img :src="data.x.image" :srcset="data.x.image + ' 1x,' + data['2x'].image + ' 2x'">
+        </div>
+      </div>
 
+      <a slot="ctrl-item" class="ctrl-item" slot-scope="{active}" :class="{active: active}"></a>
+    </slide>
   </div>
 </template>
 
 <script>
+import slide from '@/components/slide'
+
 export default {
-  name: 'HelloWorld',
+  name: 'home',
   data () {
     return {
-      msg: 'Welcome to Your Vue.js App'
+      items: [
+        {
+          view: 'collection',
+          title: '藏品',
+          'x': {
+            background: require('@/assets/images/item_top1.png'),
+            image: require('@/assets/images/item1.png')
+          },
+          '2x': {
+            background: require('@/assets/images/item_top1@2x.png'),
+            image: require('@/assets/images/item1@2x.png')
+          }
+        },
+        {
+          title: '国度',
+          'x': {
+            background: require('@/assets/images/item_top2.png'),
+            image: require('@/assets/images/item2.png')
+          },
+          '2x': {
+            background: require('@/assets/images/item_top2@2x.png'),
+            image: require('@/assets/images/item2@2x.png')
+          }
+        },
+        {
+          view: 'exhibition',
+          title: '展馆',
+          'x': {
+            background: require('@/assets/images/item_top3.png'),
+            image: require('@/assets/images/item3.png')
+          },
+          '2x': {
+            background: require('@/assets/images/item_top3@2x.png'),
+            image: require('@/assets/images/item3@2x.png')
+          }
+        }
+      ]
     }
-  }
+  },
+  methods: {
+    clickHandle (data) {
+      this.$router.push({name: data.view})
+    }
+  },
+  components: {slide}
 }
 </script>
+
+<style scoped>
+.layout {
+  width: 100%;
+  height: 100%;
+}
+
+.item {
+  position: absolute;
+  top: 0;
+  width: 100%;
+  left: 0;
+  bottom: calc(8% + 16px);
+  overflow: hidden;
+}
+
+.top {
+  text-align: center;
+  position: absolute;
+  top: 0;
+}
+
+.top img {
+  width: 72%;
+  transform: translateY(-50%);
+}
+
+.title {
+  position: absolute;
+  top: 30%;
+  width: 100%;
+  font-size: 20px;
+  font-weight: 300;
+  color: #B48A4E;
+  text-align: center;
+}
+
+.content {
+  position: absolute;
+  bottom: 0;
+  text-align: center;
+  background: url('~@/assets/images/light.png') no-repeat bottom center / 61.6% auto;
+  width: 100%;
+  padding: 0 15% 18%;
+}
+
+.content img {
+  width: 92%;
+}
+
+.ctrl-item {
+  --color: #B48A4E;
+  display: inline-block;
+  width: 8px;
+  height: 8px;
+  border: 1px solid var(--color);
+  margin: 0 14px;
+  transform: rotateZ(45deg)
+}
+
+.ctrl-item.active {
+  background: var(--color);
+}
+
+@media (-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio: 2) {
+  .content {
+    background-image: url('~@/assets/images/light@2x.png');
+  }
+}
+</style>

+ 12 - 0
src/router/index.js

@@ -1,6 +1,8 @@
 import Vue from 'vue'
 import Router from 'vue-router'
 import Home from '@/pages/home/'
+import Collection from '@/pages/collection/'
+import Exhibition from '@/pages/exhibition/'
 
 Vue.use(Router)
 
@@ -10,6 +12,16 @@ export default new Router({
       path: '/',
       name: 'Home',
       component: Home
+    },
+    {
+      path: '/collection',
+      name: 'collection',
+      component: Collection
+    },
+    {
+      path: '/exhibition',
+      name: 'exhibition',
+      component: Exhibition
     }
   ]
 })