瀏覽代碼

NavBar 组件

冯诚 3 年之前
父節點
當前提交
77992592de

二進制
src/assets/apple.png


二進制
src/assets/check.png


二進制
src/assets/close.png


二進制
src/assets/close2.png


二進制
src/assets/coupon.png


二進制
src/assets/facebook.png


二進制
src/assets/google.png


二進制
src/assets/home.png


二進制
src/assets/lite.png


二進制
src/assets/logo.png


二進制
src/assets/logo2.png


二進制
src/assets/m-coupon.png


二進制
src/assets/m-exit.png


二進制
src/assets/m-friend.png


二進制
src/assets/m-info.png


二進制
src/assets/m-order.png


二進制
src/assets/m-repair.png


二進制
src/assets/menu.png


二進制
src/assets/pro.png


二進制
src/assets/success.png


二進制
src/assets/user.png


二進制
src/assets/warn.png


+ 372 - 0
src/components/nav-bar/index.vue

@@ -0,0 +1,372 @@
+<template>
+  <div :class="['nav-bar-wrap', { 'nav-bar-wrap--fixed': fixed }]">
+    <div class="nav-bar">
+      <i v-if="showNavIcons" class="icon-menu" @click="showMenu = true"></i>
+      <i class="icon-logo"></i>
+      <i v-if="showNavIcons" class="icon-mine" @click="showMine = true"></i>
+    </div>
+    <transition enter-active-class="fadeIn" leave-active-class="fadeOut">
+      <div v-if="showMenu" class="nav-panel nav-panel-menu">
+        <div class="header">
+          <i class="logo"></i>
+          <i class="close" @click="showMenu = false"></i>
+        </div>
+        <div class="body">
+          <ul class="menu">
+            <li class="menu-item">REPAIR BOOKING</li>
+            <li class="menu-item">ONLINE SHOP</li>
+            <li class="menu-item">PTC Care Plus</li>
+            <li class="menu-item">SOTRE LOCATION</li>
+            <li class="menu-item">CONTACT US</li>
+          </ul>
+        </div>
+      </div>
+    </transition>
+    <transition enter-active-class="fadeIn" leave-active-class="fadeOut">
+      <div
+        v-if="showMine"
+        class="nav-panel nav-panel-mine"
+        :class="{ 'is-member': 1 }"
+      >
+        <div class="header">
+          <i class="logo"></i>
+          <i class="close" @click="showMine = false"></i>
+        </div>
+        <div class="body">
+          <div class="info">
+            <div class="p1">
+              <p class="name">Hi, Rebecca</p>
+              <p class="intro">Ordinary member</p>
+            </div>
+            <div v-if="0" class="p2">
+              <p class="txt">You have not purchased a member</p>
+              <button class="btn">BUY</button>
+            </div>
+            <div v-else class="p3">
+              <div class="txt">
+                $10 off for additional services |
+                <span class="ptc-text fw600">Buy now ></span>
+              </div>
+              <div class="swiper">
+                <div class="swiper-item">
+                  <div class="service">
+                    <div class="service-title">
+                      <i class="service-icon icon-lite"></i>
+                      <div class="service-type">Lite</div>
+                      <div class="service-period">2021/09/01 to 2022/08/31</div>
+                    </div>
+                    <div class="service-model tac">iPhone 12</div>
+                    <div class="service-code tac">QWERTYUIO12345678</div>
+                  </div>
+                </div>
+              </div>
+              <div class="pagination">
+                <i class="dot active"></i>
+                <i class="dot"></i>
+                <i class="dot"></i>
+              </div>
+            </div>
+          </div>
+          <ul class="list">
+            <li class="item">MY REPAIR REQUEST</li>
+            <li class="item">MY ORDER</li>
+            <li class="item">MY DISCOUNT COUPON</li>
+            <li class="item">
+              INVITE FRIENDS <span class="tag">Get a $10 coupon</span>
+            </li>
+            <li class="item">ACCOUNT INFORMATION</li>
+            <li class="item">SIGN OUT</li>
+          </ul>
+        </div>
+      </div>
+    </transition>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue'
+
+interface Props {
+  showNavIcons?: boolean
+  fixed?: boolean
+}
+
+defineProps<Props>()
+
+const showMenu = ref(false)
+const showMine = ref(false)
+</script>
+
+<style lang="scss">
+.nav-bar-wrap {
+  &--fixed {
+    position: fixed;
+    left: 0;
+    top: 0;
+    width: 100%;
+    z-index: 10;
+  }
+
+  .nav-bar {
+    box-sizing: content-box;
+    position: relative;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 0 40px;
+    height: $nav-bar-height;
+    background: #fff;
+    border-bottom: 1px solid #d9d9d9;
+  }
+  .icon-menu {
+    @include icon('@img/menu.png', 44px);
+  }
+  .icon-mine {
+    @include icon('@img/user.png', 44px);
+  }
+  .icon-logo {
+    @include icon('@img/logo.png', 130px, 70px);
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -50%);
+  }
+
+  .nav-panel {
+    display: flex;
+    flex-direction: column;
+    position: fixed;
+    left: 0;
+    right: 0;
+    top: 0;
+    bottom: 0;
+    &-menu {
+      background: $primary-color;
+    }
+    &-mine {
+      background: #fff;
+    }
+  }
+  .header {
+    position: relative;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    height: $nav-bar-height;
+
+    .logo {
+      @include icon('@img/logo.png', 130px, 70px);
+    }
+    .close {
+      @include icon('@img/close.png', 44px);
+      position: absolute;
+      top: 50%;
+      transform: translateY(-50%);
+      right: 40px;
+    }
+  }
+  .nav-panel-menu {
+    .logo {
+      background-image: url(@img/logo2.png);
+      transform: scale(1.03);
+    }
+    .close {
+      background-image: url(@img/close2.png);
+    }
+  }
+
+  .body {
+    flex: 1;
+    overflow: auto;
+  }
+
+  .menu {
+    margin-top: 36px;
+    line-height: 144px;
+    font-size: 40px;
+    font-weight: 600;
+    color: #fff;
+
+    &-item {
+      padding-left: 196px;
+      &:active {
+        background: $primary-color-lighten;
+      }
+    }
+  }
+
+  .info {
+    margin: 20px auto 24px;
+    width: 678px;
+  }
+  .p1 {
+    padding: 48px 0 0 50px;
+    height: 202px;
+    color: $primary-color;
+    background: #e9ebf0;
+    border-radius: 8px 8px 0px 0px;
+
+    .name {
+      font-size: 48px;
+      font-weight: 600;
+    }
+    .intro {
+      margin-top: 16px;
+      font-size: 32px;
+    }
+  }
+  .p2 {
+    padding: 48px;
+    height: 224px;
+    border-radius: 0 0 8px 8px;
+    border: 2px solid #e9ebf0;
+
+    .txt {
+      line-height: 44px;
+      font-size: 32px;
+      color: #333;
+    }
+
+    .btn {
+      width: 144px;
+      height: 60px;
+      font-size: 32px;
+      font-weight: 600;
+      color: #fff;
+      background: $primary-color;
+      border-radius: 8px;
+      &:active {
+        background: $primary-color-lighten;
+      }
+    }
+  }
+  .p3 {
+    height: 436px;
+    border-radius: 0 0 8px 8px;
+    background: #e9ebf0;
+
+    .txt {
+      padding: 24px 36px 24px 48px;
+      font-size: 30px;
+      color: #333;
+    }
+
+    .swiper {
+      padding-left: 44px;
+    }
+    .service {
+      padding: 26px 18px;
+      width: 526px;
+      height: 266px;
+      background: #ffffff;
+      border-radius: 8px;
+      &-title {
+        display: flex;
+        align-items: center;
+        font-size: 28px;
+      }
+      &-icon {
+        margin-right: 10px;
+        width: 36px;
+        height: 36px;
+      }
+      &-type {
+        margin-right: 30px;
+        font-weight: bold;
+        color: $primary-color;
+      }
+      &-period {
+        color: #90a0c0;
+      }
+      &-model {
+        margin-top: 48px;
+        font-size: 40px;
+        font-weight: 600;
+        text-align: center;
+      }
+      &-code {
+        margin-top: 8px;
+        font-size: 28px;
+        text-align: center;
+        color: #999;
+      }
+    }
+
+    .pagination {
+      display: flex;
+      justify-content: center;
+      margin-top: 32px;
+
+      .dot {
+        width: 16px;
+        height: 16px;
+        border-radius: 50%;
+        background: rgba(26, 48, 89, 0.3);
+        &.active {
+          background: $primary-color;
+        }
+        + .dot {
+          margin-left: 24px;
+        }
+      }
+    }
+  }
+
+  .list {
+    margin-top: 24px;
+  }
+  .item {
+    position: relative;
+    display: flex;
+    align-items: center;
+    padding-left: 144px;
+    line-height: 144px;
+    font-size: 32px;
+    color: #1a1a1a;
+    background-color: #fff;
+    background-position: 84px center;
+    background-repeat: no-repeat;
+    background-size: 32px 32px;
+    transition: background-color 0.3s ease;
+    &:active {
+      background-color: #f2f5fb;
+    }
+    &:nth-child(1) {
+      background-image: url(@img/m-repair.png);
+    }
+    &:nth-child(2) {
+      background-image: url(@img/m-order.png);
+    }
+    &:nth-child(3) {
+      background-image: url(@img/m-coupon.png);
+    }
+    &:nth-child(4) {
+      background-image: url(@img/m-friend.png);
+    }
+    &:nth-child(5) {
+      background-image: url(@img/m-info.png);
+    }
+    &:nth-child(6) {
+      background-image: url(@img/m-exit.png);
+    }
+
+    .tag {
+      margin-left: 32px;
+      padding: 0 24px;
+      line-height: 52px;
+      font-size: 28px;
+      font-weight: 600;
+      color: #fff;
+      background: $danger-color;
+      border-radius: 30px 4px 30px 4px;
+    }
+  }
+
+  .is-member {
+    .p1 {
+      color: #fff;
+      background: $primary-color;
+    }
+  }
+}
+</style>

