使用Mint-UI的Loadmore实现上拉加载更多和下拉刷新
最近用 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; width: calc(100% - 0.6rem); margin: 0.4rem auto; border: 0.02rem solid #666; border-radius: 0.16rem; } .order-intr img { width: 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; width: 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; width: calc(100% - 0.6rem); margin: 0.4rem auto; border: 0.02rem solid #666; border-radius: 0.16rem; } .order-intr img { width: 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; width: 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();