第一种:
触底加载和图片懒加载的思路一样,屏幕的高度加上滚动的高度快要大于最后一个元素距离顶部的高度的时候就开始加载数据;
(1)clientHeight:屏幕的高度;
(2)scrollTop:滚动的高度;
(3)offsetTop:最后一个元素距离顶部的高度;
if ((clientHeight + scrollTop + 快要到底的高度) >= offsetTop) 获取数据;
以下代码实例:
html代码:
<el-tooltip content="打开搜索框" placement="bottom" effect="light">
<i class="el-icon-search" @click.stop="openSearch"></i>
</el-tooltip>
<!-- 搜索弹框 -->
<div class="searchMask" v-if="searchTemplateShow" @click.stop>
<div class="searchBox" @click.stop>
<div class="searchHeader">
<i class="el-icon-close" @click.stop="searchTemplateShow = false"></i>
<el-input
v-model="searchInfo.title"
placeholder="搜索模版"
clearable
prefix-icon="el-icon-search"
@keyup.enter.native="search"
@keyup.ctrl.enter.native="openNewLink"
style="width: 100%;"
class="input-with-select">
<el-select v-model="templateType" slot="prepend" placeholder="请选择模版类型" @change="search">
<el-option v-for="item in templateTypeData" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-input>
</div>
<div class="emptySearch" v-if="wtf">
<img src="@/assets/img/emptySearch.png" />
<div>搜索无结果</div>
</div>
<div class="searchCenter" v-else>
<div class="searchContent" v-loading="templateLoading" :style="`height:${templateLoading ? '452px' : 'auto'};`">
<div class="searchContentTitle">选择模版</div>
<div class="searchContentBox" ref="searchContentBox" @scroll="scrollBottom">
<div class="searchItem" v-for="(item, index) in templateData" :key="item.id" @click.stop="createDoc(item.id)" :ref="`searchItem${index}`">
<div class="searchItemIcon">
<img src="@/assets/img/templateSearchIcon.png" />
</div>
<div class="searchItemContent">
<div class="searchItemTitle one" v-if="item.title">{{ item.title }}</div>
<div class="searchItemDesc" v-if="item.desc">{{ item.desc }}</div>
</div>
</div>
</div>
</div>
<div class="searchFooter">
<span>{{ total || 0 }}</span>
<span>结果</span>
<span>支持ENTER搜索、CTRL+ENTER新窗口打开</span>
</div>
</div>
</div>
</div>
js变量代码:
// 搜索模版弹框
searchTemplateShow: false,
// 模版类型 1:热门 2:我的
templateType: 1,
templateTypeData: [{
label: "热门",
value: 1
},{
label: "我的",
value: 2
}],
// 搜索条件对象
searchInfo: {
title: ""
},
// 搜索模版loading
templateLoading: false,
// 搜索模版数据
templateData: [],
page: 1,
total: null,
mask: true,
wtf: false
js方法代码:
/**
* 搜索弹框显示
*/
openSearch() {
if (!this.userInfo.type) {
this.showLogin = true;
return false;
};
Object.keys(this.searchInfo).forEach(key => {
this.searchInfo[key] = "";
});
this.searchTemplateShow = true;
this.search();
},
/**
* 搜索
*/
search() {
this.templateLoading = true;
this.page = 1;
this.templateData = [];
this.mask = true;
this.wtf = false;
this.getTemplateData();
},
/**
* 滚动到下面
*/
scrollBottom() {
let clientHeight = this.$refs.searchContentBox.clientHeight;
let scrollTop = this.$refs.searchContentBox.scrollTop;
let offsetTop = this.$refs[`searchItem${this.templateData.length - 1}`][0].offsetTop;
if (((clientHeight + scrollTop + 300) >= offsetTop) && this.mask) this.getTemplateData();
},
/**
* 获取模版数据
*/
getTemplateData: debounce(async function () {
this.templateLoading = true;
let params = {
...this.searchInfo,
page: this.page,
size: 10,
is_not_template: 1
}
let res = await document.getTemplateData(params, this.templateType);
if (res.code == 200) {
this.templateLoading = false;
res.data.data.forEach(item => {
this.templateData.push(item);
});
this.total = res.data.total;
this.wtf = this.templateData.length == 0 ? true : false;
this.page == res.data.last_page ? this.mask = false : this.page++;
};
}, 300),
/**
* 打开新链接搜索
*/
openNewLink() {
window.open(window.location.href);
},
/**
* 创建文档
*/
createDoc(id) {
if (!this.userInfo.type) {
this.showLogin = true;
return false;
};
this.$parent.createDoc(id);
this.searchTemplateShow = false;
}
css代码:
.el-icon-search, .el-icon-plus {
width: 24px;
display: flex;
align-items: center;
justify-content: center;
&:hover {
background-color: rgba(0,0,0,.04);
border-radius: 2px;
cursor: pointer;
}
}
.searchMask {
width: 100vw;
height: 100vh;
background-color: rgba(30, 30, 30, .8);
position: fixed;
bottom: 0;
left: 0;
z-index: 11;
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
.searchBox {
width: 600px;
height: auto;
background: #FFFFFF;
box-shadow: 0px 6px 28px -3px rgba(165,165,165,0.36);
border-radius: 10px;
.searchHeader, .searchContentBox, .emptySearch, .searchContent, .searchFooter {
width: 100%;
box-sizing: border-box;
}
.searchHeader {
height: 117px;
padding: 60px 28px 13px 28px;
border-bottom: 1px solid #F5F5F5;
position: relative;
.el-icon-close {
position: absolute;
top: 24px;
right: 23px;
font-size: 18px;
color: #111111;
cursor: pointer;
}
/deep/ .el-select .el-input {
width: 95px;
}
/deep/ .input-with-select .el-input-group__prepend {
background-color: #fff;
}
}
.searchCenter {
height: auto;
.searchContent {
height: auto;
.searchContentTitle {
width: 100%;
box-sizing: border-box;
padding: 20px 28px 10px 28px;
font-weight: 400;
font-size: 15px;
color: #999999;
}
.searchContentBox {
width: 100%;
height: auto;
max-height: 400px;
overflow-y: auto;
.searchItem {
width: 100%;
height: auto;
box-sizing: border-box;
padding: 12px 28px;
display: flex;
cursor: pointer;
&:hover {
background-color: rgba(51, 77, 102, 0.06);
}
.searchItemIcon {
width: 16px;
height: 16px;
margin: 2px 12px 0 0;
img {
width: 100%;
height: 100%;
}
}
.searchItemContent {
max-width: 508px;
.searchHeader, .searchContent {
max-width: 508px;
font-weight: 400;
}
.searchItemTitle {
font-size: 15px;
color: #333333;
line-height: 21px;
}
.searchItemDesc {
font-size: 13px;
color: #999999;
line-height: 18px;
}
}
}
}
}
.searchFooter {
height: 40px;
padding: 10px 28px;
box-shadow: 0 6px 28px -3px rgba(165,165,165,0.36);
font-weight: 400;
font-size: 14px;
color: #999999;
line-height: 20px;
& > span:first-of-type {
color: rgba(0, 0, 0, 0.64);
margin-right: 5px;
}
& > span:last-of-type {
color: rgba(0, 0, 0, 0.64);
margin-left: 16px;
}
}
}
.emptySearch {
height: 295px;
font-size: 14px;
color: rgba(0, 0, 0, 0.4);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
img {
width: 128px;
height: 128px;
margin-bottom: 20px;
}
}
}
}
第二种:
使用element ui的v-infinite-scroll属性添加触底加载事件:
v-infinite-scroll=触底加载事件
例:
<template>
<ul class="infinite-list" v-infinite-scroll="load" style="overflow:auto">
<li v-for="i in count" class="infinite-list-item">{{ i }}</li>
</ul>
</template>
<script>
export default {
data () {
return {
count: 0
}
},
methods: {
load () {
this.count += 2
}
}
}
</script>