前段时间项目忙到一半,产品突然说h5页面要加个top-bar(之前说好的混合开发呢)。WFT,项目做到了一半,突然要加这个; 看了下设计图,大概是这样的
经过认真分析,总结出了几种制作top-bar的方法;方法一
直接在view-router外添加,在路由处配置是否显示该top-bar即可 路由配置
{ path: 'xxx', name: 'xxx', component: xxx, meta: { title: 'xxxxx', topBar: false } } // topBar 为false则不显示
复制代码
top-bar组件大致如下
"top-bar" v-if="$route.meta.topBar !== false">
{{$route.meta.title}}
复制代码
然后在app.vue内引入TopBar组件
<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>
复制代码
优点
- 直接在vue入口配置,直观
- 通过路由传参控制其显示隐藏,配置简单
- 当前项目代码改动小
缺点
- 位置相对固定,不能放在router-view,会被router-view内的组件覆盖掉
- 无法动态修改title内容(原因是meta对象为只读),若想动态修改title,需脱离vue环境来操纵dom
方法二
全局注册top-bar组件,在需要的页面调用; index.js内添加
import TopBar from '@/components/common/TopBar'
Vue.components(TopBar)
复制代码
页面内,将meta 赋值给当前页面的 page 对象
{{page.title}}
复制代码
路由配置不变
优点
- 在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: ` // 模板
})
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如下
"top-bar" v-if="bar.topBar !== false">
{{bar.title}}
复制代码
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实例
最后
本文涉及的知识点和细节点还是蛮多的,自己在整理的时候,也认真的消化吸收了一波;有些小知识点,写起来比较占篇幅,再者比较时间匆忙,笔者在此就一笔带过了。
当然,如果大家有更好的解决方法,欢迎留言,一起探讨~