【前端 HTML/JSX】在Input框内部加上Icon?除了使用Bootstrap、Semantic或Material-UI之外你还可以这麽做

相信像下列的输入框需求,在前端开发的时候很容易遇到
https://ithelp.ithome.com.tw/upload/images/20210308/20135750NExEwy3izI.png

菜鸟前端的第一直觉大概就会想要这样写... 把icon的部分直接放在 <input>里面

<input>
    <svg/>
</input>

如果运气好一点,你写的是直接的html的话,会发现贴心的浏览器帮你变成这样
https://ithelp.ithome.com.tw/upload/images/20210308/20135750ORlMZPzAkT.png

但是运气不好的话,或是写的是React的JSX的话,就会收到以下警讯,然後什麽东西都没跑出来

Uncaught Error: input is a void element tag and must neither have children nor use dangerouslySetInnerHTML.

简单来说,<input>里面不能放子元素!

好der,所以到底该怎麽做呢?
除了直接使用Boostrap、Semantic或Material提供的样板之外
其实HTML应该要拆成这样才对:
https://ithelp.ithome.com.tw/upload/images/20210308/201357508NwYk2SKce.png

这边附上纯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/

以上!


<<:  Day4:Input 输入

>>:  win破解後可以接着使用商业的大量授权吗

[重构倒数第01天] - Vue的表单自动暂存

前言 该系列是为了让看过Vue官方文件或学过Vue但是却不知道怎麽下手去重构现在有的网站而去规画的系...

Ruby解题分享--Length of Last Word && Plus One && Add Binary

周日一堆韩国综艺要看....好忙! 上一篇Maximum Subarray解题,最後答案有稍作修改。...

【Day 28】Hook 08:useCallback

useCallback 如果父元件所传递的 props 包含 Object, 则在元件因状态改变而 ...

新新新手阅读 Angular 文件 - Add Services - Day08

声明一下 这边要声明一下,这一篇其实应该出现在 Day07 的内容之前才对,所以,如果真的有读者 f...

离职倒数25天:我想要在我的社交平台上分享我的创作,而不只是生活

朋友问我辞职後,最想做的第一件事是什麽,我居然回答坚持每天写日记。从肺炎开始用电脑写日记写了一年多了...