相信像下列的输入框需求,在前端开发的时候很容易遇到
菜鸟前端的第一直觉大概就会想要这样写... 把icon的部分直接放在 <input>
里面
<input> <svg/></input>
如果运气好一点,你写的是直接的html的话,会发现贴心的浏览器帮你变成这样
但是运气不好的话,或是写的是React的JSX的话,就会收到以下警讯,然后什么东西都没跑出来
Uncaught Error: input is a void element tag and must neither have
children
nor usedangerouslySetInnerHTML
.
简单来说,<input>
里面不能放子元素!
好der,所以到底该怎么做呢?
除了直接使用Boostrap、Semantic或Material提供的样板之外
其实HTML应该要拆成这样才对:
这边附上纯HTML的写法与使用React Hook 和Function Component的写法!
纯HTML写法
<div style=" width: 200px; height: 30px; background: #FaFaFa 0% 0% no-repeat padding-box; border: 1px solid #989898; border-radius: 2px; padding: 0px; display: flex; align-items: center; "> <input style=" border: none; outline: none; background: #FaFaFa 0% 0% padding-box; margin: 0px 0px 0px 10px; padding: 0px; width: 162px; " /> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-search" viewBox="0 0 16 16"><path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"></path></svg></div>
React写法
export function MySearchBar(){ const [searchBarValue, setSearchBarValue] = useState(''); function searchBarInputChangeHandler(event: React.ChangeEvent<HTMLInputElement>): void { setSearchBarValue(event.target.value); } const searchBarDivStyle: CSSProperties = { width: '200px', height: '30px', background: '#FaFaFa 0% 0% no-repeat padding-box', border: '1px solid #989898', borderRadius: '2px', padding: '0px', display: 'flex', alignItems: 'center', } const searchBarInputStyle: CSSProperties = { border: 'none', outline: 'none', background: '#FaFaFa 0% 0% no-repeat padding-box', margin: '0px 0px 0px 10px', padding: '0px', width: '162px' } return ( <div style={searchBarDivStyle}> <input style={searchBarInputStylr} value={searchBarValue} onChange={(event) => { searchBarInputChangeHandler(event); }} /> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-search" viewBox="0 0 16 16"><path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"></path></svg> </div> );}
小结
<input>
内不管是要包Icon,还是包按钮
都可以用<div>
+CSS包装的方式来达成,也就是
<div>
:border: 1px solid #989898; // 边框
border-radius: 2px; // 圆角
background: #FaFaFa; // 背景色
display: flex; // 方便内容可以用align-items定位
align-items: center; // 内容物置中内层
<input>
:border: none // 不要有任何边框
outline: none // input被foucs时不要有周围的蓝框
background: #FaFaFa; // 与外层一致的背景色内层 icon:
/* 看高兴怎么放、放哪里 */
假如还是不想自己刻,还是可以参考现成工具:
Bootstrap: https://getbootstrap.com/docs/4.0/components/input-group/
Semantic-UI: https://react.semantic-ui.com/elements/input/#input-example-action
Material-UI: https://material-ui.com/components/text-fields/
以上!