接上篇 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>
效果图

来源:https://www.cnblogs.com/chenyingying0/p/12635080.html