gpt4 book ai didi

javascript - 使用点击处理程序构建动态菜单

转载 作者:行者123 更新时间:2023-11-27 23:17:57 27 4
gpt4 key购买 nike

我在查找这段代码中的问题时遇到了很多麻烦...我正在尝试构建一个水平菜单,该菜单在单击时会展开,然后用户可以单击他们想要的选项。要关闭展开的菜单,他们可以单击左侧的“X”。 Here's an image of what I want it to look like

我问了一个以前的question并进行了一些更改,但不知道从这里开始做什么。

我的主要问题:

  • 如何从 buildLanguageSelector 添加动态创建的列表元素?

  • 如何将点击处理程序添加到 menux 以便它们在点击时切换?现在,传递给点击处理程序的 thisnull

    const LanguageSelector = (props) => {
    const { languages, onSelectLanguage } = props
    const listContainer = document.createElement('ul')
    listContainer.style.position = 'absolute'
    listContainer.style.top = '0'

    const buildLanguageSelector = () => {
    if (props.ui.languages.length) {
    [...props.ui.languages].forEach(function (language, i) {
    const el = document.createElement('li')
    el.value = language.languageCode
    el.innerHTML = language.name
    el.className = "item"
    el.addEventListener("click", function(e) {
    e.stopPropagation()
    })
    listContainer.appendChild(el)
    })
    } else {
    }
    }

    buildLanguageSelector()

    const openMenu = (e) => {
    console.log(e)
    e.parentElement.classList.add('open')
    }
    const closeMenu = (e) => {
    e.parentElement.classList.remove('open')
    }

    return (
    <div className='menu'>
    // `this` being passed into `openMenu` and `closeMenu` is null
    <div className='open-button' onClick= {openMenu(this)}>Menu</div>
    <div className='close-button' onClick= {closeMenu(this)}>&#10005;</div>
    // I know that this part is incorrect-- however I'm not sure how
    // to insert the dynamically created li's from buildLanguageSelector
    <div>{listContainer}</div>
    </div>
    )
    }
    body {
    background: white;
    }
    .menu {
    background: white;
    border-radius: 17px;
    height: 34px;
    width: 100px;
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
    cursor: pointer;
    }

    .menu .item {
    display: none;
    color: grey;
    }
    .menu #open-button {
    display: block;
    }
    .menu #close-button {
    display: none;
    color: grey;
    }

    .menu.open {
    justify-content: space-around;
    width: 300px;
    }
    .menu.open .item {
    display: block;
    }
    .menu.open .item:hover {
    color: black;
    }
    .menu.open .close-button {
    display: block;
    }
    .menu.open .close-button:hover {
    color: black;
    }
    .menu.open .open-button {
    display: none;
    }

最佳答案

更新:添加了示例菜单实现

我意识到从风格上讲这不是您想要的,但从概念上讲这是我认为您想要走的方向:

const languages = [
"English",
"Spanish",
"French",
"Wookie",
"Klingon"
]

function Menu () {
// keep track of whether the menu is open
const [isOpen, setOpen] = React.useState(false);

// in a real app this would notify interested
// parties (redux dispatch or whatever)
const [selectedLanguage, setLanguage] = React.useState(languages[0]);

// convenience function for setting the language
// and closing the menu
const onLangSelect = language => {
setLanguage(language);
setOpen(false);
};

return (
<div>
<button onClick={() => setOpen(!isOpen)}>{selectedLanguage} v</button>
<ul className="language-menu">
{
// if the menu is open, render the items…
isOpen && (
// by iterating over the available languages and emitting an item for each.
// item.onClick invokes onLangSelect, passing in the selected language
// we're also flagging the current item with a css class here
languages.map(lang => (
<li className={selectedLanguage === lang ? 'selected' : ''} onClick={() => onLangSelect(lang)} key={lang}>
{lang}
</li>
))
)
}
</ul>
</div>
)
}

ReactDOM.render(<Menu />, document.querySelector("#app"))
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}

#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}

.language-menu {
position: absolute;
background: white;
font-size: 0.875rem;
min-width: 150px;
padding: 0;
margin: 0;
list-style: none;

}

.language-menu li {
padding: 1em;
}

.language-menu li:hover {
background: lightblue;
}

li.selected {
background: bisque;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.0/umd/react-dom.production.min.js"></script>

<div id="app"></div>


您不应该直接操作 DOM。这样做削弱了 React 的全部意义。只需发出您需要的节点。所以不是这个:

// don't do this. there's no need to manually create dom elements in react
[...props.ui.languages].forEach(function (language, i) {
const el = document.createElement('li')
el.value = language.languageCode
el.innerHTML = language.name
el.className = "item"
el.addEventListener("click", function(e) {
e.stopPropagation()
})
listContainer.appendChild(el)
})

只需使用 jsx 发出标记:

// within render method
[...props.ui.languages].map((language) => (
<li key={language} onclick={...}>{language}</li>
))

当你这样做时:

// this sets onClick to undefined because openMenu doesn't return anything
onClick={openMenu(this)}

您正在将 onclick 处理程序设置为 openMenu(this)返回值,它是未定义 因为 openMenu 不返回任何东西。

再次声明,不要操纵 DOM。而不是:

e.parentElement.classList.add('open')

使用setState跟踪菜单是否打开:

this.setState({open: true});

然后相应地渲染:

const {open} = this.state;
<div className={open ? 'menu open' : 'menu'}>
...
</div>

(有像 clsx 这样的包可以帮助编写类名;我在这里手动发出 menu open 以保持示例简单。)

关于javascript - 使用点击处理程序构建动态菜单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58161809/

27 4 0