一、需求问题
在vue的项目中,我们可能也经常会遇到这样的需求。当在页面当中,对页面进行下拉刷新,重新请求数据,加载新的内容。针对这个,我们可以使用better-scroll,在此基础上进行封装下拉刷新组件,实现多个页面都可以使用这个组件,下拉刷新,得到复用。
二、需求分析
- 在components文件夹中,建立Scroller文件夹,里面建立index.vue文件,作为Scroller组件。这个下拉刷新组件在页面的多个位置中都可能会用的到,可以全局注册组件。在项目的main.js文件中写以下的代码配置,进行全局注册
import Scroller from '@/components/Scroller'
// 全局注册 Scroller 组件
Vue.component('Scroller', Scroller);
-
在
Scroller
组件中,引入better-scroll
,在props中,写handleToScroll
和handleToTouchEnd
这两个属性,在后面组件传值的时候需要使用。在mounted()
钩子函数中,通过new BScroll
创建对象,传入DOM
对象和配置参数项。通过scroll.on
进行绑定scroll
和touchEnd
事件,在后面通过pos
参数写回调函数,分别调用handleToScroll
和handleToTouchEnd
。 -
在需要用到的页面中,就可以直接写
Scroller
组件,在组件内部进行绑定属性,handleToScroll
和handleToTouchEnd
这两个属性,它们也是函数。在methods中,写handleToScroll
和handleToTouchEnd
这两个函数,参数为pos,通过pos.y
进行判断位置,然后执行相应的操作。同时在data中,写pullDownMsg
参数为空,这个会进行动态的显示提示消息,赋予不同的值。
<Scroller :handleToScroll="handleToScroll" :handleToTouchEnd="handleToTouchEnd">
三、需求实现
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import axios from 'axios'
Vue.prototype.axios = axios;
Vue.filter('setWH', (url, arg) => {
return url.replace(/w\.h/, arg);
});
Vue.config.productionTip = false;
import Scroller from '@/components/Scroller'
// 全局注册 Scroller 组件
Vue.component('Scroller', Scroller);
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
Scroll
文件夹下的index.vue
,封装组件
<template>
<div class="wrapper" ref="wrapper">
<!-- solt 插槽实现内容分发 -->
<slot></slot>
</div>
</template>
<script>
import BScroll from 'better-scroll';
export default {
name: 'Scroller',
props: {
handleToScroll: {
type: Function,
default: function() {}
},
handleToTouchEnd: {
type: Function,
default: function() {}
}
},
mounted() {
var scroll = new BScroll( this.$refs.wrapper, {
tap: true,
probeType: 1
});
this.scroll = scroll;
scroll.on('scroll', (pos) => {
this.handleToScroll(pos);
});
scroll.on('touchEnd', (pos) => {
this.handleToTouchEnd(pos);
});
},
methods: {
toScrollTop(y) {
this.scroll.scrollTo(0,y);
}
}
}
</script>
<style scoped>
.wrapper { height: 100%; }
</style>
movie
下的index.vue
, 路由页面使用组件
<template>
<div class="movie_body" ref="movie_body">
<Scroller :handleToScroll="handleToScroll" :handleToTouchEnd="handleToTouchEnd">
<ul>
<li class="pullDown">{{ pullDownMsg }}</li>
<li v-for="item in movieList" :key="item.id">
<div class="pic_show" @tap="handleToDetail"><img :src="item.img | setWH('128.180')"></div>
<div class="info_list">
<h2>{{ item.nm }} <img v-if="item.version" src="@/assets/maxs.png"></h2>
<p>观众评 <span class="grade">{{ item.sc }}</span></p>
<p>主演: {{ item.star }}</p>
<p>{{ item.showInfo }}</p>
</div>
<div class="btn_mall">
购票
</div>
</li>
</ul>
</Scroller>
</div>
</template>
<script>
export default {
name: 'NowPlaying',
data() {
return {
movieList: [],
pullDownMsg: '',
}
},
mounted() {
this.axios.get('/api/movieOnInfoList?cityId=10').then((res) => {
var msg = res.data.msg;
if( msg === 'ok') {
this.movieList = res.data.data.movieList;
}
})
},
methods: {
handleToDetail () {
console.log('handleToDetail');
},
handleToScroll (pos) {
if ( pos.y > 30 ) {
this.pullDownMsg = '正在更新中...';
}
},
handleToTouchEnd (pos) {
if ( pos.y > 30 ) {
this.axios.get('/api/movieOnInfoList?cityId=10').then( (res) => {
var msg = res.data.msg;
if ( msg === 'ok') {
this.pullDownMsg = '更新完成';
setTimeout(() => {
this.movieList = res.data.data.movieList;
this.pullDownMsg = ''
}, 1000);
}
});
}
}
}
}
</script>
<style scoped>
#content .movie_body{ flex:1; overflow:auto;}
.movie_body ul{ margin:0 12px; overflow: hidden;}
.movie_body ul li{ margin-top:12px; display: flex; align-items:center; border-bottom: 1px #e6e6e6 solid; padding-bottom: 10px;}
.movie_body .pic_show{ width:64px; height: 90px;}
.movie_body .pic_show img{ width:100%;}
.movie_body .info_list { margin-left: 10px; flex:1; position: relative;}
.movie_body .info_list h2{ font-size: 17px; line-height: 24px; width:150px; overflow: hidden; white-space: nowrap; text-overflow:ellipsis;}
.movie_body .info_list p{ font-size: 13px; color:#666; line-height: 22px; width:200px; overflow: hidden; white-space: nowrap; text-overflow:ellipsis;}
.movie_body .info_list .grade{ font-weight: 700; color: #faaf00; font-size: 15px;}
.movie_body .info_list img{ width:50px; position: absolute; right:10px; top: 5px;}
.movie_body .btn_mall , .movie_body .btn_pre{ width:47px; height:27px; line-height: 28px; text-align: center; background-color: #f03d37; color: #fff; border-radius: 4px; font-size: 12px; cursor: pointer;}
.movie_body .btn_pre{ background-color: #3c9fe6;}
.movie_body .pullDown{ margin: 0; padding: 0; border: none;}
</style>