告別原生,打造本身的topBar

前段時間項目忙到一半,產品忽然說h5頁面要加個top-bar(以前說好的混合開發呢)。WFT,項目作到了一半,忽然要加這個; 看了下設計圖,大概是這樣的javascript

img
通過認真分析,總結出了幾種製做top-bar的方法;

方法一

直接在view-router外添加,在路由處配置是否顯示該top-bar便可 路由配置css

{ path: 'xxx', name: 'xxx', component: xxx, meta: { title: 'xxxxx', topBar: false } } // topBar 爲false則不顯示
複製代碼

top-bar組件大體以下html

<template>
  <div class="top-bar" v-if="$route.meta.topBar !== false">
    {{$route.meta.title}}
  </div>
</template>
<script>
export default {
  name: 'topBar'
}
</script>
<style lang="sass" scoped>

</style>
複製代碼

而後在app.vue內引入TopBar組件vue

<template>
  <div id="app"> <top-bar></top-bar> <router-view class="container"></router-view> </div> </template> <script> import TopBar from '@/components/common/TopBar' export default { name: 'App', components: { TopBar } } </script> 複製代碼

優勢java

  • 直接在vue入口配置,直觀
  • 經過路由傳參控制其顯示隱藏,配置簡單
  • 當前項目代碼改動小

缺點node

  • 位置相對固定,不能放在router-view,會被router-view內的組件覆蓋掉
  • 沒法動態修改title內容(緣由是meta對象爲只讀),若想動態修改title,需脫離vue環境來操縱dom

方法二

全局註冊top-bar組件,在須要的頁面調用; index.js內添加api

import TopBar from '@/components/common/TopBar'
Vue.components(TopBar)
複製代碼

頁面內,將meta 賦值給當前頁面的 page 對象sass

<top-bar>{{page.title}}</top-bar>
複製代碼

路由配置不變bash

優勢app

  • 在router-view內外皆可以使用
  • 可動態修改title值
  • 操做簡單,新手必備

缺點

  • 使用起來比較麻煩,每次都須要手動調用
  • 每一個都頁面要手動去存一個對象,用來改變title的值,重複代碼多
  • 當前項目代碼改動大

方法三

建立一個TopBar的組件構造器,須要extend,在每次路由跳轉的時候,生成一個構造器實例;此方法的難點在於如何在路由跳轉的時候,獲取TopBar組件的實例;有如下注意點

  • 獲取組件實例:這裏咱們經過 $mount方法來獲取組件實例;$mount會在vue內調用compile方法;編譯後,咱們即可拿到$el;從而進行手動掛載;
  • 模板數據:在beforeRouteEnter鉤子函數內獲取
  • 每一個page都要執行,所以將此方法放到全局的mixin內,頁面加載及路由跳轉的時候,自動執行

關於$mount用法,能夠參考官網 點擊這裏

mixin 以下, topBarMixin.js

import Vue from 'vue'
import '@/style/topBar.scss'

let TopBar = null
let App = null

const getApp = function (vm) {
  App = vm.$el
  return App
}

const clearTopBar = function () {
  if (TopBar) { // 先清掉以前的,防止keep-alive的cache產生多個topbar
    const topBarElement = TopBar.$el
    const parentNode = topBarElement.parentNode
    parentNode.removeChild(topBarElement)
  }
}

const compile = function (meta) {
  const show = (meta.topBar !== false)
  const title = meta.title || ''
  if (!show) {
    return
  }
  clearTopBar() // 先清除以前的TopBar
  const TopBarComponent = Vue.extend({
    data () {
      return {
        show,
        title
      }
    },
    template: ` // 模板 <div class="xsj-top-bar" v-if="show"> <div class="xsj-top-bar-content"> <div class="top-bar-arrow" @click="back"> <icon name="return" class="return"></icon> </div> <div class="top-bar-title">{{title}}</div> </div> </div>`
  })
  TopBar = new TopBarComponent().$mount() // 掛載獲取實例
  if (App.nodeType === 1) {
    App.insertBefore(TopBar.$el, App.firstChild)
  } else {
    throw new Error('沒法給非元素節點增長topbar')
  }
}

export default {
  methods: {
    _resetTitle (title = TopBar.title) { // 可手動調用修改當前title的內容
      this.$nextTick(() => { // 在頁面模板掛載上去之後,執行
        if (TopBar.show) {
          TopBar.title = title
          document.title = title
        }
      })
    }
  },
  beforeRouteEnter (to, from, next) {
    const meta = to.meta
    next(vm => {
      getApp(vm)
      compile(meta)
    })
  }
}

複製代碼

index.js 內直接調用Vue.mixin(topBarMixin)

優勢

  • 經過路由傳參控制其顯示隱藏,配置簡單
  • 當前項目代碼改動小

缺點

  • TopBar爲動態插入,因此會引發頁面重排
  • 對於有keep-alive的頁面,須要清除以前的TopBar,否則每次enter就會增長一個TopBar實例

方法四

方法四和方法三實現邏輯差很少,只不過把組件構造器換爲組件實例TopBar.vue;

  • 組件實例 引入組件,$mount掛載獲取實例
  • 數據方面:因爲TopBar沒法拿到當前route的信息,因此須要經過props傳入

TopBar.vue以下

<template>
  <div class="top-bar" v-if="bar.topBar !== false">
    {{bar.title}}
  </div>
</template>
<script>
export default {
  name: 'TopBar',
  props: {
    bar: {
      type: Object,
      default () {
        return {}
      }
    }
  }
}
</script>
複製代碼

mixin 以下, topBarMixin.js文件

import Vue from 'vue'
import TopBar from '@/components/common/TopBar'  // 引入TopBar組件

let App = null

const getApp = function (vm) {
  App = vm.$el
  return App
}
export default {
  name: 'AddTopBar',
  beforeRouteEnter (to, from, next) {
    next(vm => {
      getApp(vm)
      const tb = new Vue(TopBar).$mount()  // 掛載獲取實例
      if (App.nodeType === 1) {
        clearTopBar()  // 先清掉以前的TopBar,防止keep-alive的cache產生多個topbar
        App.insertBefore(tb.$el, App.firstChild)
        tb._props.bar = to.meta  // 將路由數據傳給top-bar
      } else {
        throw new Error('沒法給非元素節點增長topbar')
      }
    })
  }
}
複製代碼

入口處調用 Vue.mixin(topBarMixin) 便可

優勢

  • 經過路由傳參控制其顯示隱藏,配置簡單
  • 當前項目代碼改動小
  • 可手動設置props,動態修改title
  • 組件分離出來,便於維護和擴展

缺點

  • TopBar爲動態插入,因此會引發頁面重排
  • 對於有keep-alive的頁面,須要清除以前的TopBar,否則每次enter頁面就會增長一個TopBar實例

最後

本文涉及的知識點和細節點仍是蠻多的,本身在整理的時候,也認真的消化吸取了一波;有些小知識點,寫起來比較佔篇幅,再者比較時間匆忙,筆者在此就一筆帶過了。

固然,若是你們有更好的解決方法,歡迎留言,一塊兒探討~

相關文章
相關標籤/搜索