iT邦幫忙

0

【前端 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/

以上!


尚未有邦友留言

立即登入留言