学习一下项目中的代码
搜索 - Search 组件
弹出层的顶部用到了Search组件
1. action
Search组件中需要自定义右侧的按钮,可以使用showAction(默认文字为取消)+ actionText自定义按钮文字;也可以使用action自定义右边部分操作区域
官网文档使用方法1:
jsx
<Search
showAction
label="地址"
actionText={<div onClick={() => Toast.info(value)}>搜索</div>}
value={value}
onChange={setValue}
placeholder="请输入搜索关键词"
/>
2. value
value
用于控制搜索框中的文字
value绑定的变量,通过onChange更新即可
3.点击进行搜索
jsx
// 搜索关键词
const onSearchClinic = async () => {
// 前置校验
if (!searchName) {
Toast('请输入名称关键字再进行搜索')
return
}
// 开始搜索
try {
setSearchLoading('loading')
const {
data: { rows },
} = await triggerClinicList()
const _rows = [...rows].map((item) => ({
...item,
value: item.code,
text: item.name,
}))
setClinicList(_rows)
setSearchLoading('sucess')
} catch (error) {
setSearchLoading('sucess')
}
}
数据列表 - List 组件
List 组件滚动到底部时,会触发
onLoad
事件,此时可以发起异步操作并更新数据,若数据已全部加载完毕,则直接将finished
设置成true
即可。react-vant - List 内部包含了防止并发的重复请求的逻辑,使用中不需要额外处理
如果有分页,则可以使用onLoad事件,项目中为全量返回,所以不需要这个。
选择则某个诊所之后进行反显
搜索的字段和外层最终反显的字段分为两个记录,关闭的时候或者每次打开的时候要清除内部的字段(看业务要求)
jsx
const [clinicName, setClinicName] = useState('') // 外层业务字段
const [searchName, setSearchName] = useState('') // 弹窗记录搜索的关键字
// 点击cell,进行选择
const setClinicHandle = (v: any) => {
// 更新外层输入框名称
// 关闭弹窗
onCloseClinicPop()
}
占位组件 - Empty
占位组件的图片有两个状态:1.图片显示 2. loading显示
占位组件的文案有两个状态:1.初始化时的搜索提醒 2. 搜索结果为空时的提醒
jsx
// loading -- 加载中,wait -- 初始化, sucess -- 搜索完成(不论结果如何)
const [searchLoading, setSearchLoading] = useState<'wait' | 'loading' | 'sucess'>('wait')
其他小细节:
- 点击外层按钮,唤起弹窗时自动聚焦到搜索输入框
jsx
const searchRef = useRef<SearchInstance | any>(null)
// 显示
const onShowClinicPop = () => {
// do something 点击前校验,清空搜索关键词 onClearClinic
setShowClinicPop(true) // 弹窗
setTimeout(() => {
if (searchRef && searchRef.current) {
searchRef.current?.focus() // 设置焦点
}
}, 0)
}
// 关闭弹窗
const onCloseClinicPop = () => {
if (searchRef && searchRef.current) {
searchRef.current?.blur() // 设置焦点
}
setShowClinicPop(false)
}
部分代码如下:
jsx
<Popup
position="bottom"
round={true}
visible={showClinicPop}
onClose={onCloseClinicPop}
style={{ height: '60vh' }}
>
<div className="popup-header">
<VantButton
style={{
border: 'none',
boxShadow: 'none',
backgroundColor: 'transparent',
color: 'inherit',
}}
icon={<Cross />}
onClick={onCloseClinicPop}
/>
</div>
<Search
action={
<div
className="search-text"
onClick={onSearchClinic}
>
搜索
</div>
}
value={searchName}
onChange={(v) => {
setSearchName(v)
}}
placeholder="输入名称关键字"
onSearch={onSearchClinic}
onClear={onClearClinic}
ref={searchRef}
/>
<div style={{ height: 'calc(60vh - 98px)', overflowY: 'auto' }}>
{clinicList?.length > 0 ? (
<List
onLoad={() => new Promise(() => {})}
finished={true}
>
{clinicList.map((item, index) => (
<Cell
key={index}
value={item.text}
isLink
arrowDirection="right"
valueClass="text-[#323232]"
onClick={() => {
setClinicHandle(item.code)
}}
/>
))}
</List>
) : (
<Empty
image={
searchLoading === 'loading' ? (
<div className="empty-loading">
<Loading type="ball" />
</div>
) : (
'search'
)
}
description={
searchLoading === 'sucess'
? '搜索列表为空'
: searchLoading === 'wait'
? '点击搜索查找您的诊所'
: ''
}
/>
)}
</div>
</Popup>