Vue仿京东移动端web版商品详情页滚动样式
要求:
- 页面顶部固定有 商品、评价、推荐、详情四个选项卡,对应四个部分的内容。
- 商品:显示轮播图、标题、价格等;评价:显示4条精选评价;推荐:显示两行三列6条推荐信息;详情:商品的详细介绍通常为富文本或一系列图片。
- 手动滚动页面,导航选项栏同样会自动切换对应样式。
- 当页面滚动距离为0时,导航选项栏透明度为0,且不可点击,每往下滚动20增加0.1,大于等于200时一直为1。(考虑性能可改为无级自动透明度或者每40增加0.2)
- 点任意选项卡会切换样式且滚动到对应的内容位置,
- 点击导航栏商品选项卡时时,滚动到0且透明度直接为0
预览效果
绑定滚动事件
mounted() {
window.addEventListener('scroll', this.handleScroll);
},
methods: {
// 监听页面滚动
handleScroll () {
var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
}
}
获取组件标签的位置
<div class="comment" ref="comment" id="comment"></div>
/**/
let recommendTop = this.$refs.comment.offsetTop - 45;
使页面滚动到某组件标签
<a href="javascript:" @click="onScrollComment">评价</a>
onScrollComment(){
document.documentElement.scrollTop = this.$refs.comment.offsetTop - 45;
// behavior 类型String,表示滚动行为,支持参数 smooth(平滑滚动),instant(瞬间滚动),默认值auto,实测效果等同于instant
window.scrollTo({top: this.$refs.detail.offsetTop - 45, behavior: "smooth" });
},
完整代码
样式细节未打磨,部分js代码可自行修改优化。疯狂滚动CPU占用比京东低。
1 <!DOCTYPE html>
2 <html lang="en">
3
4 <head>
5 <meta charset="UTF-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <meta http-equiv="X-UA-Compatible" content="ie=edge">
8 <title>Document</title>
9 <script src="vue.js"></script>
10 </head>
11
12 <body>
13 <div id="app">
14 <div :style="{opacity: opacity}" class="nav">
15 <div class="header-new-title">
16 <nav class="detail_anchor">
17 <a href="javascript:" dtype="item" :class="{'active': active=='goods'}"
18 @click="onScrollGoods"><span>商品</span></a>
19 <a href="javascript:" dtype="comment" :class="{'active': active=='comment'}"
20 @click="onScrollComment"><span>评价</span></a>
21 <a href="javascript:" dtype="guess" :class="{'active': active=='recommend'}"
22 @click="onScrollRecommend"><span>推荐</span></a>
23 <a href="javascript:" dtype="detail" :class="{'active': active=='detail'}"
24 @click="onScrollDetail"><span>详情</span></a>
25 </nav>
26 </div>
27 </div>
28
29 <div class="goods">
30 <img style="width: 100%;" src="./apple-1.jpg" alt="">
31 <div>我是商品标题</div>
32 <div>我是商品价格</div>
33 <div v-for="(item, index) in 10" :key="index">其他</div>
34 </div>
35 <hr>
36
37 <div class="comment" ref="comment" id="comment">
38 <div>精选评价</div>
39 <div v-for="(item, index) in 4" :key="index">
40 <div class="title"><span class="fl">张若虚</span><span class="fr">2019-10-{{item}}</span></div>
41 <div class="content">春江潮水连海平,海上明月共潮生。</div>
42 </div>
43 </div>
44 <hr>
45
46 <div class="recommend" ref="recommend" id="recommend">
47 <div>猜你喜欢</div>
48 <img v-for="(item, index) in 6" :key="index" style="width: 33%;" src="./apple-1.jpg" alt="">
49 </div>
50 <hr>
51
52 <div ref="detail">
53 <div></div>
54 <div>我是商品详情
55 <img v-for="(item, index) in 5" :key="index" style="width: 100%;" src="./apple-1.jpg" alt="">
56 </div>
57 </div>
58
59 <div class="de_btn_bar">
60 <div class="btn_group">
61 <div class="btn_group_item" style="width: 16%;">客服</div>
62 <div class="btn_group_item" style="width: 16%;">店铺</div>
63 <div class="btn_group_item" style="width: 18%;">购物车</div>
64 <div class="btn_group_item add_cart">加入购物车</div>
65 <div class="btn_group_item now_buy">立即购买</div>
66 </div>
67 </div>
68
69 </div>
70 <script>
71 var vm = new Vue({
72 el: '#app',
73 data: {
74 scrollTop: 0,
75 opacity: 0,
76 active: 'goods',
77
78 },
79 // 绑定滚动事件
80 mounted() {
81 window.addEventListener('scroll', this.handleScroll);
82 },
83 methods: {
84 // 监听页面滚动
85 handleScroll() {
86 // 获取当前的滚动距离
87 var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
88 // console.log(scrollTop)
89
90 if (scrollTop < 200) {
91 // 当滚动距离小于200时,计算导航透明度,可以考虑修改为每20增加0.1
92 // this.opacity = (scrollTop / 200).toFixed(1);
93 this.opacity = scrollTop / 200;
94 this.active = 'goods';
95 return
96 } else {
97 this.opacity = 1
98 }
99 // 当滚动距离不小于200时,获取三个部分的顶部位置-45。
100 let commentTop = this.$refs.comment.offsetTop - 45;
101 let recommendTop = this.$refs.recommend.offsetTop - 45;
102 let detailTop = this.$refs.detail.offsetTop - 45;
103 // 计算滚动距离在哪个区间,修改this.active对应的样式名
104 if (scrollTop < commentTop) { if (this.active != 'goods') this.active = 'goods'; }
105 else if (scrollTop >= commentTop && scrollTop < recommendTop) { if (this.active != 'comment') this.active = 'comment'; }
106 else if (scrollTop >= recommendTop && scrollTop < detailTop) { if (this.active != 'recommend') this.active = 'recommend'; }
107 else if (scrollTop >= detailTop) { if (this.active != 'detail') this.active = 'detail'; }
108 },
109
110 // 点击导航栏第一个商品选项卡时,直接滚动到0
111 onScrollGoods() {
112 // document.documentElement.scrollTop = 0;
113 window.scrollTo({top: 0, behavior: "smooth" });
114 },
115 // 点击导航栏其他选项卡时,直接滚动到对应ref的offsetTop-45(导航栏高度)
116 onScrollComment() {
117 if (!this.opacity) return;
118 window.scrollTo({top: this.$refs.comment.offsetTop - 45, behavior: "smooth" });
119 },
120 onScrollRecommend() {
121 if (!this.opacity) return;
122 window.scrollTo({top: this.$refs.recommend.offsetTop - 45, behavior: "smooth" });
123 },
124 onScrollDetail() {
125 if (!this.opacity) return;
126 //document.documentElement.scrollTop = this.$refs.detail.offsetTop - 45;
127 // behavior 类型String,表示滚动行为,支持参数 smooth(平滑滚动),instant(瞬间滚动),默认值auto,实测效果等同于instant
128 window.scrollTo({top: this.$refs.detail.offsetTop - 45, behavior: "smooth" });
129
130 },
131 },
132 })
133 </script>
134 <style lang="less">
135 body {
136 margin: 0;
137 }
138 a {
139 text-decoration: none;
140 color: #252525;
141 -webkit-tap-highlight-color:transparent;
142 }
143
144 #app{
145 margin: 0 5px;
146 }
147 .nav {
148 height: 45px;
149 width: 100%;
150 background-color: #fff;
151 position: fixed;
152 z-index: 99;
153 opacity: 999;
154 }
155
156 .detail_anchor {
157 display: -webkit-box;
158 display: -webkit-flex;
159 display: flex;
160 height: 44px;
161 line-height: 44px;
162 font-size: 14px;
163 color: #666;
164 box-shadow: 0 1px 6px rgba(0, 0, 0, .1);
165 justify-content: space-evenly;
166 }
167
168 .header-new-title {
169 margin: 0 70px;
170 height: 44px;
171 font-size: 16px;
172 line-height: 44px;
173 text-align: center;
174 color: #333;
175 overflow: hidden;
176 text-overflow: ellipsis;
177 white-space: nowrap;
178 }
179
180 .active {
181 color: #e4393c;
182 }
183
184 .de_btn_bar{
185 height: 50px;
186 width: 100%;
187 background-color: #fff;
188 position: fixed;
189 z-index: 99;
190 bottom: 0;
191 }
192 .btn_group{
193 /* display: flex;
194 justify-content: space-evenly; */
195 height: 100%;
196 }
197 .btn_group_item{
198 display: inline-block;
199 height: 100%;
200 width: 25%;
201 margin-right: -5px;
202 padding: 0;
203 text-align: center;
204 line-height: 50px;
205 }
206 .add_cart{
207 color: #fff;
208 background: linear-gradient(138deg,#ffa600,#ffb000 77%,#ffbc00);
209 }
210 .now_buy{
211 color: #fff;
212 background: linear-gradient(-41deg,#ff4f18,#ff2000 24%,#f10000);
213 }
214 </style>
215
216 </body>
217
218 </html>