函数页面配置
function TestPage() {
}
TestPage.config = {
//在这里配置小程序页面相关内容
}
export default TestPage
函数组件配置
function TestCom(props) {
}
TestCom.options = {
addGlobalClass: true
}
export default TestCom
数据加载
const [list, setList] = useState([])
useEffect( async () => {
let data = await getData()
setList(data)
}, [])//传空数组模拟componentDidMount 功能
写一个列表加载组件
功能分析
- 空状态
- 下拉刷新
- 上拉加载
- 加载完成提示
- 加载截流
实现方案
- 使用小程序的下拉刷新和上拉加载功能
- 抽象空状态组件
- 自定义effect抽象加载方案
列表组件代码 1.0
import {View} from "@tarojs/components";
import Empty from "../empty";
function List(props) {
const { listTotal, listLength, emptyTip, children } = props
let isEmpty = listLength === 0
let isLast = listLength >= listTotal
return (
<View>
{
children//列表内容
}
{
isEmpty//列表为空时显示
&&
<Empty title={emptyTip} />
}
{
!isEmpty && isLast//非空状态加载完毕显示
&&
<View className='paddingY30 color-5 font-size-4 text-align-center'>我也是有底线的</View>
}
</View>
)
}
List.options = {
addGlobalClass: true
}
export default List
useGetList 1.0 实现下拉加载
import Taro, {useEffect, useReachBottom, useState} from "@tarojs/taro";
export default function useGetList(getList) {//接收数据加载方法为参数
if (!getList) return []
const [list, setList] = useState([]);//列表数据
const [page, setPage] = useState(1);//列表页
useEffect(async ()=>{
try {
let {list: listGet} = await getList(page)
let newList = page === 1 ? listGet : [...list, ...listGet]
setList(newList)//更新列表
} catch (e) {
console.log(e)
}
}, [page])//页数改变的时候执行
useReachBottom(()=> {
let pageMore = page + 1
setPage(pageMore)
})
return list
}
useGetList 1.1 实现加载中截流和加载完毕截流
默认后端返回列表总数,没有就让后端
import Taro, {useEffect, useReachBottom, useState} from "@tarojs/taro";
export default function useGetList(getList) {
if (!getList) return []
const [list, setList] = useState([]);
const [page, setPage] = useState(1);
const [count, setCount] = useState(null); //列表总数
let loading = false //判断是否正在加载
useEffect(async ()=>{
let isLast = typeof count === 'number' && list.length >= count //判断是否已经加载完毕
let isStop = loading || isLast //是否截流:正在加载或者下拉加载已经完毕
if (!isStop) {
loading = true
try {
let {list: listGet, count: countGet} = await getList(page) //默认后端返回列表总数
let newList = page === 1 ? listGet : [...list, ...listGet]
setList(newList)
countGet !== count && setCount(countGet) //更新列表总数
} catch (e) {
console.log(e)
}
setTimeout(()=> {
loading = false //重置加载状态
}, 0)
}
}, [page])//页数改变的时候执行
useReachBottom(()=> {
let pageMore = page + 1
setPage(pageMore)
})
return list
}
useGetList 2.0 实现下拉刷新
考虑到page=1时刷新需求
同时下拉刷新与上来加载属于不同加载类型
所以增加参数——加载类型type,作为执行useEffect回调条件
import Taro, {useEffect, usePullDownRefresh, useReachBottom, useState} from "@tarojs/taro";
export default function useGetList(getList) {
if (!getList) return []
const [page, setPage] = useState(1);
const [list, setList] = useState([]);
const [count, setCount] = useState(null);
const [type, setType] = useState('load');//加载类型,'load','refresh'等
let loading = false
useEffect(async ()=>{
let isLast = typeof count === 'number' && list.length >= count
let isLoadMore = type === 'load'//判断是否为下拉加载
let isStop = loading || (isLoadMore && isLast)//正在加载或者下拉加载已经完毕——截流
if (!isStop) {
loading = true
try {
let {list: listGet, count: countGet} = await getList(page)
let newList = page === 1 ? listGet : [...list, ...listGet]
setList(newList)
countGet !== count && setCount(countGet)
} catch (e) {
console.log(e)
}
setTimeout(()=> {
type === 'refresh' && Taro.stopPullDownRefresh() //下拉刷新停止
loading = false
}, 0)
}
}, [page, type]) //页数改变或者加载类型改变的时候执行
useReachBottom(()=> {
let pageMore = page + 1
setPage(pageMore)
type !== 'load' && setType('load') //重置加载状态
})
usePullDownRefresh(()=>{ //注意页面需要配置允许刷新
setType('refresh') //更改加载状态
page !== 1 && setPage(1)
})
return [list, count]
}
Index.config = {
navigationBarTitleText: '测试页面',
enablePullDownRefresh: true //页面配置下拉刷新
}
到这里小程序的列表加载组件已经可以用了
使用例子
import { View } from "@tarojs/components";
import DeviceCard from "../../components/device/deviceCard";
import List from "../../components/list";
import useGetList from "../../effects/useGetList";
//这个函数可以提取到后端请求文件里
async function getDevices(page) {
let list = [
{
image: 'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3744924158,1824985192&fm=26&gp=0.jpg',
title: '1如何轻松在Coinicgame',
content: '维马逊自动封口机商用全自动连续热封机来自雅马哈',
id: 1
},
{
image: 'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3744924158,1824985192&fm=26&gp=0.jpg',
title: '2如何轻松在Coinicgame',
content: '维马逊自动封口机商用全自动连续热封机来自雅马哈',
id: 2
}
]
return {list, count: 24}
}
function Index() {
const [list , count] = useGetList(getDevices, null)
return (
<View className='padding-bottom20'>
<List length={list ? list.length : null}
count={count}>
<View className='marginX20 flex-wrap'>
{
list && list.length && list.map((device,index) => (
<DeviceCard key={device.name + index}
device={device} />
))
}
</View>
</List>
</View>
)
}
Index.config = {
navigationBarTitleText: '测试设备列表',
enablePullDownRefresh: true
}
export default Index
优化目标
- 列表组件支持接收列表子组件作为参数
- 扩展列表数据筛选功能——搜索、筛选
useGetList 3.0 增加搜索/筛序功能
import Taro, {useEffect, usePullDownRefresh, useReachBottom, useState} from "@tarojs/taro";
//暴露筛序更新方法
function createUseFilter(setPage, setType, setFilter) {
return (filter) => {
setPage(1)
setType('search')
setFilter(filter)
}
}
export default function useGetList(getList) {
if (!getList) return []
const [list, setList] = useState([]);
const [count, setCount] = useState(null);
const [page, setPage] = useState(1);
const [type, setType] = useState('load');
const [filter, setFilter] = useState({}); //增加筛序条件
let loading = false
useEffect(async ()=>{
let isLast = typeof count === 'number' && list.length >= count
let isLoadMore = type === 'load'
let isStop = loading || (isLoadMore && isLast)
if (!isStop) {
loading = true
try {
let {list: listGet, count: countGet} = await getList(page, filter) //传入筛选条件
let newList = page === 1 ? listGet : [...list, ...listGet]
setList(newList)
countGet !== count && setCount(countGet)
} catch (e) {
console.log(e)
}
type === 'refresh' && Taro.stopPullDownRefresh()
setTimeout(()=> {
loading = false
}, 0)
}
}, [page, type, filter])
useReachBottom(()=> {
let pageMore = page + 1
setPage(pageMore)
setType('load')
})
usePullDownRefresh(()=>{
setPage(1)
setType('refresh')
})
return [list, count, filter, createUseFilter(setPage, setType, setFilter)] //暴露筛选更新方法和目前筛选条件
}
使用
let searchInv = -1
function Index() {
const [list , count, filter, useActionFilter] = useGetList(getDevices, {search: ''})
return (
<View className='news-manage padding-bottom20'>
<View>
<Input type='text'
placeholder='请输入关键词'
onInput={(e) => {
clearTimeout(searchInv)
searchInv = setTimeout(()=> {
console.log('e',e.detail.value)
useActionFilter({search: e.detail.value})
}, 300)
}}
/>
</View>
<List length={list ? list.length : null}
count={count}>
<View className='marginX20 flex-wrap'>
{
list && list.length && list.map((device,index) => (
<DeviceCard key={device.name + index}
device={device} />
))
}
</View>
</List>
</View>
)
}
特别提醒:Taro中一个文件只能定义一个组件
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!