You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Preline UI Select组件onClick/onChange事件失效问题

Preline UI高级Select组件React中onChange事件无效的解决方案

问题背景

在React项目中使用Preline UI的高级Select组件时,添加data-hs-select属性配置后,原生的onChange、onClick事件完全无法触发,控制台无输出。虽然界面能正常显示选中值,也能通过useRef或DOM选择器获取选中值,但事件绑定完全失效,改用Formik的field[as='select']也存在同样问题。

原代码示例:

<select
  name='Country'
  data-hs-select='{
    "hasSearch": true,
    "searchPlaceholder": "Search...",
    "searchClasses": "block w-full text-sm border-gray-200 rounded-lg focus:border-blue-500 focus:ring-blue-500 before:absolute before:inset-0 before:z-[1] dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600 py-2 px-3",
    "searchWrapperClasses": "bg-white p-2 -mx-1 sticky top-0 dark:bg-slate-900",
    "placeholder": "Select ...",
    "toggleTag": "<button type=\"button\"><span class=\"me-2\" data-icon></span><span class=\"text-gray-800 dark:text-gray-200\" data-title></span></button>",
    "toggleClasses": "hs-select-disabled:pointer-events-none hs-select-disabled:opacity-50 relative py-3 px-4 pe-9 flex text-nowrap w-full cursor-pointer bg-white border border-gray-200 rounded-lg text-start text-sm focus:border-blue-500 focus:ring-blue-500 before:absolute before:inset-0 before:z-[1] dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600",
    "dropdownClasses": "mt-2 max-h-[300px] pb-1 px-1 space-y-0.5 z-20 w-full bg-white border border-gray-200 rounded-lg overflow-hidden overflow-y-auto dark:bg-slate-900 dark:border-gray-700",
    "optionClasses": "py-2 px-4 w-full text-sm text-gray-800 cursor-pointer hover:bg-gray-100 rounded-lg focus:outline-none focus:bg-gray-100 dark:bg-slate-900 dark:hover:bg-slate-800 dark:text-gray-200 dark:focus:bg-slate-800",
    "optionTemplate": "<div><div class=\"flex items-center\"><div class=\"me-2\" data-icon></div><div class=\"text-gray-800 dark:text-gray-200\" data-title></div></div></div>"
  }'
  className='hidden'
  onChange={() => console.log('option clicked')}
>
  <option value=''>Choose</option>
  <option value='Australia'>Australia</option>
  <option value='Canada'>Canada</option>
  <option value='France'>France</option>
  <option value='Germany'>Germany</option>
  <option value='Italy'>Italy</option>
</select>

问题原因

Preline UI的高级Select组件会通过JavaScript将原生<select>元素隐藏,渲染自定义的UI交互层(按钮、下拉列表等)。用户实际点击交互的是Preline生成的DOM元素,而非原生<select>,因此直接绑定在原生元素上的onChange等事件不会被触发。

解决方案

使用Preline UI提供的HSSelect实例API来绑定事件,而非原生事件。在React中需配合useEffect完成实例初始化与事件绑定,并在组件卸载时清理资源。

基础实现示例

import { useEffect, useRef } from 'react';

