【问题标题】:Click Down/Up keys for scrolling inside ul element- React单击向下/向上键在 ul 元素内滚动 - React
【发布时间】:2020-03-30 20:21:12
【问题描述】:

我在尝试让我自己的自动完成组件做出反应时遇到了问题。 我创建了一个渲染结果并在其包装器上设置 max-height 的组件, 我在输入元素上使用了 onKeyDown 事件来跟踪向下/向上按键。现在我用它来标记活动项目......但是当我设置的最大高度太小并且当“活动项目”超出 div 的高度限制时,侧面有一个滚动,滚动不会继续下去......我该如何解决它?

import React, { useState, useEffect } from "react"

const Autocomplete = ({ options }) => {
  const [activeOption, setActiveOption] = useState(4)
  const [filteredOptions, setFilteredOptions] = useState([])
  const [showOptions, setShowOptions] = useState(false)
  const [userInput, setUserInput] = useState("")

  useEffect(() => {
    setShowOptions(userInput)
    setFilteredOptions([
      ...options.filter(
        option => option.toLowerCase().indexOf(userInput.toLowerCase()) > -1
      )
    ])
    setActiveOption(0)
  }, [userInput])

  const handleKeyDown = e => {
    if (e.key === "ArrowDown") {
      if (activeOption === filteredOptions.length - 1) return
      setActiveOption(activeOption + 1)
    }
    if (e.key === "ArrowUp") {
      if (activeOption === 0) return
      setActiveOption(activeOption - 1)
    }
  }

  return (
    <>
      <div className="search">
        <input
          type="text"
          className="search-box"
          value={userInput}
          onChange={e => setUserInput(e.target.value)}
          onKeyDown={handleKeyDown}
        />
        <ul className="options">
          {showOptions &&
            filteredOptions.map((option, i) => (
              <li className={activeOption === i ? `option-active` : ``} key={i}>
                {option}
              </li>
            ))}
        </ul>
      </div>
    </>
  )
}

export default Autocomplete

function App() {
  return (
    <div className="App">
      <Autocomplete
        options={[
          "Alligator",
          "Bask",
          "Crocodilian",
          "Death Roll",
          "Eggs",
          "Jaws",
          "Reptile",
          "Solitary",
          "Tail",
          "Wetlands"
        ]}
      />
    </div>
  )
}
.option-active {
  font-weight: bold;
  background: cornflowerblue;
}

.options {
  height: 100px;
  overflow: overlay;
}

这里有一张图片可以更好地解释我的问题: 当第二个项目处于活动状态时:

当第六个有效时:

如您所见,滚动保持不变,不会随着 li 元素向下移动... 衷心感谢!

【问题讨论】:

  • 您是否在新选定的元素上尝试过setFocus
  • @RafaelMora 我尝试使用 ref 然后使用 ref.current.focus() 但这不起作用...
  • 试试:container = $('MyElement').get(0); container.scrollTop = (container.scrollHeight + container.offsetHeight);

标签: javascript reactjs autocomplete element


【解决方案1】:

我认为您可以维护一个元素引用数组,以便在活动选项更改时调用该元素的scrollIntoView 方法。

未经测试的代码:

// Use a ref container (we won't use `current`)
const elmRefs = useRef()

// Instead we build a custom ref object in each key of the ref for each option
useEffect(() => {
  options.forEach(opt => elmRefs[opt] = {current: null} 
}, [options])

// Effect that scrolls active element when it changes
useLayoutEffect(() => {
  // This is what makes element visible
  elmRefs[options[activeOption]].current.scrollIntoView()
}, [options, activeOption])

// In the "render" section, connect each option to elmRefs
<li className={activeOption === i ? `option-active` : ``} ref={elmRefs[option]} key={i}>
  {option}
</li>

让我知道你的想法!

编辑:

如果需要立即初始化 elmRefs,您可以这样做:

// Outside component
const initRefs = options => Object.fromEntries(options.map(o => [o, {current: null}]))

// Then in the component, replace useRef by:
const elmRefs = useRef(initRef(options))

并在其余代码中将elmRefs 替换为elmRefs.current...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-23
    • 1970-01-01
    • 1970-01-01
    • 2012-10-27
    • 1970-01-01
    相关资源
    最近更新 更多