下拉加载弹窗
kingcwt2019-12-05前端react
项目笔记
监听外层盒子scroll
// pagination.page 后端传来的页数
/**
* 下拉modal 加载更多
*/
useEffect(() => {
if (is.empty(pagination)) return;
let timeCount;
function callback() {
/**
* getBoundingClientRect()
* top 指当前加载元素距离屏幕顶部的距离
*/
const { top } = wrapperRef.current.getBoundingClientRect();
/**
* window.screen.height 获取当前屏幕的高度
*/
const windowViewHeight = window.screen.height;
// 屏幕的高度 - 加载盒子的高度
const viewBoxHeight = windowViewHeight - 25;
/**
* 当top的值小于屏幕的高度的时候 就加载更多
*/
if (top && top < viewBoxHeight) {
loadMoreDataFn();
}
}
/**
* 监听外层的盒子 滚动事件
*/
listContainerRef.current.addEventListener('scroll', () => {
// 加载到最后没有数据的时候 就让盒子消失 所以就会变为null 直接返回
if (wrapperRef.current == null) return;
if (is.empty(pagination)) return;
if (!pagination.has_more) return;
if (timeCount) clearTimeout(timeCount);
timeCount = setTimeout(callback, 50);
}, false);
}, [pagination.page]);
请求后端数据
// 后端page页数 发生变化再加载请求后端接口
let flag = pagination.page;
// flag 保证每次都加载请求一次
const loadMoreDataFn = () => {
if (pagination.page === flag) {
flag += 1;
const { _id } = account.account;
const param = {
manage_type: [20, 30],
account_id: _id,
};
dispatch({ type: 'mAccountbillIncome/fetchLoadingRoomList', payload: { ...param, _meta: { page: flag, limit: 10 } } });
}
};
modal弹窗组件
<ComponentFooterModal
wrapperRef={wrapperRef}
listContainerRef={listContainerRef}
pagination={pagination}
dropDownElement={dropDownElement}
isSelectItem={isSelectItem}
onSelectListItem={onSelectListItem}
dropDown={dropDown}
onSelectDefine={onSelectDefine}
onSelectCancel={onSelectCancel}
dataLists={roomListsData}
/>
ComponentFooterModal
/**
* 房间下拉列表 modal
*/
import React from 'react';
import PropTypes from 'prop-types';
import { List } from 'antd-mobile';
import styles from '../style.module.less';
import selectImg from '../../../static/select.png';
import roomIco from '../../../static/roomico.jpg';
import ComponentLoading from './loading';
const { Item } = List;
const { Brief } = Item;
const ComponentFooterModal = ({
wrapperRef, listContainerRef, dropDown, onSelectDefine, onSelectCancel, dataLists, isSelectItem, onSelectListItem, pagination,
}) => {
// 弹窗头部
const renderHeader = () => (
<header className={styles['page-billincome-footer-bottom-headerbox']}>
<p className={styles['page-billincome-footer-bottom-headerbox-leftp']}> <span onClick={onSelectCancel}>取消</span></p>
<h4>选择房源</h4>
<p className={styles['page-billincome-footer-bottom-headerbox-rightp']}> <span onClick={onSelectDefine}>确定</span></p>
</header>
);
// 弹窗底部
const renderFooter = () => (
<div ref={listContainerRef} className={styles['page-billincome-components-footermodal-list']}>
{
dataLists.map(i => (
// eslint-disable-next-line no-underscore-dangle
<div className={styles['page-billincome-components-footermodal-section-box']} onClick={() => onSelectListItem(i)} key={i._id}>
<Item
className={styles['page-billincome-component-header-list-item']}
thumb={i.house_cover_asset_info ? i.house_cover_asset_info.url : roomIco}
multipleLine
onClick={() => {}}
>
<span className={styles['page-billincome-component-footermodal-title']}>{i.name}</span>
<Brief> <span className={styles['page-billincome-component-footermodal-describe']}>{i.product_info ? i.product_info.name : null}</span></Brief>
{
// eslint-disable-next-line no-underscore-dangle
isSelectItem._id === i._id
? <img alt="" className={styles['page-billincome-components-footermodal-img']} src={selectImg} />
: null
}
</Item>
</div>
))
}
{!pagination.has_more ? null : <ComponentLoading wrapperRef={wrapperRef} />}
</div>
);
return (
<footer className={styles['page-billincome-footer']} style={dropDown ? { transform: 'translateY(0)', transitionDuration: '.1s' } : { transform: 'translateY(100vh)', transitionDuration: '.1s' }}>
<div className={styles['page-billincome-footer-top']} onClick={onSelectCancel} />
<div className={styles['page-billincome-footer-bottom']}>
{/* 渲染弹窗头部 */}
{renderHeader()}
{/* 渲染弹窗底部 */}
{renderFooter()}
</div>
</footer>
);
};
/**
* props: {dropDown} type:bool true:显示弹窗 false:关闭弹窗
* props: {isSelectItem} type:object 列表点击切换选中的某一项 我们拿这一项的value进行数据中的value匹配 以达到选中效果
* props: {dataLists} type:array 列表循环的数据
* props: {onSelectDefine} type:func 点击确定提交触发的事件 都关闭弹窗
* props: {onSelectCancel} type:func 点击取消提交触发的事件 都关闭弹窗
* props: {onSelectListItem} type:func 选中列表下某一项触发的事件(列表点击切换选中事件)
* props: {dropDownElement} type:object 房间列表下拉元素 ref
*/
ComponentFooterModal.propTypes = {
dropDown: PropTypes.bool,
dataLists: PropTypes.array,
isSelectItem: PropTypes.object,
onSelectDefine: PropTypes.func.isRequired,
onSelectCancel: PropTypes.func.isRequired,
onSelectListItem: PropTypes.func.isRequired,
pagination: PropTypes.object,
wrapperRef: PropTypes.object.isRequired,
listContainerRef: PropTypes.object.isRequired,
};
ComponentFooterModal.defaultProps = {
dropDown: false,
isSelectItem: {},
dataLists: [],
pagination: {},
};
export default ComponentFooterModal;
ComponentLoading
import React from 'react';
import styles from '../style.module.less';
const componentLoading = ({ wrapperRef }) => (
<div className={styles.loading} ref={wrapperRef}>
<span />
<span />
<span />
<span />
<span />
</div>
);
export default componentLoading;
style.module.less
.page-billincome-main-icon-box{
display: flex;
justify-content: center;
align-items: center;
padding-bottom: 10px;
background-color: #fff;
padding-bottom: .15rem;
margin-top:.1rem;
span{
background: #FFF6E8;
color: #F38C27;
width: 120px;
display: flex;
justify-content: center;
align-items: center;
height: .4rem;
border-radius: 0 0 .42rem .42rem;
padding: 3px 20px;
}
}
// .page-billincome-detail-header-box{
// margin-top: 5px;
// }
.page-billincome-detail-header-box-span{
display: flex;
justify-content: center;
align-items: center;
}
.page-billincome-main-icon-box-list-left-green-span{
color: #18b350;
}
.page-billincome-main-icon-box-list-left-grey-span{
color: #b1b1b1;
font-size: 12px;
margin-left:6px;
}
.page-billincome-detail-main-icon{
display: flex;
align-items: center;
margin-top: 10px;
background: rgba(244, 249, 255, 1);
padding: 10px 5px;
padding-left: .15rem;
color: rgba(90, 154, 229, 1);
height: .44rem;
box-sizing: border-box;
font-size: .16rem;
// .page-billincome-detail-main-icon-leftBox{
// background: #8bce7b;
// color: #fff;
// width: 40%;
// display: flex;
// justify-content: center;
// align-items: center;
// height: 35px;
// }
// .page-billincome-detail-main-icon-rightBox{
// background: #b2dda9;
// color: #333;
// width: 60%;
// display: flex;
// justify-content: start;
// align-items: center;
// height: 35px;
// padding-left: 10px;
// box-sizing: border-box;
// }
}
.page-billincome-detail-main-icon-box{
background: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
position: relative;
// padding-bottom: 15px;
padding-top: .28rem;
.page-billincome-main-icon-box-main{
display: flex;
flex-direction: column;
justify-content: center;
color: #999;
width: 100%;
align-items: self-end;
padding-left: 16px;
box-sizing: border-box;
border-top: 1px solid #eee;
.page-billincome-main-icon-box-main-titleMain{
color: #999;
margin-bottom: 0px;
}
}
}
.page-billincome-detail-bill-amount-one{
font-size: .3rem;
margin: .1rem 0 .2rem 0;
// color:#000;
}
.page-billincome-detail-bill-amount-two{
font-size: .3rem;
margin: .1rem 0 .2rem 0;
color:#ED0E0E;
}
.page-billincome-main-icon-box-footerBox-redSpan{
color: #e83333;
}
.page-billincome-main-icon-box-footerBox-blueSpan{
color: #108ee9;
}
.page-billIncome-main-iconBox-mylist{
background-color: #fff;
padding: 0 14px;
.am-list-header{
background: #f5f6f7;
padding: 8px 9px;
}
}
.page-billIncome-main-iconBox-mylist>div:nth-child(1){
background: #f5f6f7;
padding: 8px 9px;
}
.page-billincome-main-icon-box-main-p{
margin: 5px 0;
}
.page-billIncome-main-iconBox-list-span{
color: #333;
}
.page-billincome-main-icon-box-position-title{
width: 73px;
height: 32px;
background: rgba(255, 235, 235, 1);
color: rgba(206, 137, 115, 1);
display: flex;
justify-content: center;
align-items: center;
font-size: 12px;
border-radius: 100px 0px 0px 100px;
position: absolute;
right: 0px;
top: 2px;
}
.page-billincome-detail-button{
width: 3.82rem;
height: 0.47rem;
border-radius: 0.04rem;
display: flex;
justify-content: center;
align-items: center;
margin: 0.84rem auto .34rem auto;
}
.page-billincome-detail-modal-content{
margin-top: 5px;
}
.page-billincome-footer{
width: 100%;
height: 100%;
// background: #fff;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
z-index: 99999;
display: flex;
flex-direction: column;
justify-content: flex-end;
.page-billincome-footer-top{
// background: #000;
width: 100%;
height: 100%;
opacity: 0.3;
filter: alpha(opacity=30);
-moz-opacity:0.3;
-khtml-opacity:0.5;
z-index: 999999;
background-color: #000;
}
.page-billincome-footer-bottom{
width: 100%;
background: #eee;
max-height: 6.1rem;
background: #acacaf;
.page-billincome-footer-bottom-headerbox{
background: rgba(248, 248, 248, 1);
height: .49rem;
border-radius: .12rem .12rem 0 0;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
.page-billincome-footer-bottom-headerbox-leftp{
color:rgb(111 101 101);
span{
padding: .12rem;
}
}
.page-billincome-footer-bottom-headerbox-rightp{
color:rgba(245, 147, 0, 1);
span{
padding: .12rem;
}
}
}
}}
.page-billIncome-detail-hedaer-imgBox{
display:flex;
.page-billIncome-detail-hedaer-imgBox-img{
margin-right: 18px;
width: 40px;
height: 40px;
}
}
.page-billincome-detail-main-icon-green{
display: flex;
align-items: center;
margin-top: 10px;
background: rgba(245, 255, 249, 1);
padding: 10px 5px;
padding-left: .15rem;
color: rgba(74, 193, 120, 1);
height: .44rem;
box-sizing: border-box;
font-size: .16rem;
}
.page-billincome-detail-main-icon-yellow{
display: flex;
align-items: center;
margin-top: 10px;
background: rgba(255, 250, 243, 1);
padding: 10px 5px;
padding-left: .15rem;
color: rgba(240, 154, 25, 1);
height: .44rem;
box-sizing: border-box;
font-size: .16rem;
}
.page-billincome-detail-main-icon-grey{
display: flex;
align-items: center;
margin-top: 10px;
background: rgba(255, 255, 255, 1);
padding: 10px 5px;
color: rgba(175, 175, 199, 1);
height: .44rem;
box-sizing: border-box;
border-bottom: 1px solid #dfdfff;
height: .44rem;
padding-left: .15rem;
font-size: .16rem;
}
.page-billincome-detail-main-icon-error{
display: flex;
align-items: center;
margin-top: 10px;
background: rgba(255, 255, 255, 1);
padding: 10px 5px;
padding-left: .15rem;
color:red;
height: .44rem;
box-sizing: border-box;
font-size: .16rem;
}
.page-billincome-main-icon-box-switch-ico{
width:16px;
margin-left:5px;
}
.page-billincome-components-footermodal-section-box{
min-height: 60px;
height: .92rem;
border-bottom: 1px solid #eee;
z-index: 999999999;
.page-billincome-components-footermodal-img{
position: absolute;
width: .33rem;
height: .3rem;
display: block;
top: 50%;
right: 17px;
margin-top: -15px;
}
}
// 房间头部占位符
.page-billincome-header-roomlist-placeholder{
height: 50px;
width: 100%;
background: #fff;
}
.page-billincome-list-child-item-amount{
color:#000;
}
.page-billincome-header-list-item{
padding: .16rem;
img{
width: .6rem;
height: auto;
}
}
.page-billincome-component-header-list-item{
height: 100%;
img{
width: .6rem;
height: auto;
}
}
.page-billincome-detail-in-out-date{
font-size: .14rem;
}
.page-billincome-render-select-tab-bill{
display: flex;
justify-content: center;
align-items: center;
height: calc(100vh - 2rem);
img{
width: 1.6rem;
height: auto;
}
}
.page-billincome-components-footermodal-list{
height: 400px;
overflow-y: auto;
background-color: #fff;
z-index: 9999;
}
.page-billincome-components-footermodal-placeholder{
background: #fff;
border: 1px solid red;
display: flex;
justify-content: center;
align-items: center;
font-size: 20px;
height: .5rem;
margin: .1rem;
}
.loading{
width: 100%;
height: .2rem;
margin: 10px 0;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
}
.loading span{
display: inline-block;
width: 15px;
height: 100%;
margin-right: 5px;
background: lightgreen;
-webkit-animation: load 1.04s ease infinite;
}
.loading span:last-child{
margin-right: 0px;
}
@-webkit-keyframes load{
0%{
opacity: 1;
}
100%{
opacity: 0;
}
}
.loading span:nth-child(1){
-webkit-animation-delay:0.13s;
}
.loading span:nth-child(2){
-webkit-animation-delay:0.26s;
}
.loading span:nth-child(3){
-webkit-animation-delay:0.39s;
}
.loading span:nth-child(4){
-webkit-animation-delay:0.52s;
}
.loading span:nth-child(5){
-webkit-animation-delay:0.65s;
}
.page-billincome-component-footermodal-title,.page-billincome-component-footermodal-describe{
width: 85%;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}