Vue仿京东移动端web版商品详情页滚动样式
Vue仿京东移动端web版商品详情页滚动样式
要求:
- 页面顶部固定有 商品、评价、推荐、详情四个选项卡,对应四个部分的内容。
- 商品:显示轮播图、标题、价格等;评价:显示4条精选评价;推荐:显示两行三列6条推荐信息;详情:商品的详细介绍通常为富文本或一系列图片。
- 手动滚动页面,导航选项栏同样会自动切换对应样式。
- 当页面滚动距离为0时,导航选项栏透明度为0,且不可点击,每往下滚动20增加0.1,大于等于200时一直为1。(考虑性能可改为无级自动透明度或者每40增加0.2)
- 点任意选项卡会切换样式且滚动到对应的内容位置,
- 点击导航栏商品选项卡时时,滚动到0且透明度直接为0
预览效果
http://vietechen.gitee.io/jd/product/product.html
绑定滚动事件
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>