vue 封装组件之顶部导航栏随着页面滚动变化颜色
NavigationBar.vue<template><divclass="nav-bar z-index-max":class="{'bottom-line': pageName}":style="navBarStyle"><div class="left"><img v-if="isShowBack" src="@img/back.svg" alt="
导航栏可以说是前端页面很常见的一个组件。许多组件库也提供了自己的导航栏
在这篇文章里,我们来实现一个随着页面的滚动样式发生改变的导航栏吧。
一个通用的顶部导航栏应该具备的能力:
默认的展示效果 -> 左边后退按钮的图标,中间页面的名称,右边是空白的内容
可以通过插槽来配置具体的展示样式 -> 左,中,右 三个插槽,父组件可以通过三个插槽来指定
可以接收从外部指定的一个样式(可以在父组件中指定
navigationBar
的 style)
导航栏的样式布局很简单,三个具名插槽。通过父组件传入的参数判断显示的内容。
NavigationBar.vue
<template>
<div
class="nav-bar z-index-max"
:class="[{ 'iphonex-top': isIphoneX }, { 'bottom-line': pageName }]"
:style="navBarStyle"
>
<div class="left" @click="$emit('onLeftClick')">
<!-- 默认状态 -->
<img
v-if="isDefault && isShowBack"
src="@img/back.svg"
alt=""
srcset=""
/>
<!-- 定制具名插槽 -->
<slot name="nav-left"></slot>
</div>
<div class="center">
<!-- 默认状态 -->
<span class="page-title" v-if="isDefault">{{ pageName }}</span>
<!-- 定制具名插槽 -->
<slot name="nav-center"></slot>
</div>
<div class="right">
<!-- 定制具名插槽 -->
<slot name="nav-right"></slot>
</div>
</div>
</template>
<script>
export default {
props: {
// 是否展示默认状态
isDefault: {
default: true,
type: Boolean,
},
// 是否展示默认后退按钮
isShowBack: {
default: true,
type: Boolean,
},
// 默认状态下页面标题的名称
pageName: {
default: '',
type: String,
},
// navBar样式
navBarStyle: {
type: Object,
default() {
return {
backgroundColor: 'white',
};
},
},
},
data() {
return {
isIphoneX: window.isIphoneX,
};
},
};
</script>
<style lang="scss" scoped>
@import "@css/style.scss";
.nav-bar {
width: 100%;
height: $navBarHeight;
line-height: $navBarHeight;
display: flex;
justify-content: space-between;
// 适配手机 stateBar
padding-top: $stateBarHeight;
.left,
.right {
display: flex;
height: 100%;
width: px2rem(26);
padding: 0 8px;
img {
width: 100%;
align-self: center;
}
}
.center {
display: flex;
height: 100%;
flex-grow: 1;
.page-title {
align-self: center;
margin: 0 auto;
font-size: $titleSize;
}
}
}
.bottom-line {
border-bottom: 1px solid $lineColor;
}
</style>
调用父组件处
<template>
<div class="home" @scroll="onScrollChange" ref="home">
<navgation-bar :isDefault="false" :navBarStyle="navBarStyle">
<template v-slot:nav-left>
<img :src="navBarCurrentSlot.leftIcon" />
</template>
<template v-slot:nav-center>
<search
:bgColor="navBarCurrentSlot.search.bgColor"
:hintColor="navBarCurrentSlot.search.hintColor"
:icon="navBarCurrentSlot.search.icon"
></search>
</template>
<template v-slot:nav-right>
<img :src="navBarCurrentSlot.rightIcon" />
</template>
</navgation-bar>
</div>
</template>
<navgation-bar :isShowBack="false" :pageName="'个人中心'"></navgation-bar>
监听页面的滚动事件 @scroll="onScrollChange"
data() {
return {
// navBar 插槽的样式数据,包含页面未开始滑动的时候插槽的样式 和 页面滑动到锚定点之后的插槽样式
navBarSlotData: {
// 正常样式
normal: {
leftIcon: require('./img/more-white.svg'),
search: {
bgColor: '#ffffff',
hintColor: '#999999',
icon: require('./img/search.svg')
},
rightIcon: require('./img/message-white.svg')
},
// 到达锚定点的样式
highlight: {
leftIcon: require('./img/more.svg'),
search: {
bgColor: '#d7d7d7',
hintColor: '#eee',
icon: require('./img/search-white.svg')
},
rightIcon: require('./img/message.svg')
}
},
// navBar 当前使用的插槽样式
navBarCurrentSlot: {},
// 顶部样式
navBarStyle: {
backgroundColor: '',
position: 'fixed',
},
// 页面滚动值
scrollTopValue: -1,
// 锚点值(滑动页面超过锚点值的时候,navBar 样式发生改变)
ANCHOR_SCROLL_TOP: 160
}
},
created() {
// 页面初始化的时候
this.navBarCurrentSlot = this.navBarSlotData.normal;
},
监听页面的滚动事件,调用 onScrollChange
获取到当前页面滚动的距离
计算
navBar
背景颜色(navBar
背景透明度)。当前滚动的距离 / 锚点值 =navBar
背景透明度opacity
opacity
>= 1,当前滚动的距离等于或者已经超过了锚点值,那就让navBar
的样式变为高亮显示的
opacity
< 1,当前navBar
插槽的样式则为默认的样式
methods: {
onScrollChange($event) {
// 获取到当前页面滚动的距离
this.scrollTopValue = $event.target.scrollTop
// 计算 navBar 背景颜色(navBar 背景透明度)
let opacity = this.scrollTopValue / this.ANCHOR_SCROLL_TOP
// 指定 navBar 插槽样式
if (opacity >= 1) {
this.navBarCurrentSlotStyle = this.naBarSlotStyle.highlight
} else {
this.navBarCurrentSlotStyle = this.naBarSlotStyle.normal
}
// 根据透明比例来设置 navBar 的背景颜色
this.navBarStyle.backgroundColor = "rgba(255, 255, 255, " + opacity + ")"
}
},
中间的插槽可以放置其他的组件,样式就要进行相对应的修改
(px2rem() 这个是我做移动端适配的函数,使用者将 px2rem() 里面的数值取出来加上 px 就可以正常使用,只不过没有适配)
实现效果
关注公众号:大明贵妇,无套路获取前端学习资料,期待各位客官来临
更多推荐
所有评论(0)