本文介绍了vue mint-ui源码解析之loadmore组件,分享给大家,具体如下:
接入
官方接入文档mint-ui loadmore文档
接入使用Example
html
<div id="app">
<mt-loadmore :top-method="loadTop" :bottom-method="loadBottom" :bottom-all-loaded="allLoaded" :max-distance="150"
@top-status-change="handleTopChange" ref="loadmore">
<div slot="top" class="mint-loadmore-top">
<span v-show="topStatus === 'pull'" :class="{ 'rotate': topStatus === 'drop' }">↓</span>
<span v-show="topStatus === 'loading'">Loading...</span>
<span v-show="topStatus === 'drop'">释放更新</span>
</div>
<ul class="scroll-wrapper">
<li v-for="item in list" @click="itemClick(item)">{{ item }}</li>
</ul>
</mt-loadmore>
</div>
css
<link rel="stylesheet" href="https://unpkg.com/mint-ui/lib/style.css" rel="external nofollow" >
*{
margin: 0;
padding: 0;
}
html, body{
height: 100%;
}
#app{
height: 100%;
overflow: scroll;
}
.scroll-wrapper{
margin: 0;
padding: 0;
list-style: none;
}
.scroll-wrapper li{
line-height: 120px;
font-size: 60px;
text-align: center;
}
js
<!-- 先引入 Vue --> <script src="/UploadFiles/2021-04-02/vue.js">实现原理解析
布局原理
- loadmore组件内部由三个slot组成,分别为name=top,name=bottom,default;
- top用于展示下拉刷新不同状态展示的内容,初始设置margin-top为-top的高度来将自己隐藏
- bottom同top,用于展示上拉加载更多不同状态展示的内容
- default填充滚动详细内容
实现原理
- 主要是通过js的touch事件的监听来实现
- 在touchmove事件,如果是向下滑动并且滚动的dom的scrollTop为0,那么整个组件向下偏移(滑动的距离/比值)展示出top solt的内容
- 在touchmove时间,如果是向上滑动并且滑动到了底部,再继续滑动整个组件向上偏移(滑动的距离/比值)展示出bottom solt的内容
源码解析
组件的template html
<div class="mint-loadmore">
<div class="mint-loadmore-content" :class="{ 'is-dropped': topDropped || bottomDropped}" :style="{ 'transform': 'translate3d(0, ' + translate + 'px, 0)' }">
<slot name="top">
<div class="mint-loadmore-top" v-if="topMethod">
<spinner v-if="topStatus === 'loading'" class="mint-loadmore-spinner" :size="20" type="fading-circle"></spinner>
<span class="mint-loadmore-text">{{ topText }}</span>
</div>
</slot>
<slot></slot>
<slot name="bottom">
<div class="mint-loadmore-bottom" v-if="bottomMethod">
<spinner v-if="bottomStatus === 'loading'" class="mint-loadmore-spinner" :size="20" type="fading-circle"></spinner>
<span class="mint-loadmore-text">{{ bottomText }}</span>
</div>
</slot>
</div>
</div>
关于 上面的spinner标签,是一个组件,这里不做详细介绍。top solt和bottom slot中的内容是展示的内容,可以通过外部自定义的方式传入。
其实它的实现有一个很严重的弊端,就是写死了top solt和bottom slot的高度为50px,而且js中的处理也是使用50px进行的逻辑处理。所以并满足我们开发中自定义top slot 和bottom slot的需求。
js核心解析
- props解析:关于props的解析,可以参考mint-ui的官方文档
- data解析
data() {
return {
translate: 0, // 此变量决定当前组件上下移动,
scrollEventTarget: null, // 滚动的dom节点
containerFilled: false, // 当前滚动的内容是否填充完整,不完成会调用 loadmore的回调函数
topText: '', // 下拉刷新,显示的文本
topDropped: false, // 记录当前drop状态,用给组件dom添加is-dropped class(添加回到原点的动画)
bottomText: '', // 上拉加载更多 显示的文本
bottomDropped: false, // 同topDropped
bottomReached: false, // 当前滚动是否滚动到了底部
direction: '', // touch-move过程中, 当前滑动的方向
startY: 0, // touch-start 起始的y的坐标值
startScrollTop: 0, // touch-start 起始的滚动dom的 scrollTop
currentY: 0, // touch-move 过程中的 y的坐标
topStatus: '', // 下拉刷新的状态: pull(下拉) drop(释放) loading(正在加载数据)
bottomStatus: '' // 上拉加载更多的状态: 状态同上
};
}
上面的关于每个data数据的具体作用通过注释做了详细说明。
watch解析
watch: {
topStatus(val) {
this.$emit('top-status-change', val);
switch (val) {
case 'pull':
this.topText = this.topPullText;
break;
case 'drop':
this.topText = this.topDropText;
break;
case 'loading':
this.topText = this.topLoadingText;
break;
}
},
bottomStatus(val) {
this.$emit('bottom-status-change', val);
switch (val) {
case 'pull':
this.bottomText = this.bottomPullText;
break;
case 'drop':
this.bottomText = this.bottomDropText;
break;
case 'loading':
this.bottomText = this.bottomLoadingText;
break;
}
}
}
上面是组件通过watch监听的两个变量,后面我们能看到他们的改变是在touchmove事件中进行处理改变的。它的作用是通过它的变化来改变top slot和bottom slot的文本内容;
同时发出status-change事件给外部使用,因为可能外部自定义top slot 和bottom slot的内容,通过此事件来通知外部当前状态以便外部进行处理。
核心函数的解析
这里就不将所有的method列出,下面就根据处理的所以来解析对应的method函数。
首先,入口是在组件mounted生命周期的钩子回调中执行init函数
mounted() {
this.init();// 当前 vue component挂载完成之后, 执行init()函数
}
init函数:
init() {
this.topStatus = 'pull';
this.bottomStatus = 'pull';
this.topText = this.topPullText;
this.scrollEventTarget = this.getScrollEventTarget(this.$el); // 获取滚动的dom节点
if (typeof this.bottomMethod === 'function') {
this.fillContainer(); // 判断当前滚动内容是否填满,没有执行外部传入的loadmore回调函数加载数据
this.bindTouchEvents(); // 为当前组件dom注册touch事件
}
if (typeof this.topMethod === 'function') {
this.bindTouchEvents();
}
},
fillContainer() {
if (this.autoFill) {
this.$nextTick(() => {
if (this.scrollEventTarget === window) {
this.containerFilled = this.$el.getBoundingClientRect().bottom >=
document.documentElement.getBoundingClientRect().bottom;
} else {
this.containerFilled = this.$el.getBoundingClientRect().bottom >=
this.scrollEventTarget.getBoundingClientRect().bottom;
}
if (!this.containerFilled) { // 如果没有填满内容, 执行loadmore的操作
this.bottomStatus = 'loading';
this.bottomMethod();// 调用外部的loadmore函数,加载更多数据
}
});
}
}
init函数主要是初始化状态和事件的一些操作,下面着重分析touch事件的回调函数的处理。
首先touchstart事件回调处理函数
handleTouchStart(event) {
this.startY = event.touches[0].clientY; // 手指按下的位置, 用于下面move事件计算手指移动的距离
this.startScrollTop = this.getScrollTop(this.scrollEventTarget); // 起始scroll dom的 scrollTop(滚动的距离)
//下面重置状态变量
this.bottomReached = false;
if (this.topStatus !== 'loading') {
this.topStatus = 'pull';
this.topDropped = false;
}
if (this.bottomStatus !== 'loading') {
this.bottomStatus = 'pull';
this.bottomDropped = false;
}
}
主要是记录初始位置和重置状态变量。
下面继续touchmove的回调处理函数
handleTouchMove(event) {
//确保当前touch节点的y的位置,在当前loadmore组件的内部
if (this.startY < this.$el.getBoundingClientRect().top && this.startY > this.$el.getBoundingClientRect().bottom) {
return;
}
this.currentY = event.touches[0].clientY;
let distance = (this.currentY - this.startY) / this.distanceIndex;
this.direction = distance > 0 "htmlcode">
checkBottomReached() {
if (this.scrollEventTarget === window) {
return document.body.scrollTop + document.documentElement.clientHeight >= document.body.scrollHeight;
} else {
return this.$el.getBoundingClientRect().bottom <= this.scrollEventTarget.getBoundingClientRect().bottom + 1;
}
}
经过我的测试,上面的代码是有问题:
当scrollEventTarget是window的条件下,上面的判断是不对的。因为document.body.scrollTop总是比正常值小1,所以用于无法满足到达底部的条件;
当scrollEventTarget不是window的条件下,上面的判断条件也不需要在this.scrollEventTarget.getBoundingClientRect().bottom后面加1,但是加1也不会有太大视觉上的影响。
最后来看下moveend事件回调的处理函数
handleTouchEnd() {
if (this.direction === 'down' && this.getScrollTop(this.scrollEventTarget) === 0 && this.translate > 0) {
this.topDropped = true; // 为当前组件添加 is-dropped class(也就是添加动画处理)
if (this.topStatus === 'drop') { // 到达了loading的状态
this.translate = '50'; // top slot的高度
this.topStatus = 'loading';
this.topMethod(); // 执行回调函数
} else { // 没有到达,回调原点
this.translate = '0';
this.topStatus = 'pull';
}
}
// 处理逻辑同上
if (this.direction === 'up' && this.bottomReached && this.translate < 0) {
this.bottomDropped = true;
this.bottomReached = false;
if (this.bottomStatus === 'drop') {
this.translate = '-50';
this.bottomStatus = 'loading';
this.bottomMethod();
} else {
this.translate = '0';
this.bottomStatus = 'pull';
}
}
this.$emit('translate-change', this.translate);
this.direction = '';
}
}
总结
- 下拉刷新和上拉加载更多的实现原理可以借鉴
- getScrollEventTarget()获取滚动对象,getScrollTop()获取滚动距离,checkBottomReached()判断是否滚动到底部;这三种方式可以借鉴
- 缺点: 写死了top slot 和 bottom slot的高度,太不灵活;这个地方可以优化
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?
更新日志
- 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]