react + zarm 实现账单列表类型以及时间条件弹窗封装
Posted 凯小默:树上的男爵
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了react + zarm 实现账单列表类型以及时间条件弹窗封装相关的知识,希望对你有一定的参考价值。
需要实现的效果
点击类型,出现下面的条件弹窗
点击时间,出现下面的弹窗
实现过程
这里用到 popup 组件 https://zarm.design/#/components/popup
1.封装类型条件组件
新建 components/PopupType
,在其内部新建 index.jsx
和 style.module.less
内容如下:
import React, forwardRef, useEffect, useState from 'react'
import PropTypes from 'prop-types'
import Popup, Icon from 'zarm'
import cx from 'classnames'
import queryTypeList from './api/index.js'
import s from './style.module.less'
// forwardRef 用于拿到父组件传入的 ref 属性,这样在父组件便能通过 ref 控制子组件。
const PopupType = forwardRef(( onSelect , ref) =>
const [show, setShow] = useState(false); // 组件的显示和隐藏
const [active, setActive] = useState('all'); // 激活的 type
const [expense, setExpense] = useState([]); // 支出类型标签
const [income, setIncome] = useState([]); // 收入类型标签
useEffect(async () =>
// 请求标签接口放在弹窗内,这个弹窗可能会被复用,所以请求如果放在外面,会造成代码冗余。
const data = await queryTypeList();
console.log(data);
setExpense(data.filter(i => i.type == 1))
setIncome(data.filter(i => i.type == 2))
, [])
if (ref)
ref.current =
// 外部可以通过 ref.current.show 来控制组件的显示
show: () =>
setShow(true)
,
// 外部可以通过 ref.current.close 来控制组件的显示
close: () =>
setShow(false)
;
// 选择类型回调
const choseType = (item) =>
setActive(item.id)
setShow(false)
// 父组件传入的 onSelect,为了获取类型
onSelect(item)
;
return <Popup
visible=show
direction="bottom"
onMaskClick=() => setShow(false)
destroy=false
mountContainer=() => document.body
>
<div className=s.popupType>
<div className=s.header>
请选择类型
<Icon type="wrong" className=s.cross onClick=() => setShow(false) />
</div>
<div className=s.content>
<div onClick=() => choseType( id: 'all' ) className=cx( [s.all]: true, [s.active]: active == 'all' )>全部类型</div>
<div className=s.title>支出</div>
<div className=s.expenseWrap>
expense.map((item, index) => <p key=index onClick=() => choseType(item) className=cx([s.active]: active == item.id) > item.name </p>)
</div>
<div className=s.title>收入</div>
<div className=s.incomeWrap>
income.map((item, index) => <p key=index onClick=() => choseType(item) className=cx([s.active]: active == item.id) > item.name </p>)
</div>
</div>
</div>
</Popup>
);
PopupType.propTypes =
onSelect: PropTypes.func
export default PopupType;
.popup-type
height: 500px;
background-color: #f5f5f5;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
.header
position: sticky;
top: 0;
left: 0;
z-index: 1000;
width: 100%;
height: 56px;
text-align: center;
font-size: 14px;
line-height: 56px;
color: rgba(0, 0, 0, 0.9);
background-color: #fff;
.cross
position: absolute;
right: 10px;
top: 50%;
font-size: 20px;
transform: translateY(-50%);
color: rgba(0, 0, 0, 0.6);
.content
padding: 20px;
.all
display: inline-block;
padding: 12px 20px;
font-size: 16px;
color: rgba(0, 0, 0, 0.9);
background-color: #fff;
.title
color: rgba(0, 0, 0, 0.9);
margin: 10px 0;
font-size: 14px;
.expense-wrap, .income-wrap
display: flex;
justify-content: space-between;
flex-wrap: wrap;
p
width: calc(~"(100% - 20px) / 3");
text-align: center;
padding: 12px 0;
margin-bottom: 10px;
background-color: #fff;
font-size: 16px;
.active
background-color: #007fff!important;
color: #fff;
然后新建 components/PopupType/api
,在其内部新建 index.js
添加如下:
import fetchData from "@/utils/axios.js";
// 获取类型字典列表
export function queryTypeList(data)
return fetchData('/api/type/list', 'get', data);
2.封装时间条件组件
新建 components/PopupDate
,在其内部新建 index.jsx
代码如下:
import React, forwardRef, useState from 'react'
import PropTypes from 'prop-types'
import Popup, DatePicker from 'zarm'
import dayjs from 'dayjs'
const PopupDate = forwardRef(( onSelect, mode = 'date' , ref) =>
const [show, setShow] = useState(false)
const [now, setNow] = useState(new Date())
const choseMonth = (item) =>
setNow(item)
setShow(false)
if (mode == 'month')
onSelect(dayjs(item).format('YYYY-MM'))
else if (mode == 'date')
onSelect(dayjs(item).format('YYYY-MM-DD'))
if (ref)
ref.current =
show: () =>
setShow(true)
,
close: () =>
setShow(false)
;
return <Popup
visible=show
direction="bottom"
onMaskClick=() => setShow(false)
destroy=false
mountContainer=() => document.body
>
<div>
<DatePicker
visible=show
value=now
mode=mode
onOk=choseMonth
onCancel=() => setShow(false)
/>
</div>
</Popup>
);
PopupDate.propTypes =
mode: PropTypes.string, // 日期模式
onSelect: PropTypes.func, // 选择后的回调
export default PopupDate;
3.账单列表组件改动
import React, useState, useEffect, useRef from 'react'
import Icon, Pull from 'zarm'
import dayjs from 'dayjs'
import BillItem from '@/components/BillItem'
import PopupType from '@/components/PopupType'
import PopupDate from '@/components/PopupDate'
import queryBillList from './api/index.js'
import REFRESH_STATE, LOAD_STATE from '@/utils/index.js' // Pull 组件需要的一些常量
import s from './style.module.less'
const Home = () =>
const typeRef = useRef(); // 账单类型 ref
const monthRef = useRef(); // 月份筛选 ref
const [currentSelect, setCurrentSelect] = useState(); // 当前筛选类型
const [currentTime, setCurrentTime] = useState(dayjs().format('YYYY-MM')); // 当前筛选时间
const [totalExpense, setTotalExpense] = useState(0); // 总支出
const [totalIncome, setTotalIncome] = useState(0); // 总收入
const [page, setPage] = useState(1); // 分页
const [dataList, setDataList] = useState([]); // 账单列表
const [totalPage, setTotalPage] = useState(0); // 分页总数
const [refreshing, setRefreshing] = useState(REFRESH_STATE.normal); // 下拉刷新状态
const [loading, setLoading] = useState(LOAD_STATE.normal); // 上拉加载状态
useEffect(() =>
getBillList() // 初始化
, [page, currentSelect, currentTime])
// 获取账单方法
const getBillList = async () =>
const data = await queryBillList(
curPage: page,
pageSize: 5,
typeId: currentSelect.id || "all",
billDate: currentTime
);
// 下拉刷新,重制数据
if (page == 1)
setDataList(data.dataList);
else
setDataList(dataList.concat(data.dataList));
setTotalExpense(data.totalExpense);
setTotalIncome(data.totalIncome);
setTotalPage(data.pageObj.totalPage);
// 上滑加载状态
setLoading(LOAD_STATE.success);
setRefreshing(REFRESH_STATE.success);
// 请求列表数据
const refreshData = () =>
setRefreshing(REFRESH_STATE.loading);
if (page != 1)
setPage(1);
else
getBillList();
;
;
const loadData = () =>
if (page < totalPage)
setLoading(LOAD_STATE.loading);
setPage(page + 1);
// 添加账单弹窗
const toggle = () =>
typeRef.current && typeRef.current.show()
;
// 选择月份弹窗
const monthToggle = () =>
monthRef.current && monthRef.current.show()
;
// 筛选类型
const select = (item) =>
setRefreshing(REFRESH_STATE.loading);
setPage(1);
setCurrentSelect(item)
// 筛选月份
const selectMonth = (item) =>
setRefreshing(REFRESH_STATE.loading);
setPage(1);
setCurrentTime(item)
return <div className=s.home>
<div className=s.header>
<div className=s.dataWrap>
<span className=s.expense>总支出:<b>¥ totalExpense </b></span>
<span className=s.income>总收入:<b>¥ totalIncome </b></span>
</div>
<div className=s.typeWrap>
<div className=s.left onClick=toggle>
<span className=s.title> currentSelect.name || '全部类型' <Icon className=s.arrow type="arrow-bottom" /></span>
</div>
<div className=s.right onClick=monthToggle>
<以上是关于react + zarm 实现账单列表类型以及时间条件弹窗封装的主要内容,如果未能解决你的问题,请参考以下文章
react + zarm + antV F2 实现账单数据统计饼图效果
react + zarm + react-captcha-code + classnames 实现登录注册页面
react + zarm + rc-form + crypto-js 实现个人中心页面,头像上传,密码重置,登录退出功能
egg.js + react + zarm ui + vite2.0 全栈项目实战:从 0 到 1 实现记账本小册学习笔记合集(完结)