基于react-vant实现弹窗搜索功能

学习一下项目中的代码

弹出层的顶部用到了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')

其他小细节:

  1. 点击外层按钮,唤起弹窗时自动聚焦到搜索输入框
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>
相关推荐
y_y12 分钟前
Streamable HTTP:下一代实时通信协议,解决SSE的四大痛点
前端·http
无羡仙19 分钟前
流式输出SSE
前端
小噔小咚什么东东39 分钟前
Vue开发H5项目中基于栈的弹窗管理
前端·vue.js·vant
OpenTiny社区40 分钟前
基于华为云大模型服务MaaS和OpenTiny框架实现商城商品智能化管理
前端·agent·mcp
云枫晖42 分钟前
JS核心知识-原型和原型链
前端·javascript
小卓笔记1 小时前
第1章 Web服务-nginx
前端·网络·nginx
OneWind1 小时前
今天发现一个提升图片加载速度的方法就是使用服务器代理
react.js
华仔啊1 小时前
Vue+CSS 做出的LED时钟太酷了!还能倒计时,代码全开源
前端·css·vue.js
m0_564914922 小时前
点击EDGE浏览器下载的PDF文件总在EDGE中打开
前端·edge·pdf
@大迁世界2 小时前
JavaScript 2.0?当 Bun、Deno 与 Edge 运行时重写执行范式
开发语言·前端·javascript·ecmascript