告别原生,打造本身的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实例

最后

本文涉及的知识点和细节点仍是蛮多的,本身在整理的时候,也认真的消化吸取了一波;有些小知识点,写起来比较占篇幅,再者比较时间匆忙,笔者在此就一笔带过了。

固然,若是你们有更好的解决方法,欢迎留言,一块儿探讨~

相关文章
相关标签/搜索