vue移动端下拉刷新、上拉加载
由于自身的项目比较简单,只有几个H5页面,用来嵌入app中,所有没有引入移动端的UI框架,但是介于能让用户在浏览H5页面时有下拉刷新和上拉加载,有更好的用户体验,自己写组件实现。
1、下拉刷新
DropDownRefresh.vue
<template lang="html">
<div class="refresh-moudle" @touchstart="touchStart($event)" @touchmove="touchMove($event)" @touchend="touchEnd($event)" :style="{transform: 'translate3d(0,' + top + 'px, 0)'}">
<header class="pull-refresh">
<slot name="pull-refresh">
<div class="down-tip" v-if="dropDownState==1">
<img v-if="dropDownInfo.downImg" class="down-img" :src="require('../../assets/images/refreshAndReload/'+dropDownInfo.downImg)">
<span class="down-text">{{dropDownInfo.downText}}</span>
</div>
<div class="up-tip" v-if="dropDownState==2">
<img v-if="dropDownInfo.upImg" class="up-img" :src="require('../../assets/images/refreshAndReload/'+dropDownInfo.upImg)">
<span class="up-text">{{dropDownInfo.upText}}</span>
</div>
<div class="refresh-tip" v-if="dropDownState==3">
<img v-if="dropDownInfo.refreshImg" class="refresh-img" :src="require('../../assets/images/loading/'+dropDownInfo.refreshImg)">
<span class="refresh-text">{{dropDownInfo.refreshText}}</span>
</div>
</slot>
</header>
<slot></slot>
</div>
</template>
<script>
export default {
props: {
onRefresh: {
type: Function,
required: false
}
},
data () {
return {
defaultOffset: 50, // 默认高度, 相应的修改.releshMoudle的margin-top和.down-tip, .up-tip, .refresh-tip的height
top: 0,
scrollIsToTop: 0,
startY: 0,
isDropDown: false, // 是否下拉
isRefreshing: false, // 是否正在刷新
dropDownState: 1, // 显示1:下拉可以刷新, 2:松开立即刷新, 3:正在刷新数据中...
dropDownInfo: {
downText: '下拉可以刷新',
downImg: 'arrow.png',
upText: '松开立即刷新',
upImg: 'arrow.png',
refreshText: '正在刷新数据...',
refreshImg: 'loading.png'
}
}
},
created () {
if (document.querySelector('.down-tip')) {
// 获取不同手机的物理像素(dpr),以便适配rem
this.defaultOffset = document.querySelector('.down-tip').clientHeight || this.defaultOffset
}
},
methods: {
/**
* 触摸开始,手指点击屏幕时
* @param {object} e Touch 对象包含的属性
*/
touchStart (e) {
this.startY = e.targetTouches[0].pageY
},
/**
* 接触点改变,滑动时
* @param {object} e Touch 对象包含的属性
*/
touchMove (e) {
this.scrollIsToTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop // safari 获取scrollTop用window.pageYOffset
if (e.targetTouches[0].pageY > this.startY) {
// 下拉
this.isDropDown = true
if (this.scrollIsToTop === 0 && !this.isRefreshing) {
// 拉动的距离
let diff = e.targetTouches[0].pageY - this.startY - this.scrollIsToTop
this.top = Math.pow(diff, 0.8) + (this.dropDownState === 3 ? this.defaultOffset : 0)
if (this.top >= this.defaultOffset) {
this.dropDownState = 2
e.preventDefault()
} else {
this.dropDownState = 1
// 去掉会导致ios无法刷新
e.preventDefault()
}
}
} else {
this.isDropDown = false
this.dropDownState = 1
}
},
/**
* 触摸结束,手指离开屏幕时
* @param {object} e Touch 对象包含的属性
*/
touchEnd (e) {
if (this.isDropDown && !this.isRefreshing) {
if (this.top >= this.defaultOffset) {
// do refresh
this.refresh()
this.isRefreshing = true
} else {
// cancel refresh
this.isRefreshing = false
this.isDropDown = false
this.dropDownState = 1
this.top = 0
}
}
},
/**
* 刷新
*/
refresh () {
this.dropDownState = 3
this.top = this.defaultOffset
// 这是全是静态数据,延时1200毫秒,给用户一个刷新的感觉,如果是接口数据的话,直接调接口即可
setTimeout(() => {
this.onRefresh(this.refreshDone)
}, 1200)
},
/**
* 刷新完成
*/
refreshDone () {
this.isRefreshing = false
this.isDropDown = false
this.dropDownState = 1
this.top = 0
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.refresh-moudle {
width: 100%;
margin-top: -100px;
-webkit-overflow-scrolling: touch; /* ios5+ */
}
.pull-refresh {
width: 100%;
color: #999;
transition-duration: 200ms;
font-size: 24px;
}
.refresh-moudle .down-tip,
.up-tip,
.refresh-tip {
display: flex;
align-items: center;
justify-content: center;
height: 100px;
}
.down-img {
width: 35px;
height: 35px;
margin-right: 15px;
transform: rotate(0deg);
animation: anticlockwise 0.8s ease;
}
@keyframes anticlockwise {
0% {
transform: rotate(-180deg);
}
100% {
transform: rotate(0deg);
}
}
.up-img {
width: 35px;
height: 35px;
margin-right: 15px;
transform: rotate(180deg);
animation: clockwise 0.8s ease;
}
@keyframes clockwise {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(-180deg);
}
}
.refresh-img {
width: 35px;
height: 35px;
margin-right: 15px;
animation: rotating 1.5s linear infinite;
}
@keyframes rotating {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(1turn);
}
}
</style>
2、上拉加载
PullUpReload.vue
<template lang="html">
<div class="load-moudle" @touchstart="touchStart($event)" @touchmove="touchMove($event)" @touchend="touchend($event)">
<slot></slot>
<footer class="load-more">
<slot name="load-more">
<div class="more-tip" v-if="pullUpState==1">
<span class="more-text">{{pullUpInfo.moreText}}</span>
</div>
<div class="loading-tip" v-if="pullUpState==2">
<span class="loading-icon"></span>
<span class="loading-text">{{pullUpInfo.loadingText}}</span>
</div>
<div class="no-more-tip" v-if="pullUpState==3">
<span class="connecting-line"></span>
<span class="no-more-text">{{pullUpInfo.noMoreText}}</span>
<span class="connecting-line"></span>
</div>
</slot>
</footer>
</div>
</template>
<script>
export default {
props: {
parentPullUpState: {
default: 0
},
onInfiniteLoad: {
type: Function,
require: false
}
},
data () {
return {
top: 0,
pullUpState: 0, // 1:上拉加载更多, 2:加载中……, 3:我是有底线的
isLoading: false, // 是否正在加载
pullUpInfo: {
moreText: '上拉加载更多',
loadingText: '数据加载中...',
noMoreText: '我是有底线的'
},
startX: 0,
startY: 0,
endX: 0,
endY: 0
}
},
methods: {
/**
* 触摸开始,手指点击屏幕时
* @param {object} e Touch 对象包含的属性
*/
touchStart (e) {
this.startX = e.touches[0].pageX
this.startY = e.touches[0].pageY
},
/**
* 接触点改变,滑动时
* @param {object} e Touch 对象包含的属性
*/
touchMove (e) {
this.endX = e.changedTouches[0].pageX
this.endY = e.changedTouches[0].pageY
let direction = this.getSlideDirection(this.startX, this.startY, this.endX, this.endY)
switch (direction) {
case 0:
// console.log('没滑动')
break
case 1:
// console.log('向上')
this.scrollToTheEnd()
break
case 2:
// console.log('向下')
break
case 3:
// console.log('向左')
break
case 4:
// console.log('向右')
break
default:
}
},
/**
* 触摸结束,手指离开屏幕时
* @param {object} e Touch 对象包含的属性
*/
touchend (e) {
this.isLoading = false
},
/**
* 判断滚动条是否到底
*/
scrollToTheEnd () {
let innerHeight = document.querySelector('.load-moudle').clientHeight
// 变量scrollTop是滚动条滚动时,距离顶部的距离
let scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop
// 变量scrollHeight是滚动条的总高度
let scrollHeight = document.documentElement.clientHeight || document.body.scrollHeight
// 滚动条到底部的条件
if (scrollTop + scrollHeight >= innerHeight) {
if (this.pullUpState !== 3 && !this.isLoading) {
this.infiniteLoad()
}
// console.log('距顶部' + scrollTop + '滚动条总高度' + scrollHeight + '内容高度' + innerHeight)
}
},
/**
* 上拉加载数据
*/
infiniteLoad () {
if (this.pullUpState !== 0) {
this.pullUpState = 2
this.isLoading = true
this.onInfiniteLoad(this.infiniteLoadDone)
}
},
/**
* 加载数据完成
*/
infiniteLoadDone () {
this.pullUpState = 1
},
/**
* 返回角度
*/
getSlideAngle (dx, dy) {
return Math.atan2(dy, dx) * 180 / Math.PI
},
/**
* 根据起点和终点返回方向 1:向上,2:向下,3:向左,4:向右,0:未滑动
* @param {number} startX X轴开始位置
* @param {number} startY X轴结束位置
* @param {number} endX Y轴开始位置
* @param {number} endY Y轴结束位置
*/
getSlideDirection (startX, startY, endX, endY) {
let dy = startY - endY
let dx = endX - startX
let result = 0
// 如果滑动距离太短
if (Math.abs(dx) < 2 && Math.abs(dy) < 2) {
return result
}
let angle = this.getSlideAngle(dx, dy)
if (angle >= -45 && angle < 45) {
result = 4
} else if (angle >= 45 && angle < 135) {
result = 1
} else if (angle >= -135 && angle < -45) {
result = 2
} else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) {
result = 3
}
return result
}
},
watch: {
parentPullUpState (curVal, oldVal) {
this.pullUpState = curVal
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.load-more {
width: 100%;
color: #c0c0c0;
background: #fafafa;
font-size: 24px;
}
.more-tip,
.loading-tip,
.no-more-tip {
display: flex;
align-items: center;
justify-content: center;
height: 150px;
}
.load-moudle .loading-icon {
display: inline-flex;
width: 35px;
height: 35px;
background: url(../../assets/images/refreshAndReload/loading.png) no-repeat;
background-size: cover;
margin-right: 5px;
animation: rotating 2s linear infinite;
}
@keyframes rotating {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(1turn);
}
}
.connecting-line {
display: inline-flex;
width: 150px;
height: 2px;
background: #ddd;
margin-left: 20px;
margin-right: 20px;
}
</style>
3、对两个组件的使用
<template>
<section class="container">
<v-refresh :on-refresh="onRefresh">
<v-reload
:on-infinite-load="onInfiniteLoad"
:parent-pull-up-state="infiniteLoadData.pullUpState"
>
<div class="bank-box">
<div class="bank-list" v-for="item in bankList" :key="item.id">
<div
class="bank-icon"
:style="{ 'background': 'url(' + require('../../assets/images/bankIcon/'+item.iconName) + ') no-repeat', 'background-size': '100%' }"
></div>
<span class="bank-name">{{item.bankName}}</span>
</div>
</div>
<div class="hot-box">
<div class="hot-header">
<span class="hot-name">热门推荐</span>
<div class="more-box">
<span class="more-text">查看更多</span>
<span class="more-icon"></span>
</div>
</div>
<div class="hot-centenrt">
<div class="hot-left">
<span class="left-name">{{hotLeft.name}}</span>
<span class="left-desc">{{hotLeft.desc}}</span>
<div
class="left-img"
:style="{ 'background': 'url(' + require('../../assets/images/bank/'+hotLeft.imgName) + ') no-repeat', 'background-size': '100%' }"
></div>
</div>
<div class="hot-right">
<div class="right-top">
<div class="text-box">
<span class="right-name">{{centenrtOne.name}}</span>
<span class="right-desc">{{centenrtOne.desc}}</span>
</div>
<div
class="right-img"
:style="{ 'background': 'url(' + require('../../assets/images/bank/'+centenrtOne.imgName) + ') no-repeat', 'background-size': '100%' }"
></div>
</div>
<div class="hot-right-bottom">
<div class="text-box2">
<span class="right-name2">{{centenrtTwo.name}}</span>
<span class="right-desc2">{{centenrtTwo.desc}}</span>
</div>
<div
class="right-img"
:style="{ 'background': 'url(' + require('../../assets/images/bank/'+centenrtTwo.imgName) + ') no-repeat', 'background-size': '100%' }"
></div>
</div>
</div>
</div>
</div>
<div class="card-state">
<div class="card-progress border-right">
<div class="progress-icon"></div>
<div class="card-text">
<span class="card-name">办卡进度</span>
<span class="card-desc">让等待随处可见</span>
</div>
</div>
<div class="card-activation">
<div class="activation-icon"></div>
<div class="card-text">
<span class="card-name">办卡激活</span>
<span class="card-desc">让等待随处可见</span>
</div>
</div>
</div>
<div class="card-order">
<div class="border-bottom card-bottom">
<div class="hot-header">
<span class="hot-name">热卡排行</span>
</div>
</div>
<div slot="load-more">
<li
class="card-list"
v-for="(item,index) in infiniteLoadData.pullUpList"
:key="item.id"
>
<div
class="card-content"
:class="infiniteLoadData.pullUpList.length - 1 != index? 'card-bottom':''"
>
<div
class="card-img"
:style="{ 'background': 'url(' + require('../../assets/images/bank/'+item.imgName) + ') no-repeat', 'background-size': '100%' }"
></div>
<div class="card-list-text">
<p class="card-name">{{item.cardName}}</p>
<p class="card-title">{{item.cardTitle}}</p>
<div class="words-lists">
<div class="card-words">
<p class="card-word">{{item.cardWordOne}}</p>
</div>
<div v-if="item.cardWordTwo" class="card-words words-two">
<p class="card-word">{{item.cardWordTwo}}</p>
</div>
</div>
</div>
</div>
</li>
</div>
</div>
</v-reload>
</v-refresh>
</section>
</template>
<script>
import DropDownRefresh from '../common/DropDownRefresh'
import PullUpReload from '../common/PullUpReload'
export default {
data () {
return {
bankList: [
{
iconName: 'zhaoshang.png',
bankName: '招商银行'
},
{
iconName: 'minsheng.png',
bankName: '民生银行'
},
{
iconName: 'pingancar.png',
bankName: '平安联名'
},
{
iconName: 'xingye.png',
bankName: '兴业银行'
},
{
iconName: 'shanghai.png',
bankName: '上海银行'
},
{
iconName: 'jiaotong.png',
bankName: '交通银行'
},
{
iconName: 'guangda.png',
bankName: '光大银行'
},
{
iconName: 'more.png',
bankName: '全部银行'
}
],
hotLeft: {
bankName: '交通银行',
name: '交行Y-POWER黑卡',
desc: '额度100%取现',
imgName: 'jiaohangY-POWER.png'
},
centenrtOne: {
bankName: '招商银行',
name: '招行YOUNG卡',
desc: '生日月双倍积分',
imgName: 'zhaohangYOUNG.png'
},
centenrtTwo: {
bankName: '光大银行',
name: '光大淘票票公仔联名卡',
desc: '电影达人必备',
imgName: 'guangdalianming.png'
},
cardList: [
{
bankName: '平安联名',
imgName: 'pinganqiche.png',
cardName: '平安银行信用卡',
cardTitle: '平安银行汽车之家联名单币卡',
cardWordOne: '首年免年费',
cardWordTwo: '加油88折'
},
{
bankName: '上海银行',
imgName: 'shanghaitaobao.png',
cardName: '上海银行信用卡',
cardTitle: '淘宝金卡',
cardWordOne: '积分抵现',
cardWordTwo: '首刷有礼'
},
{
bankName: '华夏银行',
imgName: 'huaxiaiqiyi.png',
cardName: '华夏银行信用卡',
cardTitle: '华夏爱奇艺悦看卡',
cardWordOne: '送爱奇艺会员',
cardWordTwo: '商城8折'
},
{
bankName: '浦发银行',
imgName: 'pufajianyue.png',
cardName: '浦发银行信用卡',
cardTitle: '浦发银行简约白金卡',
cardWordOne: '团购立减',
cardWordTwo: '酒店优惠 免年费'
},
{
bankName: '中信银行',
imgName: 'zhongxinbaijin.png',
cardName: '中信银行信用卡',
cardTitle: '中信银行i白金信用卡',
cardWordOne: '首刷有礼',
cardWordTwo: '双倍积分'
}
],
// 上拉加载的设置
infiniteLoadData: {
initialShowNum: 3, // 初始显示多少条
everyLoadingNum: 3, // 每次加载的个数
pullUpState: 2, // 子组件的pullUpState状态
pullUpList: [], // 上拉加载更多数据的数组
showPullUpListLength: this.initialShowNum // 上拉加载后所展示的个数
}
}
},
mounted () {
this.getStartPullUpState()
this.getPullUpDefData()
},
methods: {
/**
* 获取上拉加载的初始数据
*/
getPullUpDefData () {
this.infiniteLoadData.pullUpList = []
if (this.cardList.length < this.infiniteLoadData.initialShowNum) {
for (let i = 0; i < this.cardList.length; i++) {
this.infiniteLoadData.pullUpList.push(this.cardList[i])
}
} else {
for (let i = 0; i < this.infiniteLoadData.initialShowNum; i++) {
this.infiniteLoadData.pullUpList.push(this.cardList[i])
}
}
this.getStartPullUpState()
},
/**
* 获取上拉加载的pullUpState状态
*/
getStartPullUpState () {
if (this.infiniteLoadData.pullUpList.length) {
if (this.cardList.length <= this.infiniteLoadData.initialShowNum) {
// 修改子组件的pullUpState状态
this.infiniteLoadData.pullUpState = 3
} else {
this.infiniteLoadData.pullUpState = 1
}
} else {
this.infiniteLoadData.pullUpState = 0
}
},
/**
* 上拉一次加载更多的数据
*/
getPullUpMoreData () {
this.showPullUpListLength = this.infiniteLoadData.pullUpList.length
if (this.infiniteLoadData.pullUpList.length + this.infiniteLoadData.everyLoadingNum > this.cardList.length) {
for (let i = 0; i < this.cardList.length - this.showPullUpListLength; i++) {
this.infiniteLoadData.pullUpList.push(this.cardList[i + this.showPullUpListLength])
}
} else {
for (let i = 0; i < this.infiniteLoadData.everyLoadingNum; i++) {
this.infiniteLoadData.pullUpList.push(this.cardList[i + this.showPullUpListLength])
}
}
if (this.cardList.length === this.infiniteLoadData.pullUpList.length) {
this.infiniteLoadData.pullUpState = 3
} else {
this.infiniteLoadData.pullUpState = 1
}
},
/**
* 下拉刷新
*/
onRefresh (done) {
// 如果下拉刷新和上拉加载同时使用,下拉时初始化上拉的数据
this.getStartPullUpState()
this.getPullUpDefData()
done() // call done
},
/**
* 上拉加载
*/
onInfiniteLoad (done) {
if (this.infiniteLoadData.pullUpState === 1) {
this.getPullUpMoreData()
}
done()
}
},
components: {
'v-refresh': DropDownRefresh,
'v-reload': PullUpReload
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
@import "../../assets/css/not2rem.css";
.container {
display: flex;
flex-direction: column;
width: 750px;
height: 1334px;
background-color: #f7f7f7;
}
.bank-box {
display: flex;
flex-wrap: wrap;
padding: 2px 7px 42px 7px;
background-color: #fff;
}
.bank-list {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100px;
height: 98px;
margin: 40px 42px 0 42px;
}
.bank-icon {
width: 56px;
height: 56px;
margin: 0 22px 18px;
}
.bank-name {
display: flex;
align-items: center;
width: 110px;
height: 24px;
line-height: 24px;
font-size: 24px;
color: #333;
}
.hot-box {
width: 100%;
height: 420px;
margin-top: 10px;
background: #fff;
}
.hot-header {
display: flex;
justify-content: space-between;
align-items: center;
width: 674px;
height: 80px;
margin: 0 30px 0 46px;
}
.hot-name {
display: flex;
align-items: center;
height: 28px;
font-size: 28px;
color: #333;
}
.more-text {
display: flex;
align-items: center;
font-size: 24px;
color: #999;
}
.more-box {
display: flex;
align-items: center;
}
.more-icon {
margin-left: 20px;
width: 11px;
height: 20px;
background: url("../../assets/images/bank/more.png") no-repeat;
background-size: 100%;
}
.hot-centenrt {
display: flex;
align-items: center;
width: 710px;
height: 320px;
margin: 0 20px 20px 20px;
}
.hot-left {
display: flex;
flex-direction: column;
width: 350px;
height: 320px;
background: #f7f7f7;
}
.left-name {
display: flex;
align-items: center;
width: 282px;
height: 24px;
margin: 50px 34px 0 34px;
font-size: 24px;
line-height: 24px;
color: #333;
}
.left-desc {
display: flex;
align-items: center;
width: 282px;
height: 20px;
margin: 12px 34px 0 34px;
font-size: 20px;
line-height: 20px;
color: #999;
}
.left-img {
width: 220px;
height: 142px;
margin-left: 34px;
margin-top: 34px;
}
.hot-right {
display: flex;
flex-direction: column;
width: 350px;
height: 320px;
margin-left: 10px;
}
.right-top {
display: flex;
flex-direction: row;
width: 100%;
height: 156px;
background: #f7f7f7;
}
.text-box {
display: flex;
flex-direction: column;
width: 180px;
height: 58px;
margin: 49px 20px 0 20px;
}
.right-name {
display: flex;
align-items: center;
width: 100%;
height: 24px;
line-height: 24px;
font-size: 24px;
color: #333;
}
.right-desc {
display: flex;
align-items: center;
margin-top: 10px;
width: 100%;
height: 24px;
line-height: 24px;
font-size: 24px;
color: #999;
}
.right-img {
width: 110px;
height: 70px;
margin-top: 43px;
}
.hot-right-bottom {
display: flex;
flex-wrap: wrap;
width: 100%;
height: 156px;
margin-top: 8px;
background: #f7f7f7;
}
.text-box2 {
display: flex;
flex-direction: column;
width: 180px;
margin: 31px 20px 0 20px;
}
.right-name2 {
display: flex;
align-items: center;
width: 100%;
height: 58px;
line-height: 30px;
font-size: 24px;
color: #333;
}
.right-desc2 {
display: flex;
align-items: center;
margin-top: 12px;
width: 100%;
height: 24px;
line-height: 24px;
font-size: 24px;
color: #999;
}
.card-state {
display: flex;
flex-direction: row;
width: 100%;
height: 128px;
margin-top: 10px;
background-color: #fff;
}
.card-progress {
display: flex;
align-items: center;
width: 327px;
height: 88px;
margin: 20px 0 20px 48px;
}
.progress-icon {
width: 48px;
height: 48px;
margin: 20px 0;
background: url("../../assets/images/bank/search.png") no-repeat;
background-size: 100%;
}
.activation-icon {
width: 48px;
height: 48px;
margin: 20px 0;
background: url("../../assets/images/bank/activation.png") no-repeat;
background-size: 100%;
}
.card-text {
display: flex;
flex-direction: column;
align-items: center;
width: 228px;
height: 66px;
margin: 11px 20px 11px 30px;
}
.card-name {
display: flex;
align-items: center;
width: 100%;
height: 28px;
line-height: 28px;
font-size: 28px;
color: #333;
}
.card-desc {
display: flex;
align-items: center;
width: 100%;
height: 22px;
line-height: 22px;
font-size: 22px;
margin-top: 16px;
color: #999;
}
.card-activation {
display: flex;
align-items: center;
width: 326px;
height: 88px;
margin: 20px 0 20px 48px;
}
.card-order {
width: 100%;
height: auto;
margin-top: 10px;
background-color: #fff;
}
.border-bottom {
width: 100%;
height: 80px;
}
.card-list {
width: 100%;
height: 228px;
list-style-type: none;
}
.card-content {
display: flex;
flex-direction: row;
width: 700px;
height: 228px;
margin-left: 50px;
}
.card-img {
width: 186px;
height: 120px;
margin: 54px 0 54px 20px;
}
.card-list-text {
display: flex;
flex-direction: column;
width: 386px;
height: 124px;
margin: 52px 34px 52px 74px;
}
.card-name {
width: 100%;
height: 28px;
line-height: 28px;
font-size: 28px;
color: #333;
}
.card-title {
width: 100%;
height: 24px;
margin-top: 20px;
line-height: 24px;
font-size: 24px;
color: #666;
}
.words-lists {
display: flex;
flex-direction: row;
}
.card-words {
height: 36px;
margin-top: 16px;
border-radius: 20px;
background-color: #e8ca88;
}
.card-word {
height: 20px;
padding: 8px 18px;
line-height: 20px;
font-size: 20px;
color: #4b4b4b;
}
.words-two {
margin-left: 20px;
}
</style>
这里只是展示了一下效果,使用的全是静态数据,如果要用接口数据的话,this.getPullUpMoreData()
方法直接换成接口数据的方法,并将判断的逻辑移到接口方法里,当然根据实际情况,分页呀啥的做做适当的修改。
vue移动端下拉刷新、上拉加载的更多相关文章
- Android 下拉刷新上啦加载SmartRefreshLayout + RecyclerView
在弄android刷新的时候,可算是耗费了一番功夫,最后发觉有现成的控件,并且非常好用,这里记录一下. 原文是 https://blog.csdn.net/huangxin112/article/de ...
- SwipeRefreshLayout实现下拉刷新上滑加载
1. 效果图 2.RefreshLayout.java package myapplication.com.myapplication; import android.content.Context; ...
- 移动端下拉刷新上拉加载-mescroll.js插件
最近无意间看到有这么一个上拉刷新下拉加载的插件 -- mescroll.js,个人感觉挺好用的,官网地址是:http://www.mescroll.com 然后我就看了一下文档,简单的写了一个小dem ...
- 基于SwiperJs的H5/移动端下拉刷新上拉加载更多的效果
最早时,公司的H5项目中曾用过点击一个"加载更多"的DOM元素来实现分页的功能,后来又用过网上有人写的一个上拉加载更多的插件,那个插件是页面将要滚动到底部时就自动请求数据并插入到页 ...
- 基于SwiperJs的H5/移动端下拉刷新上拉加载更多
最早时,公司的H5项目中曾用过点击一个"加载更多"的DOM元素来实现分页的功能,后来又用过网上有人写的一个上拉加载更多的插件,那个插件是页面将要滚动到底部时就自动请求数据并插入到页 ...
- vue mint-ui 框架下拉刷新上拉加载组件的使用
安装 npm i mint-ui -S 然后在main.js中引入 import MintUI from 'mint-ui' import 'mint-ui/lib/style.css' Vue.us ...
- mui下拉刷新上拉加载
新外卖商家端主页订单大厅页面 使用mui双webview,实现下拉刷新上拉加载 主页面: order_index.html <!doctype html> <html> < ...
- vue10行代码实现上拉翻页加载更多数据,纯手写js实现下拉刷新上拉翻页不引用任何第三方插件
vue10行代码实现上拉翻页加载更多数据,纯手写js实现下拉刷新上拉翻页不引用任何第三方插件/库 一提到移动端的下拉刷新上拉翻页,你可能就会想到iScroll插件,没错iScroll是一个高性能,资源 ...
- MaterialRefreshLayout+ListView 下拉刷新 上拉加载
效果图是这样的,有入侵式的,非入侵式的,带波浪效果的......就那几个属性,都给出来了,自己去试就行. 下拉刷新 上拉加载 关于下拉刷新-上拉加载的效果,有许许多多的实现方式,百度了一下竟然有几十种 ...
- 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载
title: 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载 tags: -RecyclerView,下拉刷新,上拉加载更多 grammar_cjkRuby: true - ...
随机推荐
- 将一条路由约束到一组指定的值 约束路由 URL路由
- 使用Razor 使用Razor表达式处理命名空间 精通ASP-NET-MVC-5-弗瑞曼
- SpringMVC 中的异常处理
目录 1.搭建编码分析 2.编写异常类 3.编写自定义异常处理器 4.在springmvc.xml中配置异常处理器 5.编写Error.jsp.index.jsp页面 6.编写collector代码模 ...
- CentOS7安装docker以及错误解决
今天在公司电脑上安装docker出现了一些问题,原先是直接用yum安装docker,一次就成功了,由于公司的网络问题导致docker安装完出现了一些问题,客户端启动了,服务端一直启动不了:Job fo ...
- .net 项目更改默认命名空间
这个项目是我去年毕业设计做的项目,项目创建的时候由于手抖把Landlordtenant写成了 LandloRdtenant(R大写了),当时不知道如何改回来又担心改完之后报错也就没管了. 今天尝试使用 ...
- [白话解析] Flink的Watermark机制
[白话解析] Flink的Watermark机制 0x00 摘要 对于Flink来说,Watermark是个很难绕过去的概念.本文将从整体的思路上来说,运用感性直觉的思考来帮大家梳理Watermark ...
- Java 接口及接口回调_Chris
题目: 利用接口和接口回调,实现简单工厂模式,当输入不同的字符,代表相应图形时,利用工厂类获得图形对象,再计算以该图形为底的柱体体积. 代码: 1.Test.java /** * 测试类,包含一个主方 ...
- vagrant相关
无法挂载共享目录,报错如下 Vagrant was unable to mount VirtualBox shared folders. This is usually because the fil ...
- WeChall_Training: Get Sourced (Training)
The solution is hidden in this page Use View Sourcecode to get it 解题: 网页源码,最后一行 <!-- You are look ...
- ELK:收集k8s容器日志最佳实践
简介 关于日志收集这个主题,这已经是第三篇了,为什么一再研究这个课题,因为这个课题实在太重要,而当今优秀的开源解决方案还不是很明朗: 就docker微服务化而言,研发有需求标准输出,也有需求文件输出, ...