[TOC]
### vue 实现天猫国际商城导航效果交互
实现效果:
![](https://box.kancloud.cn/91a141e72f7608a9421df518360633d4_375x396.png)
上拉时
![](https://box.kancloud.cn/58a47bd162ab0a6f083f9db3a24710f7_377x305.png)
*****
实现思路:
1. 页面上拉时,顶部导航消失,搜索框逐渐滑动到顶部位置
2. 顶部导航产生1px阴影下边框
2. 页面滚动到顶部时,还原初始效果,边框阴影消失
代码演示:
Home.vue
~~~
<template>
<div class='home'>
<!-- 顶部导航 -->
<search-bar :posy="posy" ref='top'></search-bar>
<!-- 内容滚动区域 -->
<div ref="content" class='main-content' :style="{top:offsetTop+'px'}">
<p>1111111111111111</p>
<p>1111111111111111</p>
<p>1111111111111111</p>
<p>1111111111111111</p>
<p>1111111111111111</p>
<p>1111111111111111</p>
<p>没有更多了...</p>
</div>
</div>
</template>
<script>
import SearchBar from 'components/home/SearchBar'
export default {
components: {
// 顶部搜索条组件
SearchBar
},
mounted() {
// Dom 加载完成,监听局部内容滚动
this.$refs.content.addEventListener('scroll', this.handleScroll)
},
data() {
return {
// 判断向上还是向下滚动 0顶部位置 >0 向下滚动
posy: 0,
// 内容初始距离顶部导航条的偏移量
offsetTop: 90
}
},
methods: {
// 监听内容滚动事件
handleScroll() {
// 距离顶部偏移
let scrollTop = this.$refs.content.scrollTop
this.posy = scrollTop;
if (scrollTop > 0) {
// 上拉
this.offsetTop = 50
} else {
// 回到顶部
this.offsetTop = 90
}
}
}
}
</script>
<style lang="scss" scoped>
.home {
width: 100%;
height: 100%;
position: relative;
.main-content {
position: absolute;
bottom: 50px;
left: 0;
right: 0;
overflow: auto;
z-index: 500;
}
}
</style>
~~~
*****
SearchBar.vue
~~~
<template>
<div class='search-bar-wrapper' ref='tops' :class="{hideTitle: !titleVisible, hideShaow: !shaowVisible}">
<!-- 顶部导航中间文件 -->
<div class='search-bar-top' v-show="titleVisible">
<div class='text'>天猫国际进口超市</div>
</div>
<!-- 左边按钮 -->
<div class='icon-left' :class="{hideTitle: !titleVisible}">
<i class='icon iconfont'></i>
</div>
<!-- 右边按钮 -->
<div class='icon-right' :class="{hideTitle: !titleVisible}">
<i class='icon iconfont'></i>
</div>
<!-- 搜索框 -->
<div class='search-bar-input' :class="{hideTitle: !titleVisible}">
<!-- 占位左边空白元素 -->
<div class='flex-left-empty' :class="{hideTitle: !titleVisible}"></div>
<!-- 中间搜索框 -->
<div class='input-inner'>
<label>搜索进口产品</label>
<div class='icon-search'></div>
</div>
<!-- 占位右边空白元素 -->
<div class='flex-right-empty' :class="{hideTitle: !titleVisible}"></div>
</div>
</div>
</template>
<script>
export default {
props: {
// Home 父组件传递的值,用于判断上拉还是下拉
posy: {
type: Number,
default: 0
}
},
data() {
return {
// 标题显示控制
titleVisible:true,
// 边框阴影显示控制
shaowVisible: false
}
},
watch: {
// 监听 Home 父组件传递的滚动值
posy(val) {
if (val > 0) {
// 向下滚动,隐藏标题 显示阴影
this.showTitle()
this.showShaow()
} else if (val === 0) {
// 滚到顶部显示标题 隐藏阴影
this.hideTitle()
this.hideShaow()
}
}
},
methods: {
// 显示 && 隐藏 具体实现方法
showTitle() {
this.titleVisible = false;
},
hideTitle() {
this.titleVisible = true;
},
showShaow() {
this.shaowVisible = true;
},
hideShaow() {
this.shaowVisible = false;
}
}
}
</script>
<style lang="scss" scoped>
.search-bar-wrapper {
background: linear-gradient(rgb(255,199,113), rgb(226,142,27)); /* 标准的语法 */
position: relative;
top: 0;
left: 0;
right: 0;
height: 90px;
z-index:1200;
box-shadow: 0 2px 2px 0 rgba(238,238,238, .8);
&.hideTitle {
height: 50px;
}
&.hideShaow {
box-shadow: none;
}
}
.search-bar-top {
position: absolute;
width: 100%;
height: 40px;
line-height: 40px;
.text {
width:100%;
position: absolute;
text-align: center;
color: #fff;
font-size: 16px;
color: rgba(255,255,255,.8);
font-weight: 600;
}
}
.icon-left {
position: absolute;
width: 40px;
height: 40px;
line-height: 40px;
left: 0;
text-align: center;
transition: all .2s linear;
color: #fff;
&.hideTitle {
height: 50px;
line-height: 50px;
}
i {
font-size:20px;
}
}
.icon-right {
position: absolute;
right: 0;
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
transition: all .1s linear;
&.hideTitle {
height: 50px;
line-height: 50px;
}
color: #fff;
i {
font-size: 20px;
}
}
.search-bar-input {
display: flex;
position: absolute;
top: 40px;
width: 100%;
height: 50px;
box-sizing: border-box;
padding: 0 15px;
display: flex;
align-items: center;
justify-content: center;
transition: .1s all linear;
&.hideTitle {
top: 0
}
.flex-left-empty {
flex: 0 0;
width: 0;
transition: all .1s linear;
&.hideTitle {
width:34px;
flex: 0 0 34px;
}
}
.flex-right-empty{
flex: 0 0;
width: 0;
transition: all .1s linear;
&.hideTitle {
width:34px;
flex: 0 0 34px;
}
}
.input-inner {
flex:1;
width: 100%;
line-height: 30px;
text-align: center;
background-color: #fff;
border-radius: 2px;
color: #999;
font-size: 14px;
}
}
</style>
~~~