vue原生div做触底加载

第一种:

触底加载和图片懒加载的思路一样,屏幕的高度加上滚动的高度快要大于最后一个元素距离顶部的高度的时候就开始加载数据;

(1)clientHeight:屏幕的高度;

(2)scrollTop:滚动的高度;

(3)offsetTop:最后一个元素距离顶部的高度;

if ((clientHeight + scrollTop + 快要到底的高度) >= offsetTop) 获取数据;

以下代码实例:

html代码:

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变量代码:

javascript 复制代码
// 搜索模版弹框
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方法代码:

javascript 复制代码
/**
 * 搜索弹框显示
 */
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代码:

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=触底加载事件

例:

javascript 复制代码
<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>
相关推荐
真滴book理喻1 小时前
Vue(四)
前端·javascript·vue.js
程序员_三木2 小时前
Three.js入门-Raycaster鼠标拾取详解与应用
开发语言·javascript·计算机外设·webgl·three.js
不是鱼3 小时前
构建React基础及理解与Vue的区别
前端·vue.js·react.js
开心工作室_kaic3 小时前
springboot476基于vue篮球联盟管理系统(论文+源码)_kaic
前端·javascript·vue.js
川石教育3 小时前
Vue前端开发-缓存优化
前端·javascript·vue.js·缓存·前端框架·vue·数据缓存
搏博3 小时前
使用Vue创建前后端分离项目的过程(前端部分)
前端·javascript·vue.js
isSamle3 小时前
使用Vue+Django开发的旅游路书应用
前端·vue.js·django
温轻舟3 小时前
前端开发 之 12个鼠标交互特效上【附完整源码】
开发语言·前端·javascript·css·html·交互·温轻舟
web135085886353 小时前
2024-05-18 前端模块化开发——ESModule模块化
开发语言·前端·javascript
ss2734 小时前
基于Springboot + vue实现的汽车资讯网站
vue.js·spring boot·后端