接上篇 https://www.cnblogs.com/chenyingying0/p/12623653.html 下拉刷新 下拉刷新--變化提示文字 base/scroll/index.vue <template> <!-- wiper會實例化構造函數,生成swiper實例 --> <!-- re ...
接上篇 https://www.cnblogs.com/chenyingying0/p/12623653.html
下拉刷新
下拉刷新--變化提示文字
base/scroll/index.vue
<template> <!-- wiper會實例化構造函數,生成swiper實例 --> <!-- ref="swiper"能夠獲取到這個swiper實例 --> <swiper :options="swiperOption" ref='swiper'> <div class="mine-scroll-pull-down" v-if="pullDown"> <!-- ref="pullDownLoading" -- 獲取下拉的loading --> <me-loading :text="pullDownText" inline ref="pullDownLoading" /> </div> <swiper-slide> <slot></slot> </swiper-slide> <div class="swiper-scrollbar" v-if="scrollbar" slot="scrollbar"></div> </swiper> </template> <script> // 組件首字母大寫,否則會報錯 import {Swiper,SwiperSlide} from 'vue-awesome-swiper'; import MeLoading from 'base/loading'; import { PULL_DOWN_HEIGHT, PULL_DOWN_TEXT_INIT, PULL_DOWN_TEXT_START, PULL_DOWN_TEXT_ING, PULL_DOWN_TEXT_END } from './config'; export default { name:"MeScroll", components:{ Swiper, SwiperSlide, MeLoading }, props:{//過濾器 scrollbar:{ type:Boolean, default:true }, data:{//熱門推薦載入完成後傳遞過來的recommends數據 type:[Array,Object] }, pullDown:{ type:Boolean, default:false } }, data(){ return { pullDownText:PULL_DOWN_TEXT_INIT,//設置初始化文字 swiperOption:{ direction:'vertical',//垂直方向 slidesPerView:'auto',//一次顯示幾張 freeMode:true,//任意滑動多少距離 setWrapperSize:true,//根據內容設置容器尺寸 scrollbar:{ el:this.scrollbar?'.swiper-scrollbar':null, hide:true //滾動條自動隱藏 }, on:{ //swiper配置時會觸發sliderMove方法,這裡調用時執行自定義的scroll方法 sliderMove:this.scroll } } } }, methods:{ update(){//不知道怎麼寫就去swiper官網查api console.log(this.$refs.swiper);//列印swiper實例 this.$refs.swiper && this.$refs.swiper.$swiper.update();//調用swiper.update()更新滾動條 }, scroll(){ const swiper=this.$refs.swiper.$swiper; console.log(swiper.translate);//列印出滾動條滾過的距離 if(swiper.translate>0){//下拉 if(!this.pullDown){//如果不需要下拉刷新 return; } if(swiper.translate>PULL_DOWN_HEIGHT){ this.$refs.pullDownLoading.setText(PULL_DOWN_TEXT_START); }else{ this.$refs.pullDownLoading.setText(PULL_DOWN_TEXT_INIT); } } } }, watch:{//檢測數據變化的事件 data(){ this.update();//data數據變化時執行update函數 } } } </script> <style lang="scss" scoped> @import '~assets/scss/mixins'; .swiper-container{ width:100%; height:100%; overflow:hidden; & .swiper-slide{ height:auto; } } //預設是不顯示的 .mine-scroll-pull-down{ position:absolute; left:0; bottom:100%; width:100%; height:80px; } </style>
base/loading/index.vue
<template> <div class="mine-loading" :class="{'me-loading-inline':inline}"> <span class="mine-loading-indicator" v-if="indicator==='on'" > <img src="./loading.gif" alt=""> </span> <span class="mine-loading-text" v-if="loadingText">{{loadingText}}</span> </div> </template> <script> export default { name:"MeLoading", props:{//過濾器 indicator:{ type:String, default:'on', validator(value){ return ['on','off'].indexOf(value)>-1; } }, text:{ type:String, default:'載入中...' }, inline:{ type:Boolean, default:false } }, data(){ return{ loadingText:this.text } }, methods:{ setText(text){ this.loadingText=text; } }, watch:{ text(text){ this.loadingText=text; } } } </script> <style lang="scss" scoped> @import '~assets/scss/mixins'; .mine-loading{ width:100%; height:100%; @include flex-center(column); //圖文左右排列時 &.me-loading-inline{ flex-direction: row; .mine-loading-indicator ~ .mine-loading-text{ margin-top:0px; margin-left:7px; } } .mine-loading-indicator{ } // 存在.mine-loading-indicator和.mine-loading-text時 .mine-loading-indicator ~ .mine-loading-text{ margin-top:7px; } } </style>
base/scroll/config.js
export const PULL_DOWN_HEIGHT=100; export const PULL_DOWN_TEXT_INIT='再拉,再拉就刷新給你看'; export const PULL_DOWN_TEXT_START='夠了啦,鬆開人家嘛'; export const PULL_DOWN_TEXT_ING='刷的好累呀,喵~'; export const PULL_DOWN_TEXT_END='刷新完啦';
pages/home/index.vue
<template> <div class="home"> <header class="g-header-container"> <!-- 沒有內容自閉合即可--> <home-header/> </header> <!-- 滾動條接收到數據後開始更新 --> <!-- pullDown是布爾值,可以使用簡寫直接傳入,不加冒號 --> <me-scroll :data="recommends" pullDown> <home-slider /> <home-nav /> <!-- 接收熱門推薦載入完畢的消息 --> <home-recommend @loaded="getRecommends" /> </me-scroll> <div class="g-backup-container"></div> <!-- 當前頁面存在二級頁面時需要使用router-view --> <router-view></router-view> </div> </template> <script> import MeScroll from 'base/scroll'; import HomeHeader from './header'; import HomeSlider from './slider'; import HomeNav from './nav'; import HomeRecommend from './recommend'; export default { name:"Home", components:{ HomeHeader, HomeSlider, MeScroll, HomeNav, HomeRecommend }, data(){ return{ recommends:[] } }, methods:{ getRecommends(recommends){ this.recommends=recommends; }, updateScroll(){ } } } </script> <style lang="scss" scoped> // 引入前面需要加波浪線,否則會報錯 @import "~assets/scss/mixins"; .home{ overflow:hidden; width:100%; height:100%; background:$bgc-theme; } </style>
效果圖
下拉刷新--鬆手刷新
修改base/scroll/index.vue
<template> <!-- wiper會實例化構造函數,生成swiper實例 --> <!-- ref="swiper"能夠獲取到這個swiper實例 --> <swiper :options="swiperOption" ref='swiper'> <div class="mine-scroll-pull-down" v-if="pullDown"> <!-- ref="pullDownLoading" -- 獲取下拉的loading --> <me-loading :text="pullDownText" inline ref="pullDownLoading" /> </div> <swiper-slide> <slot></slot> </swiper-slide> <div class="swiper-scrollbar" v-if="scrollbar" slot="scrollbar"></div> </swiper> </template> <script> // 組件首字母大寫,否則會報錯 import {Swiper,SwiperSlide} from 'vue-awesome-swiper'; import MeLoading from 'base/loading'; import { PULL_DOWN_HEIGHT, PULL_DOWN_TEXT_INIT, PULL_DOWN_TEXT_START, PULL_DOWN_TEXT_ING, PULL_DOWN_TEXT_END } from './config'; export default { name:"MeScroll", components:{ Swiper, SwiperSlide, MeLoading }, props:{//過濾器 scrollbar:{ type:Boolean, default:true }, data:{//熱門推薦載入完成後傳遞過來的recommends數據 type:[Array,Object] }, pullDown:{ type:Boolean, default:false } }, data(){ return { pulling:false,//是否正在下拉 pullDownText:PULL_DOWN_TEXT_INIT,//設置初始化文字 swiperOption:{ direction:'vertical',//垂直方向 slidesPerView:'auto',//一次顯示幾張 freeMode:true,//任意滑動多少距離 setWrapperSize:true,//根據內容設置容器尺寸 scrollbar:{ el:this.scrollbar?'.swiper-scrollbar':null, hide:true //滾動條自動隱藏 }, on:{ //swiper配置時會觸發sliderMove方法,這裡調用時執行自定義的scroll方法 sliderMove:this.scroll, touchEnd:this.touchEnd//touchEnd是swiper提供的滾動結束的函數,this.touchEnd是我們自己寫的函數 } } } }, methods:{ update(){//不知道怎麼寫就去swiper官網查api //console.log(this.$refs.swiper);//列印swiper實例 this.$refs.swiper && this.$refs.swiper.$swiper.update();//調用swiper.update()更新滾動條 }, scroll(){ const swiper=this.$refs.swiper.$swiper; //如果正在下拉中,不會再次執行 if(this.pulling) return; console.log(swiper.translate);//列印出滾動條滾過的距離 if(swiper.translate>0){//下拉 if(!this.pullDown){//如果不需要下拉刷新 return; } if(swiper.translate>PULL_DOWN_HEIGHT){ this.$refs.pullDownLoading.setText(PULL_DOWN_TEXT_START); }else{ this.$refs.pullDownLoading.setText(PULL_DOWN_TEXT_INIT); } } }, touchEnd(){ const swiper=this.$refs.swiper.$swiper; //如果正在下拉中,不會再次執行 if(this.pulling) return; if(swiper.translate>PULL_DOWN_HEIGHT){//如果距離大於設定的距離 if(!this.pullDown){//如果不需要下拉刷新 return; } this.pulling=true; swiper.allowTouchMove=false;//禁止觸摸 swiper.setTransition(swiper.params.speed);//設置初始速度 swiper.setTranslate(PULL_DOWN_HEIGHT);//移動到設定的位置(拖動過度時回到設置的位置) swiper.params.virtualTranslate=true;//定住不給回彈 this.$refs.pullDownLoading.setText(PULL_DOWN_TEXT_ING);//設置正在刷新中的文字 this.$emit("pull-down",this.pullDownEnd);//觸發消息,傳遞結束下拉的函數 } }, pullDownEnd(){ const swiper=this.$refs.swiper.$swiper; this.pulling=false; this.$refs.pullDownLoading.setText(PULL_DOWN_TEXT_END);//設置載入結束後的文字 swiper.allowTouchMove=true;//可以觸摸 swiper.setTransition(swiper.params.speed);//設置初始速度 swiper.params.virtualTranslate=false;//可以回彈 swiper.setTranslate(0);//移動到最初的位置 } }, watch:{//檢測數據變化的事件 data(){ this.update();//data數據變化時執行update函數 } } } </script> <style lang="scss" scoped> @import '~assets/scss/mixins'; .swiper-container{ width:100%; height:100%; overflow:hidden; & .swiper-slide{ height:auto; } } //預設是不顯示的 .mine-scroll-pull-down{ position:absolute; left:0; bottom:100%; width:100%; height:80px; } </style>
修改pages/home/index.vue
<template> <div class="home"> <header class="g-header-container"> <!-- 沒有內容自閉合即可--> <home-header/> </header> <!-- 滾動條接收到數據後開始更新 --> <!-- pullDown是布爾值,可以使用簡寫直接傳入,不加冒號 --> <!-- 接收到pull-down消息後,觸發pullToRefresh方法 --> <me-scroll :data="recommends" pullDown @pull-down="pullToRefresh"> <home-slider /> <home-nav /> <!-- 接收熱門推薦載入完畢的消息 --> <home-recommend @loaded="getRecommends" /> </me-scroll> <div class="g-backup-container"></div> <!-- 當前頁面存在二級頁面時需要使用router-view --> <router-view></router-view> </div> </template> <script> import MeScroll from 'base/scroll'; import HomeHeader from './header'; import HomeSlider from './slider'; import HomeNav from './nav'; import HomeRecommend from './recommend'; export default { name:"Home", components:{ HomeHeader, HomeSlider, MeScroll, HomeNav, HomeRecommend }, data(){ return{ recommends:[] } }, methods:{ getRecommends(recommends){ this.recommends=recommends; }, updateScroll(){ }, pullToRefresh(end){ setTimeout(()=>{ console.log("下拉刷新"); end(); },1000); } } } </script> <style lang="scss" scoped> // 引入前面需要加波浪線,否則會報錯 @import "~assets/scss/mixins"; .home{ overflow:hidden; width:100%; height:100%; background:$bgc-theme; } </style>
效果圖
更新幻燈片
真正實現通過下拉刷新,更新幻燈片
修改src/api/home.js
import axios from 'axios'; import {SUCC_CODE,TIMEOUT,HOME_RECOMMEND_PAGE_SIZE,JSONP_OPTIONS} from './config'; import jsonp from 'assets/js/jsonp'; // shuffle打亂數組順序的方法 const shuffle=(arr)=>{ const arrLength=arr.length; let i=arrLength; let rndNum; while(i--){ //如果當前索引不等於隨機數索引,則交換這兩個索引的位置 if(i!==(rndNum=Math.floor(Math.random()*arrLength))){ //這是一種新的交換寫法 ES6解構 [arr[i],arr[rndNum]]=[arr[rndNum],arr[i]]; } } return arr; } //獲取幻燈片數據 ajax export const getHomeSliders=()=>{ //演示超時錯誤 return axios.get('http://www.imooc.com/api/home/slider',{ timeout:TIMEOUT }).then(res=>{ //console.log(res); if(res.data.code===SUCC_CODE){ //這段代碼的作用主要是演示下拉刷新的效果 //每次刷新會載入出不同數量,不同順序的輪播圖 let sliders=res.data.slider; const slider=[sliders[Math.floor(Math.random()*sliders.length)]];//slider是從sliders中隨機取出一張圖片,並包裝成數組 sliders=shuffle(sliders.filter(()=>Math.random()>=0.5));//50%的概率,真就返回,假就剔除 if(sliders.length===0){ sliders=slider;//如果不幸一張都沒有,就把之前隨機的那張賦值給sliders } return sliders; //return res.data.slider; } throw new Error('沒有成功獲取到數據'); }).catch(err=>{ console.log(err); //錯誤處理 return [{ linkUrl:'www.baidu.com', picUrl:require('assets/img/404.png') }] }).then(data=>{//獲取輪播圖數據後,延遲一秒再顯示 return new Promise(resolve=>{ setTimeout(()=>{ resolve(data); },1000); }) }); } //獲取熱門推薦數據 export const getHomeRecommend=(page=1,psize=HOME_RECOMMEND_PAGE_SIZE)=>{ const url='https://ju.taobao.com/json/tg/ajaxGetItemsV2.json'; const params={ page, psize, type:0, frontCatId:''//type和frontCatId是根據給定的淘寶介面來添加的 } //調用jsonp獲取數據 return jsonp(url,params,JSONP_OPTIONS).then(res=>{ if(res.code==='200'){ return res; } throw new Error('沒有成功獲取到數據'); }).catch(err=>{ if(err){ console.log(err); } }).then(res=>{ //延遲一秒返回數據 return new Promise(resolve=>{ setTimeout(()=>{ resolve(res); },1000); }) }) }
pages/home/slider.vue
<template> <div class="slider-wrapper"> <!-- sliders沒載入時顯示loading --> <Meloading v-if="!sliders.length"></Meloading> <!-- 分開傳才能分開校驗,因此不直接傳入對象 --> <MeSlider :data="sliders" :direction="direction" :loop="loop" :interval="interval" :pagination="pagination" v-else > <swiper-slide v-for="(item,index) in sliders" :key="index"> <a :href="item.linkUrl" class="slider-link"> <img :src="item.picUrl" class="slider-img"> </a> </swiper-slide> </MeSlider> </div> </template> <script> import MeSlider from 'base/slider'; import { SwiperSlide } from 'vue-awesome-swiper'; import { sliderOptions } from './config'; import { getHomeSliders } from 'api/home'; import Meloading from 'base/loading'; export default { name:"HomeSlider", components:{ MeSlider, SwiperSlide, Meloading }, data(){ return{ direction:sliderOptions.direction, loop:sliderOptions.loop, interval:sliderOptions.interval, pagination:sliderOptions.pagination, sliders:[],//這是從伺服器讀取 } }, created(){ //一般在created里獲取遠程數據 this.getSliders(); }, methods:{ //api update(){ return this.getSliders(); }, getSliders(){ return getHomeSliders().then(data=>{ //console.log(data); this.sliders=data; }); } } } </script> <style lang="scss" scoped> // 引入前面需要加波浪線,否則會報錯 @import "~assets/scss/mixins"; .slider-wrapper{ width:100%; height:183px; } .slider-link{ display:block; } .slider-link, .slider-img{ width:100%; height:100%; } </style>
pages/home/index.vue
<template> <div class="home"> <header class="g-header-container"> <!-- 沒有內容自閉合即可--> <home-header/> </header> <!-- 滾動條接收到數據後開始更新 --> <!-- pullDown是布爾值,可以使用簡寫直接傳入,不加冒號 --> <!-- 接收到pull-down消息後,觸發pullToRefresh方法 --> <me-scroll :data="recommends" pullDown @pull-down="pullToRefresh"> <home-slider ref="slider" /> <home-nav /> <!-- 接收熱門推薦載入完畢的消息 --> <home-recommend @loaded="getRecommends" /> </me-scroll> <div class="g-backup-container"></div> <!-- 當前頁面存在二級頁面時需要使用router-view --> <router-view></router-view> </div> </template> <script> import MeScroll from 'base/scroll'; import HomeHeader from './header'; import HomeSlider from './slider'; import HomeNav from './nav'; import HomeRecommend from './recommend'; export default { name:"Home", components:{ HomeHeader, HomeSlider, MeScroll, HomeNav, HomeRecommend }, data(){ return{ recommends:[] } }, methods:{ getRecommends(recommends){ this.recommends=recommends; }, updateScroll(){ }, pullToRefresh(end){ this.$refs.slider.update().then(end); } } } </script> <style lang="scss" scoped> // 引入前面需要加波浪線,否則會報錯 @import "~assets/scss/mixins"; .home{ overflow:hidden; width:100%; height:100%; background:$bgc-theme; } </style>
base/slider/index.vue
<template> <div class="mine-slider"> <!-- 動態的屬性前面加冒號 --> <swiper :options="swiperOption" class="swiper-container" :key="keyId"> <slot></slot> <div class="swiper-pagination" v-if="pagination" slot="pagination"></div> </swiper> </div> </template> <script> import { Swiper } from 'vue-awesome-swiper'; export default { name:"MeSlider", components: { Swiper }, props:{ direction:{ type:String, default:'horizontal', validator(value){ // 返回true則驗證通過 return [ 'horizontal', 'vertical' ].indexOf(value)>-1; } }, interval:{//自動輪播 type:Number, default:3000, validator(value){ return value>=0; } }, loop:{//無縫滾動 type:Boolean, default:true }, pagination:{//分液器 type:Boolean, default:true }, data:{ type:Array, default(){ return []; } } }, data(){ return{ keyId:Math.random(), } }, watch:{ data(newData){ if(newData.length===0) return; this.swiperOption.loop=newData.length<=1?false:this.loop;//每次刷新後重新判斷是否需要滾動 this.keyId=Math.random(); } }, created(){ this.init(); }, methods:{ init(){ this.swiperOption={ watchOverflow:true,//只有一張圖片時不設置滾動效果 direction:this.direction,//滾動方向 autoplay:this.interval?{ delay:this.interval, disableOnInteraction:false//手指滑動時是否停止自動輪播 }:false, slidesPerView:1,//同時顯示幾張圖片 loop:this.data.length<=1?false:this.loop,//是否開啟無縫滾動,1張圖片不需要滾動 pagination:{//分頁器 el:this.pagination?'.swiper-pagination':null } } } } } </script> <style lang="scss" scoped> @import '~assets/scss/mixins'; .swiper-container{ width:100%; height:100%; } </style>
效果圖