function CountrySelect() {
  const selectRef = useRef(null);

  useEffect(() => {
    // 初始化Preline Select实例
    const selectInstance = new HSSelect(selectRef.current, {
      hasSearch: true,
      searchPlaceholder: "Search...",
      searchClasses: "block w-full text-sm border-gray-200 rounded-lg focus:border-blue-500 focus:ring-blue-500 before:absolute before:inset-0 before:z-[1] dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600 py-2 px-3",
      searchWrapperClasses: "bg-white p-2 -mx-1 sticky top-0 dark:bg-slate-900",
      placeholder: "Select ...",
      toggleTag: "<button type=\"button\"><span class=\"me-2\" data-icon></span><span class=\"text-gray-800 dark:text-gray-200\" data-title></span></button>",
      toggleClasses: "hs-select-disabled:pointer-events-none hs-select-disabled:opacity-50 relative py-3 px-4 pe-9 flex text-nowrap w-full cursor-pointer bg-white border border-gray-200 rounded-lg text-start text-sm focus:border-blue-500 focus:ring-blue-500 before:absolute before:inset-0 before:z-[1] dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600",
      dropdownClasses: "mt-2 max-h-[300px] pb-1 px-1 space-y-0.5 z-20 w-full bg-white border border-gray-200 rounded-lg overflow-hidden overflow-y-auto dark:bg-slate-900 dark:border-gray-700",
      optionClasses: "py-2 px-4 w-full text-sm text-gray-800 cursor-pointer hover:bg-gray-100 rounded-lg focus:outline-none focus:bg-gray-100 dark:bg-slate-900 dark:hover:bg-slate-800 dark:text-gray-200 dark:focus:bg-slate-800",
      optionTemplate: "<div><div class=\"flex items-center\"><div class=\"me-2\" data-icon></div><div class=\"text-gray-800 dark:text-gray-200\" data-title></div></div></div>"
    });

    // 绑定change事件
    const handleSelectChange = () => {
      const selectedValue = selectInstance.getValue();
      console.log('选中值:', selectedValue);
      // 这里可添加自定义逻辑,比如更新组件state
    };

    selectRef.current.addEventListener('change', handleSelectChange);

    // 组件卸载时清理实例与事件监听
    return () => {
      selectRef.current.removeEventListener('change', handleSelectChange);
      selectInstance.destroy();
    };
  }, []);

  return (
    <select
      ref={selectRef}
      name='Country'
      className='hidden'
    >
      <option value=''>Choose</option>
      <option value='Australia'>Australia</option>
      <option value='Canada'>Canada</option>
      <option value='France'>France</option>
      <option value='Germany'>Germany</option>
      <option value='Italy'>Italy</option>
    </select>
  );
}

export default CountrySelect;

Formik集成示例

若需配合Formik使用,需在事件处理中手动更新Formik的字段值:

import { useEffect, useRef } from 'react';
import { useFormik } from 'formik';

function CountrySelectForm() {
  const selectRef = useRef(null);
  const formik = useFormik({
    initialValues: { Country: '' },
    onSubmit: (values) => {
      console.log('表单提交数据:', values);
    },
  });

  useEffect(() => {
    const selectInstance = new HSSelect(selectRef.current, {
      hasSearch: true,
      searchPlaceholder: "Search...",
      // 其他配置项同上
    });

    const handleSelectChange = () => {
      const selectedValue = selectInstance.getValue();
      // 更新Formik字段值
      formik.setFieldValue('Country', selectedValue);
      console.log('选中值:', selectedValue);
    };

    selectRef.current.addEventListener('change', handleSelectChange);

    return () => {
      selectRef.current.removeEventListener('change', handleSelectChange);
      selectInstance.destroy();
    };
  }, [formik]);

  return (
    <form onSubmit={formik.handleSubmit}>
      <select
        ref={selectRef}
        name='Country'
        className='hidden'
        value={formik.values.Country}
      >
        <option value=''>Choose</option>
        <option value='Australia'>Australia</option>
        <option value='Canada'>Canada</option>
        <option value='France'>France</option>
        <option value='Germany'>Germany</option>
        <option value='Italy'>Italy</option>
      </select>
      <button type='submit' className='mt-4'>提交表单</button>
    </form>
  );
}

export default CountrySelectForm;

关键注意点

  • 移除原生<select>上的data-hs-select属性,将配置项移至HSSelect实例初始化参数中,避免React中JSON字符串解析问题。
  • 必须通过HSSelect实例的getValue()方法获取选中值,而非直接读取原生select的value。
  • 组件卸载时务必销毁HSSelect实例并移除事件监听,防止内存泄漏。

内容的提问来源于stack exchange,提问作者Jubair

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 21:36:06