一,利用FastClick第三方插件來解決移動端click事件300毫秒延遲情況
1,安裝,npm i fastclick -S
在main.js中引入
import FastClick from "fastclick"; FastClick.attach(document.body);
2,安裝stylus
npm i stylus stylus-loader --save-dev
3.關於移動端的尺寸計算,設計圖為750px, 以蘋果6開發(設備寬度375)
在reset.css重置樣式樣式表中可看到font-size大小, 在main.js引入reset.css
1rem = html font-size = 50px
在組件的樣式表中,可用rem來樣式作為尺寸單位
如果一個height為86px, 因為移動端一般用二倍圖來畫,所以height是43px, 再除以50, 也就是0.86rem,
4,阿里圖標本地引入
將阿里圖標下載到本地,在vue項目中,assets文件-style文件夾-新建iconfont文件夾,將圖標字體文件放入,在assets-stylus文件中放入iconfont.css,然后在main.js引入iconfont.css
import "./assets/style/iconfont.css";
最后,在iconfont.css中修改圖標字體的路徑(五個都要修改)
@font-face {font-family: "iconfont"; src: url('./iconfont/iconfont.eot?t=1612861657067'); /* IE9 */ src: url('./iconfont/iconfont.eot?t=1612861657067#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAANIAAsAAAAAB1QAAAL6AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDHAqCCIF9ATYCJAMQCwoABCAFhG0HTht1BsgeB+XGM0sZRXL+HcHX2G/f3X0VSJJEI0PFO4npJqERSWKx0SiJ7CXwk13+y02MdiKdupif3OzO7E4Ws/wCOrmT2lz3jUrqkoC///9zTb4SX307m0tUU0Ta0d4Ax60Dimoa2SYyMZ8T8NZlHCfQNKNK1G5n/0SIV1jjAnHNZAHicy5FEaJ1oVqztIhXiFFPd74RAC/h9+MPwhFPUsmsk/ZPOyRo/iz6tAGtGAUz82pYMZ8VwioyVoFCnNfaD6E4tAppar2jrQN1dYm52sKfNozOGNkxz/7LIySZqLIy22CNCWc+i1yS4DNMkvjckCHDDzHUvVFkD7hiiSlZQDNKtu7u3kinVpSTvZsPr8yl+1bmyfsPnRAfPZr8+PGUhw8nPXgQcbMcSCait7Dv8MnjOZP2Hjh2IlfsuP/ZpLSH0yuypT2bqsT51+8rzQtuXpmf+z1nfjBduXHvzLJP8DTpHPr8GZ1H5zjpOXBTLjiIP9+0A925gzzJdp4LHsuBZAdKt9QcqhxzZ2HzYHArvD06dWok/2D65awFBZHJU0cKwAT45/uPVvNdQx5qBiDf+ugXUQjef/btm5NW/yc+qYCPbuspWf9F9zQAfEdBb8EHF7BlRRdZhlJUscs3nMXsZQcSmraJzxxj6NUcyonemYS6iRSSmmnI6maRQqxCRcsaVNVtQNOKrtUtIzYkSgPL1hKEvouQdL1B1hdBCvESKiZ9gap+IGg6iKwtW+aDJbbZRHCJhIcWYiZygzomNzHKHk9kTxPsrCikTSa2w7w45A8Wo13EIPYcM5x5cth1KaY213EnnUY0jWPT5sNEdP2K65q1gQCte5Nf5Dok2mEjBC5Cgg1ZCGNEnIH61V2Jpc+PR8g8GoHdQqmxT0bYHKxzLMQv2APpkhu9KPfyimMeWZjLRWGUjdNhnTSI0Gg4zKwfNIwQufyUEQFTrYBdifaV+9dX6l+4Bpqsq0ukyFGionoqGIrHYh3uOR7PFGybz6+W3H5GNWWaxgwZAAAA') format('woff2'), url('./iconfont/iconfont.woff?t=1612861657067') format('woff'), url('./iconfont/iconfont.ttf?t=1612861657067') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ url('./iconfont/iconfont.svg?t=1612861657067#iconfont') format('svg'); /* iOS 4.1- */ } .iconfont { font-family: "iconfont" !important; font-size: 16px; font-style: normal; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .iconfanhui:before { content: "\e624"; } .iconsousuo:before { content: "\e632"; } .iconarrow-down-filling:before { content: "\e688"; }
然后在模板中引入字體圖標類
<div class="header-left ">h <span class="iconfont iconfanhui"></span> </div>
5.將主題顏色抽離成變量,以后主題顏色修改更加方便
assets文件夾-style文件夾- 新建varibles.styl文件,寫入主題顏色
$bgColor = #00bcd4
在header組件中,引入該樣式文件,在樣式中寫入該顏色變量
<style lang="stylus" scoped> @import '~assets/style/varibles.styl' .header display :flex height :0.86rem line-height : .86rem background : $bgColor color : #fff .header-left flex :0 0 .64rem color : #fff text-align : center font-size: .4rem
6.移動端1px像素問題
assets文件夾-style文件夾- 新建mixins.styl文件, 寫入1px的樣式, 然后組件中引入
// 偽類+transform // 原理:把原先元素的border去掉,然后利用:before或者:after重做border,並 transform的scale縮小一半, // 原先的元素相對定位,新做的border絕對定位。 $color = blue .border-1px-bottom, .border-1px-top,.border-1px-left,.border-1px-right position: relative // 邊框一像素,利用偽類設置一像素 .border-1px::after content: ""; box-sizing: border-box; position: absolute; left: 0; top: 0; width: 100%; height: 100%; border: 1px solid $color // 下邊框 .border-1px-bottom::after position :absolute left: 0 bottom: 0 width: 100% border-bottom: 1px solid $color content: ' ' // 上邊框 .border-1px-top::before position :absolute left: 0 top: 0 width: 100% border-top: 1px solid $color content: ' ' // 左邊框 .border-1px-left::before position :absolute left: 0 top: 0 height: 100% border-left: 1px solid $color content: ' ' // 右邊框 .border-1px-right::after position :absolute right: 0 top: 0 height: 100% border-right: 1px solid $color content: ' ' /*設備像素比*/ /*顯示屏最小dpr為1.5*/ @media (-webkit-min-device-pixel-ratio: 1.5),(min-device-pixel-ratio: 1.5) .border-1px-bottom::after,.border-1px-top::before // Y軸壓縮0.7, 1.5*0.7 約等於1 -webkit-transform: scaleY(0.7) transform: scaleY(0.7) .border-1px-left::before,.border-1px-right::after // X軸壓縮0.7, 1.5*0.7 約等於1 -webkit-transform: scaleX(0.7) transform: scalexX(0.7) .border-1px::after width: 150%; height: 150%; transform: scale(0.7); transform-origin: 0 0; @media (-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio: 2) .border-1px-bottom::after,.border-1px-top::before // Y軸壓縮0.5, 2*0.5 等於1 -webkit-transform: scaleY(0.5) transform: scaleY(0.5) .border-1px-left::before,.border-1px-right::after // X軸壓縮0.5, 2*0.5 等於1 -webkit-transform: scaleX(0.5) transform: scaleX(0.5) .border-1px::after width: 200%; height: 200%; transform: scale(0.5); transform-origin: 0 0; @media (-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio: 3) .border-1px-bottom::after,.border-1px-top::before -webkit-transform: scaleY(0.333) transform: scaleY(0.5) .border-1px-left::before,.border-1px-right::after -webkit-transform: scaleX(0.333) transform: scaleX(0.333) .border-1px::after width: 300%; height: 300%; transform: scale(0.333); transform-origin: 0 0; // 去除邊框 // border-none() &:after display: none
7.使用vue封裝的vue-awesome-swiper輪播圖插件,不是原生的swiper插件
安裝,npm install vue-awesome-swiper@4.1.1 --save
npm install swiper@5 --save
在main.js全局注冊
import VueAwesomeSwiper from "vue-awesome-swiper"; import "swiper/css/swiper.min.css"; Vue.use(VueAwesomeSwiper);
新建swiper組件
<template> <swiper ref="mySwiper" :options="swiperOptions"> <swiper-slide>Slide 1</swiper-slide> <swiper-slide>Slide 2</swiper-slide> <swiper-slide>Slide 3</swiper-slide> <div class="swiper-pagination" slot="pagination"></div> </swiper> </template> <script> export default { data() { return { swiperOptions: { pagination: { el: ".swiper-pagination" } } }; } }; </script> <style scoped lang="stylus"></style>
在home父組件中引入和注冊swiper組件。
<template> <div> <HomeHeader></HomeHeader> <HomeSwiper></HomeSwiper> </div> </template> <script> import HomeHeader from "components/HomeHeader/HomeHeader"; import HomeSwiper from "components/Swiper/Swiper";
8, 此時有個小bug,如果在網速條件差的情況,圖片還沒有加載完成的時候,輪播圖結構下方的結構會先占用輪播圖的位置,直到輪播圖加載完成后,才會到他正確的位置(稱為抖動情況)
原因,當圖片沒加載完成,此時圖片高度為0,下面的結構會撐上去,此時只需要計算寬高比,計算padding-bottom即可解決
解決方法,在swiper組件,新增一個根標簽div ,計算圖片的寬高比例,用樣式來解決
<template> <div class="wrapper"> <swiper ref="mySwiper" :options="swiperOptions"> <swiper-slide> <img class="item" src="@/assets/logo.png" alt="" /> </swiper-slide> <swiper-slide> <img class="item" src="@/assets/logo.png" alt="" /> </swiper-slide> <swiper-slide> <img class="item" src="@/assets/logo.png" alt="" /> </swiper-slide> <div class="swiper-pagination" slot="pagination"></div> </swiper> </div> </template> <script> export default { data() { return { swiperOptions: { pagination: { el: ".swiper-pagination" } } }; } }; </script> <style scoped lang="stylus"> .wrapper overflow :hidden width:100% height:0 padding-bottom :31.25% .item width:100% </style>
#Scoped CSS 當 <style> 標簽有 scoped 屬性時,它的 CSS 只作用於當前組件中的元素。這類似於 Shadow DOM 中的樣式封裝。
vue-loader官網介紹;https://vue-loader.vuejs.org/zh/guide/scoped-css.html#%E6%B7%B7%E7%94%A8%E6%9C%AC%E5%9C%B0%E5%92%8C%E5%85%A8%E5%B1%80%E6%A0%B7%E5%BC%8F
#子組件的根元素 使用 scoped 后,父組件的樣式將不會滲透到子組件中。不過一個子組件的根節點會同時受其父組件的 scoped CSS 和子組件的 scoped CSS 的影響。
這樣設計是為了讓父組件可以從布局的角度出發,調整其子組件根元素的樣式。 #深度作用選擇器 如果你希望 scoped 樣式中的一個選擇器能夠作用得“更深”,例如影響子組件,你可以使用 >>> 操作符:
<template> <div class="wrapper"> <swiper ref="mySwiper" :options="swiperOptions"> <swiper-slide> <img class="item" src="@/assets/logo.png" alt="" /> </swiper-slide> <swiper-slide> <img class="item" src="@/assets/logo.png" alt="" /> </swiper-slide> <swiper-slide> <img class="item" src="@/assets/logo.png" alt="" /> </swiper-slide> <div class="swiper-pagination" slot="pagination"></div> </swiper> </div> </template> <script> export default { data() { return { swiperOptions: { pagination: { el: ".swiper-pagination",
loop:true
} } }; } }; </script> <style scoped lang="stylus"> .wrapper & >>> .swiper-pagination-bullet-active background: red overflow :hidden width:100% height:0 padding-bottom :100% .item width:100% </style>
10.商品圖標區域布局,一個圖標
<div class="icons"> <div class="icon"> <div class="icon-img"> <img class="icon-img-content" src="//s.qunarzz.com/homenode/images/touchheader/hotel.png" alt="" /> </div> <p class="icon-desc">熱門景點</p> </div>
樣式布局,同理,慢速網絡下對於圖片下的結構抖動情況,對用padding-bottom來代替height, 一行八個圖標,一個weidth占25%
<style scoped lang="stylus"> .icons margin-top:.1rem .icon float:left width:25% height :0 padding-bottom :25% position : relative .icon-img position: absolute top: 0 left: 0 right: 0 bottom: .44rem padding :.1rem box-sizing:border-box .icon-img-content display :block margin :0 auto height :100% width:100% .icon-desc position: absolute bottom: 0 left: 0 right: 0 line-height .44rem height .44rem text-align :center
如果,圖片圖標很多,需要用到swiper輪播圖來處理
<div class="icons"> <swiper> <swiper-slide> <div class="icon"> <div class="icon-img"> <img class="icon-img-content" src="//s.qunarzz.com/homenode/images/touchheader/hotel.png" alt="" /> </div> <p class="icon-desc">熱門景點</p> </div> </swiper-slide> <swiper-slide> <div class="icon"> <div class="icon-img"> <img class="icon-img-content" src="//s.qunarzz.com/homenode/images/touchheader/hotel.png" alt="" /> </div> <p class="icon-desc">熱門景點</p> </div> </swiper-slide> </swiper> </div>
此時一排圖片圖標高度占25%,兩排就占50%,而加入swiper組件后,左右滑動的高度距離只有25%, 我們需要增大他的高度為50%, 此時利用到深度選擇器
樣式
.icons margin-top:.1rem & >>>.swiper-container padding-bottom : 50% height :0 .icon float:left width:25% height :0 padding-bottom :25% position : relative
11. 對於圖片圖標輪播的頁數邏輯計算以及樣式抽離公共代碼
圖片圖標的數據
data() { return { iconList: [ { id: "0001", imgUrl: "http://img1.qunarzz.com/piao/fusion/1611/54/ace00878a52d9702.png", desc: "景點門票" }, { id: "0002", imgUrl: "http://img1.qunarzz.com/piao/fusion/1711/df/86cbcfc533330d02.png", desc: "滑雪季" }, { id: "0003", imgUrl: "http://img1.qunarzz.com/piao/fusion/1710/a6/83f636bd75ae6302.png", desc: "泡溫泉" }, { id: "0004", imgUrl: "http://img1.qunarzz.com/piao/fusion/1611/35/2640cab202c41b02.png", desc: "動植園" }, { id: "0005", imgUrl: "http://img1.qunarzz.com/piao/fusion/1611/d0/e09575e66f4aa402.png", desc: "游樂園" }, { id: "0006", imgUrl: "http://img1.qunarzz.com/piao/fusion/1611/59/569d3c096e542502.png", desc: "必游榜單" }, { id: "0007", imgUrl: "http://img1.qunarzz.com/piao/fusion/1611/17/4bd370f3eb1acd02.png", desc: "演出" }, { id: "0008", imgUrl: "http://img1.qunarzz.com/piao/fusion/1611/7f/b1ea3c8c7fb6db02.png", desc: "城市觀光" }, { id: "0009", imgUrl: "http://img1.qunarzz.com/piao/fusion/1611/a9/ffc620dbda9b9c02.png", desc: "一日游" } ]
模板數據填充,每頁輪播圖圖片的數量是8個,第九個圖標需要在第二頁,此時根據iconList數據去計算頁數
<div class="icons"> <swiper> <!-- 輪播圖頁數 --> <swiper-slide > <div class="icon" v-for="(icon, index) in iconList" :key="icon.id"> <div class="icon-img"> <img class="icon-img-content" :src="icon.imgUrl" /> </div> <p class="icon-desc">{{icon.desc}}</p> </div> </swiper-slide> </swiper>
計算頁數,用computed
computed: { // 計算輪播圖每行圖片的頁數 pages() { const pages = []; const { iconList } = this; iconList.forEach((item, index) => { // 計算當前圖標在第幾頁 const page = Math.floor(index / 8); // 判斷第0個索引沒有數據,內嵌一個數組 if (!pages[page]) { pages[page] = []; } // 有數據 pages[page].push(item); }); return pages; } }
在swiper模板中填充
<div class="icons"> <swiper> <!-- 輪播圖頁數 --> <swiper-slide v-for="(page, index) in pages" :key="index"> <div class="icon" v-for="(icon, index) in page" :key="icon.id"> <div class="icon-img"> <img class="icon-img-content" :src="icon.imgUrl" /> </div> <p class="icon-desc">{{icon.desc}}</p> </div> </swiper-slide> </swiper> </div>
優化效果,如果圖片下方文字的數量過多,需要有省略情況
在mixins.styl中定義樣式,然后在該組件中引入,
ellipsis() overflow: hidden white-space: nowrap text-overflow: ellipsis
@import '~assets/style/mixins.styl' .icon-desc position: absolute bottom: 0 left: 0 right: 0 line-height .44rem height .44rem text-align :center ellipsis()