最近用 mint-ui 实现了上拉加载更多和下拉刷新,正好今天有空就把实现过程都给记录下来,下面我准备来个小白教程。
我这个利用vue单页和普通页面方式展示。
1、首先用脚手架 vue-cli 搭建环境(这里我百度找了一个算看到舒服的教程,仅供参考)
2、Mint-UI (这里官网快速上手,可以根据里面的教程快速的添加 mint-ui 到项目中去,图片和代码看都有,推荐自己看图手敲代码)
.babelrc文件

{ "presets": [ ["env", { "modules": false, "targets": { "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] } }], "stage-2" ], "plugins": ["transform-vue-jsx", "transform-runtime", ["component", [ { "libraryName": "mint-ui", "style": true } ] ] ] }
main.js

// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import { Loadmore } from 'mint-ui' Vue.component(Loadmore.name, Loadmore); Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', router, components: { App }, template: '<App/>' })
HelloWorld.vue(页面就直接上代码截图太长了,里面用的图片[chicken-wings.jpg, swine-fever.jpg]我是百度的需要图片的自己找, 另外这两张图都是直接放在 static 文件夹)

<template>
<div class="hello">
<mt-loadmore
:top-method="loadTop"
:bottom-method="loadBottom"
:bottom-all-loaded="allLoaded"
@top-status-change="handleTopChange"
@bottom-status-change="handleBottomChange"
:autoFill="false"
ref="loadmore"
>
<ul>
<li class="order-intr clearfix" v-for="(item, index) in list" :key="index">
<img class="fl" :src="item.cover">
<div class="title fl">
<h3>{{item.title}}</h3>
<p>数量:{{item.num}}</p>
</div>
<b class="fr price">¥{{item.price}}</b>
</li>
</ul>
<div slot="top" class="mint-loadmore-top">
<span v-show="topStatus !== 'loading'" :class="{ 'rotate': topStatus === 'drop' }">松手释放↓</span>
<span v-show="topStatus === 'loading'">加载中</span>
</div>
<div slot="bottom" class="mint-loadmore-bottom">
<span
v-show="bottomStatus !== 'loading'"
:class="{ 'rotate': bottomStatus === 'drop' }"
>松手释放↑</span>
<span v-show="bottomStatus === 'loading'">加载中</span>
</div>
<p v-if="allLoaded" class="to-the-bottom">我是有底线的</p>
</mt-loadmore>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
topStatus: "",
bottomStatus: "",
allLoaded: false,
list: [],
mockArr: [],
number: 0
};
},
created() {
// ajax 模拟初始加载, 使用定时器默认ajax加载
let timer = setTimeout(_ => {
clearTimeout(timer);
this.loadData('refresh');
}, 200);
},
methods: {
loadData(p_status) {
// 第一次加载或者下拉刷新最新数据
if (p_status === "refresh") {
this.mockArr = [];
}
for (let i = 0; i < 5; ) {
let obj = {
cover: "./static/chicken-wings.jpg",
title: "奥尔良鸡中翅饭",
num: 1,
price: 14.88
};
obj["id"] = this.mockArr.length + 1;
if (i % 2) {
obj["cover"] = "./static/swine-fever.jpg";
obj["title"] = "猪扒饭";
obj["num"] += 1;
obj["price"] -= 1;
}
i++;
this.mockArr.push(obj);
}
this.list = this.mockArr;
},
handleTopChange(p_status) {
this.topStatus = p_status;
},
handleBottomChange(p_status) {
this.bottomStatus = p_status;
},
loadBottom() {
// 一次下拉加载5条更多数据,使用定时器默认ajax加载
this.loadData()
this.number++;
// allLoaded 设置为 true 时,表示数据已全部获取完毕不需要再出现上拉加载更多
if (this.number === 3) {
this.allLoaded = true;
}
this.$refs.loadmore.onBottomLoaded();
},
loadTop() {
// 默认下拉刷新最新数据
this.loadData("refresh");
this.number = 0;
this.allLoaded = false;
this.$refs.loadmore.onTopLoaded();
}
}
};
</script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* 这里直接设置 1rem = 50px begin */
html {
font-size: 50px;
}
/* 这里直接设置 1rem = 50px end */
html,
body {
font-family: "微软雅黑";
color: #333;
background: #fff;
}
ul,
li {
list-style: none;
}
/* 给要上拉的容器设置 begin */
.hello {
height: 100vh;
overflow-y: auto;
}
/* 给要上拉的容器设置 end */
.fl {
float: left;
}
.fr {
float: right;
}
.clearfix::before,
.clearfix::after {
content: "";
display: block;
overflow: hidden;
clear: both;
visibility: hidden;
}
li {
background: #fff;
}
.order-intr {
position: relative;
padding: 0.3rem 0.4rem;
calc(100% - 0.6rem);
margin: 0.4rem auto;
border: 0.02rem solid #666;
border-radius: 0.16rem;
}
.order-intr img {
3rem;
height: 2.4rem;
}
.title {
margin-left: 0.24rem;
text-align: left;
}
.title h3 {
font-size: 0.4rem;
}
.title p {
font-size: 0.3rem;
}
.price {
position: absolute;
right: 0.3rem;
bottom: 0.3rem;
font-size: 0.5rem;
color: #fe696b;
}
.mint-loadmore-top,
.mint-loadmore-bottom {
font-size: 0.28rem;
}
/* 我是有底线的 begin */
.to-the-bottom {
position: relative;
color: #999999;
font-size: 0.32rem;
text-align: center;
padding: 0.1rem 0;
background: #f1eded;
}
.to-the-bottom::before,
.to-the-bottom::after {
position: absolute;
top: 50%;
height: 0.02rem;
25%;
margin-top: -0.01rem;
background: #999;
content: "";
}
.to-the-bottom::before {
left: 10%;
}
.to-the-bottom::after {
right: 10%;
}
/* 我是有底线的 end */
</style>
3、最后来一个单页代码(图片自己找,图片路径也可以自己改)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>loadmore</title>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/mint-ui/lib/style.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* 这里直接设置 1rem = 50px begin */
html {
font-size: 50px;
}
/* 这里直接设置 1rem = 50px end */
html,
body {
font-family: "微软雅黑";
color: #333;
background: #fff;
}
ul,
li {
list-style: none;
}
/* 给要上拉的容器设置 begin */
.data-list {
height: 100vh;
overflow-y: auto;
}
/* 给要上拉的容器设置 end */
.fl {
float: left;
}
.fr {
float: right;
}
.clearfix::before,
.clearfix::after {
content: "";
display: block;
overflow: hidden;
clear: both;
visibility: hidden;
}
li {
background: #fff;
}
.order-intr {
position: relative;
padding: 0.3rem 0.4rem;
calc(100% - 0.6rem);
margin: 0.4rem auto;
border: 0.02rem solid #666;
border-radius: 0.16rem;
}
.order-intr img {
3rem;
height: 2.4rem;
}
.title {
margin-left: 0.24rem;
text-align: left;
}
.title h3 {
font-size: 0.4rem;
}
.title p {
font-size: 0.3rem;
}
.price {
position: absolute;
right: 0.3rem;
bottom: 0.3rem;
font-size: 0.5rem;
color: #fe696b;
}
.mint-loadmore-top,
.mint-loadmore-bottom {
font-size: 0.28rem;
}
/* 我是有底线的 begin */
.to-the-bottom {
position: relative;
color: #999999;
font-size: 0.32rem;
text-align: center;
padding: 0.1rem 0;
background: #f1eded;
}
.to-the-bottom::before,
.to-the-bottom::after {
position: absolute;
top: 50%;
height: 0.02rem;
25%;
margin-top: -0.01rem;
background: #999;
content: "";
}
.to-the-bottom::before {
left: 10%;
}
.to-the-bottom::after {
right: 10%;
}
/* 我是有底线的 end */
</style>
</head>
<body>
<div id="app">
<div class="data-list">
<mt-loadmore :top-method="loadTop" :bottom-method="loadBottom" :bottom-all-loaded="allLoaded" @top-status-change="handleTopChange"
@bottom-status-change="handleBottomChange" :autoFill="false" ref="loadmore">
<ul>
<li class="order-intr clearfix" v-for="(item, index) in list" :key="index">
<img class="fl" :src="item.cover">
<div class="title fl">
<h3>{{item.title}}</h3>
<p>数量:{{item.num}}</p>
</div>
<b class="fr price">¥{{item.price}}</b>
</li>
</ul>
<div slot="top" class="mint-loadmore-top">
<span v-show="topStatus !== 'loading'" :class="{ 'rotate': topStatus === 'drop' }">松手释放↓</span>
<span v-show="topStatus === 'loading'">加载中</span>
</div>
<div slot="bottom" class="mint-loadmore-bottom">
<span v-show="bottomStatus !== 'loading'" :class="{ 'rotate': bottomStatus === 'drop' }">松手释放↑</span>
<span v-show="bottomStatus === 'loading'">加载中</span>
</div>
<p v-if="allLoaded" class="to-the-bottom">我是有底线的</p>
</mt-loadmore>
</div>
</div>
<!-- 先引入 Vue -->
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<!-- 引入组件库 -->
<script src="https://unpkg.com/mint-ui/lib/index.js"></script>
<script>
let vm = new Vue({
el: '#app',
data() {
return {
topStatus: "",
bottomStatus: "",
allLoaded: false,
list: [],
mockArr: [],
number: 0
};
},
created() {
// ajax 模拟初始加载, 使用定时器默认ajax加载
let timer = setTimeout(_ => {
clearTimeout(timer);
this.loadData('refresh');
}, 200);
},
methods: {
loadData(p_status) {
// 第一次加载或者下拉刷新最新数据
if (p_status === "refresh") {
this.mockArr = [];
}
for (let i = 0; i < 5;) {
let obj = {
cover: "./static/chicken-wings.jpg",
title: "奥尔良鸡中翅饭",
num: 1,
price: 14.88
};
obj["id"] = this.mockArr.length + 1;
if (i % 2) {
obj["cover"] = "./static/swine-fever.jpg";
obj["title"] = "猪扒饭";
obj["num"] += 1;
obj["price"] -= 1;
}
i++;
this.mockArr.push(obj);
}
this.list = this.mockArr;
},
handleTopChange(p_status) {
this.topStatus = p_status;
},
handleBottomChange(p_status) {
this.bottomStatus = p_status;
},
loadBottom() {
// 一次下拉加载5条更多数据,使用定时器默认ajax加载
this.loadData()
this.number++;
// allLoaded 设置为 true 时,表示数据已全部获取完毕不需要再出现上拉加载更多
if (this.number === 3) {
this.allLoaded = true;
}
this.$refs.loadmore.onBottomLoaded();
},
loadTop() {
// 默认下拉刷新最新数据
this.loadData("refresh");
this.number = 0;
this.allLoaded = false;
this.$refs.loadmore.onTopLoaded();
}
}
})
</script>
</body>
</html>
这是 demo 百度云盘链接
链接: https://pan.baidu.com/s/1NSOQA8gU0rg20QqL2iPW8g
提取码: mhpp

---------- 2019.08.14 补充 ----------
如果出现下面这个报错
Uncaught TypeError: Cannot read property 'onTopLoaded' of undefined
下面是官方对于refs的说明:
如何解决上面的报错,我这里推荐使用先判断在执行
this.$refs.loadmore && this.$refs.loadmore.onTopLoaded();