+ 4 - 0
src/main.ts

@@ -4,5 +4,9 @@ import router from './router'
 import './utils/rem'
 import './style'
 
+import NavBar from './components/nav-bar/index.vue'
+
 const app = createApp(App)
+app.component('NavBar', NavBar)
+
 app.use(router).mount('#app')

+ 2 - 16
src/pages/login/index.vue

@@ -42,9 +42,7 @@
   </div>
 
   <div v-else class="surprise">
-    <div class="header">
-      <i class="logo"></i>
-    </div>
+    <NavBar :show-nav-icons="false" />
     <div class="ptc-form">
       <div class="title">Change Password</div>
       <div class="ptc-form-item">
@@ -70,25 +68,13 @@
 
 <script setup lang="ts">
 import { ref } from 'vue'
+import NavBar from '@/components/nav-bar/index.vue'
 
 const showSurprise = ref(false)
 </script>
 
 <style lang="scss">
 .surprise {
-  .header {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    height: 116px;
-    border-bottom: 1px solid #d9d9d9;
-    .logo {
-      width: 160px;
-      height: 88px;
-      background: #efefef;
-    }
-  }
-
   .ptc-form {
     padding: 96px 80px 0;
   }

+ 2 - 16
src/pages/password/index.vue

@@ -1,8 +1,6 @@
 <template>
   <div class="p-password">
-    <div class="header">
-      <i class="logo"></i>
-    </div>
+    <NavBar :show-nav-icons="true" />
     <div v-if="step === 0" class="step">
       <h3 class="title">Recover password</h3>
       <div class="desc">
@@ -62,6 +60,7 @@
 <script setup lang="ts">
 import { ref } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
+import NavBar from '@/components/nav-bar/index.vue'
 
 const router = useRouter()
 const { query } = useRoute()
@@ -77,19 +76,6 @@ function next() {
 
 <style lang="scss">
 .p-password {
-  .header {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    height: 116px;
-    border-bottom: 1px solid #d9d9d9;
-    .logo {
-      width: 160px;
-      height: 88px;
-      background: #efefef;
-    }
-  }
-
   .step {
     margin-top: 98px;
     padding: 0 80px;

+ 6 - 0
src/style/_mixins.scss

@@ -0,0 +1,6 @@
+@mixin icon($url, $width, $height: $width) {
+  width: $width;
+  height: $height;
+  background: url(#{$url}) no-repeat;
+  background-size: 100% 100%;
+}

+ 4 - 1
src/style/_variables.scss

@@ -1,4 +1,7 @@
 $primary-color: #1A3059;
+$primary-color-lighten: scale-color($primary-color, $lightness: 10%);
 $danger-color: #EB3735;
 $border-color: #D9D9D9;
-$placeholder-color: #bebebe;
+$placeholder-color: #bebebe;
+
+$nav-bar-height: 116px;

+ 16 - 0
src/style/animate.scss

@@ -0,0 +1,16 @@
+.fadeIn {
+  animation: fadeIn .3s;
+}
+.fadeOut {
+  animation: fadeOut .3s forwards;
+}
+@keyframes fadeIn {
+  0% {
+    opacity: 0;
+  }
+}
+@keyframes fadeOut {
+  100% {
+    opacity: 0;
+  }
+}

+ 4 - 0
src/style/atom.scss

@@ -1,3 +1,7 @@
 .tac {
   text-align: center;
 }
+
+.fw600 {
+  font-weight: 600;
+}

+ 3 - 0
src/style/components.scss

@@ -6,6 +6,9 @@
   font-size: 32px;
   font-weight: 600;
   color: #fff;
+  &:active {
+    background: $primary-color-lighten;
+  }
 
   &--stroke {
     background: none;

+ 8 - 0
src/style/icons.scss

@@ -0,0 +1,8 @@
+.icon {
+  &-lite {
+    @include icon('@img/lite.png', 36px);
+  }
+  &-pro {
+    @include icon('@img/pro.png', 36px);
+  }
+}

+ 2 - 0
src/style/index.js

@@ -1,4 +1,6 @@
 import './normalize.scss'
 import './atom.scss'
 import './components.scss'
+import './animate.scss'
+import './icons.scss'
 import './login.scss'

+ 2 - 1
vite.config.ts

@@ -14,7 +14,8 @@ export default defineConfig({
   css: {
     preprocessorOptions: {
       scss: {
-        additionalData: '@import "@/style/_variables.scss";',
+        additionalData:
+          '@import "@/style/_variables.scss", "@/style/_mixins.scss";',
       },
     },
   },