导航栏总结

2021-07-01  本文已影响0人  Summerdise

这次所做的导航栏是为了练习components(组件)layout(布局)responsive(响应式)下拉框(collapse)

导航栏的特点是:根据导航数据结构渲染,三层目录不定量选项卡,web端与mobile端自适应变化,mobile端导航栏特殊设计。

重点学习的技术包含:组件获取数据的方法和不定项的渲染方法,响应式布局动画设计手风琴导航栏

组件数据获取和渲染

目前项目broading阶段,使用的数据是与后端沟通后的mock数据。组件获取数据的方法是创建时fetch获取,利用cms提供的获取方法,返回具体的Navigation数据。

  async fetch(): Promise<void> {
    this.navigationList = (await getNavigations()).data
  },

在需要不定项获取时,利用v-for中传入列表数据来实现。通常列表中需要重新定义格式时,就在每一行li中加入一个代入数据的新的组件。

<ul class="navbar-nav">
   <li v-for="item in navigationList.navigation" :key="item.id" class="alert-second-nav pl-5 nav-item active">
        <a :href="item.link.href" class="nav-link text-black-50">{{ item.link.label }}</a>
        <DropDown class="second-nav border-top border-bottom border-dark-50" :data="item.sections" />
        <div class="mask-bg w-100 h-100 m-0 p-0"></div>
    </li>
</ul>

其中DropDown就是新组件用于接收数据。

具体的接收方法为:

props: {
    data: {
      type: Array as PropType<NaviSectionEntity[]>,
      default(): NaviSectionEntity[] {
        return [] as NaviSectionEntity[]
      },
    },
  },

数据得到后的渲染中主要就是直接使用$props原型数据。

特殊的需要注意,区分data数据与$props.data的区别。data数据可以方便的随时更改再获取,但原型不能更改。

响应式布局

这里说到的响应式主要是web端和mobile端的区别。

响应式最重要的几个内容是1.不同端的具体布局2.屏幕大小的监听3.不同端内容的控制。

mounted() {
    window.onresize = () => {
      // 监听屏幕变化
      this.page_width()
    }
    this.page_width()
  }

监听后对屏幕大小做一个规定,判定mobile端与web端的屏幕大小分界,根据分解转化为一个bool值。

page_width() {
      // 获取屏幕宽度
      const screenWidth = document.body.clientWidth
      this.fullWidth = screenWidth >= 1000
    }

在不同端的布局上都加上v-show这个标签属性,该属性用于控制这个标签的内容是否显示。用屏幕的bool值来控制内容是否显示。

<div v-show="fullWidth" id="navbarSupportedContent" class="collapse navbar-collapse">
  <ul class="navbar-nav">
  </ul>
</div>

特殊的:项目中移动端还会出现点击出现或显示的功能。

<div v-show="!fullWidth && !disMenu" class="collapse navbar-collapse mobile-menu-open">
        <ul class="navbar-nav">
  </ul>
</div>

动画设计

项目中暂时用到的动画设计只有从右边划入,向右边划出这种。

设计方案就是针对需要使用动画的div外包裹一层transition标签。

<transition name="mobile-menu-slide-fade">
  <div>
  </div>
</transition>

具体设计这个动画transition时,即在style中对该nameenter,leave属性进行修改。

.mobile-menu-slide-fade-enter-active {
  transition: all 0.5s ease;
}

.mobile-menu-slide-fade-leave-active {
  transition: all 0.3s cubic-bezier(1, 0.5, 0.8, 1);
}

.mobile-menu-slide-fade-enter,
.mobile-menu-slide-fade-leave-to {
  transform: translateX(300px);
  opacity: 0;
}

手风琴导航栏

手风琴指的是列表中点击一行时,行内的下级列表内容全部显示,此时点击另一行时,会把之前全部内容隐藏,显示当前行下的下级列表内容。

项目中用到的手风琴导航栏主要是在移动端的第二层菜单时,希望不再继续往下跳转。

具体实现时的难点是:数据的传递和显示与隐藏的控制。

数据传递和控制上需要注意的是v-for是可以获得index值的,通过index的值可以完成对具体某一行内容的操作与获取。

具体的控制方法有两种实现:

  1. 对每一项数据内容中加入一个是否显示的字段,该字段中保证在一组同级数据下仅有一个true,代表为显示,每次点击事件发生时都会判断全部内容下的该字段,保证字段准确性。
  2. 在全局data中添加一个showIndex字段,初始值为-1,用于记录当前可以显示的某行,如果为-1则为都不显示。每次点击事件发生时都对showIndex字段进行更新。

本项目因为原数据已经确定,所以使用的第二种实现方法。

<template>
  <div>
    <ul class="list-unstyled">
      <li v-for="(item, index) in $props.data" :key="item.id" :class="[{ active: isShowing(index) }]">
        <div class="nav-link text-black-50">
          <p class="mb-0" @click="changeShowingIndex(index)">{{ item.title }}</p>
        </div>
        <ul v-show="isShowing(index)" class="list-unstyled pl-3">
          <li v-for="subItem in item.links" :key="subItem.id">
            <div class="nav-link text-black-50">
              <p class="mb-0">{{ subItem.label }}</p>
            </div>
          </li>
        </ul>
      </li>
    </ul>
  </div>
</template>

<script lang="ts">
import Vue, { PropType } from 'vue'
import { NaviSectionEntity } from '~/apis/cms'

type NaviData = {
  showingIndex: number
}

export default Vue.extend({
  name: 'MobileSecondNavi',
  props: {
    data: {
      type: Array as PropType<NaviSectionEntity[]>,
      default(): NaviSectionEntity[] {
        return [] as NaviSectionEntity[]
      },
    },
  },
  data(): NaviData {
    return {
      showingIndex: -1,
    }
  },
  methods: {
    changeShowingIndex(index) {
      if (this.showingIndex === index) {
        this.showingIndex = -1
      } else {
        this.showingIndex = index
      }
    },
    isShowing(index) {
      return this.showingIndex === index
    },
  },
})
</script>
上一篇下一篇

猜你喜欢

热点阅读