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>
相关推荐
fruge1 分钟前
纯css制作声波扩散动画、js+css3波纹催眠动画特效、【css3动画】圆波扩散效果、雷达光波效果完整代码
javascript·css·css3
neter.asia9 分钟前
vue中如何关闭eslint检测?
前端·javascript·vue.js
十一吖i28 分钟前
前端将后端返回的文件下载到本地
vue.js·elementplus
光影少年29 分钟前
vue2与vue3的全局通信插件,如何实现自定义的插件
前端·javascript·vue.js
Rattenking34 分钟前
React 源码学习01 ---- React.Children.map 的实现与应用
javascript·学习·react.js
熊的猫2 小时前
JS 中的类型 & 类型判断 & 类型转换
前端·javascript·vue.js·chrome·react.js·前端框架·node.js
mosen8682 小时前
Uniapp去除顶部导航栏-小程序、H5、APP适用
vue.js·微信小程序·小程序·uni-app·uniapp
别拿曾经看以后~3 小时前
【el-form】记一例好用的el-input输入框回车调接口和el-button按钮防重点击
javascript·vue.js·elementui
川石课堂软件测试3 小时前
性能测试|docker容器下搭建JMeter+Grafana+Influxdb监控可视化平台
运维·javascript·深度学习·jmeter·docker·容器·grafana
JerryXZR4 小时前
前端开发中ES6的技术细节二
前端·javascript·es6