Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
Flutter系列的文章我會持續更新一個月左右,力求利用1個月帶大家入門Flutter,抓住這波技術風口,歡迎大家關注。同時如果覺得這里代碼排版不是很舒服的讀者可以關注我的微信公眾號“IT工匠”,我會同步更新,另外微信公眾號上還有很多互聯網必備資源(涉及算法、數據結構、java、深度學習、計算機網絡、python、Android等互聯網技術資料),歡迎大家關注、交流。
文的主要內容:
Flutter中按照是否自身可直接響應用戶交互可以將Widget分為兩類:
由于第一類比較簡單,本文重點介紹一下第二類,即如何為非交互性(不能直接響應用戶交互)的Widget添加交互性, 具體來說,我們將通過創建一個自定義的Statful Widget來讓Icon具有交互性。
在上一篇文章中我們介紹了如何構建一個下面這樣的UI頁面:
當這個app第一次運行的時候那個星星是紅色的,代表這個屏幕中展示的那個圖片被用戶點擊了喜歡,星星后面的數字47代表一共有47個用戶點擊了喜歡。本文將實現,點擊星星后移除喜歡狀態,用空心星星替換實心星星并減少星星后面的計數。 再次點擊空心星星代表添加喜歡,會繪制一顆實心的星星并增加星星后的數字。
要實現此功能,您將創建一個包含星星和計數的自定義Widget, 點擊星星會更改兩個子Widget的狀態,因此自定義的Widget應該同時管理這兩個子Widget(星星和計數)。
首先我將會介紹一點前備知識,如果你只對最終的代碼實現感興趣,你可以直接跳到第2步:創建StatefulWidget的子類,如果你想嘗試其他的管理狀態的方法,可以直接跳到管理狀態一節。
一個Widget要么是有狀態(stateful)的,要么是無狀態(stateless)的,如果一個Widget是可改變的,比如當用戶與其交互的時候其會產生變化,這個Widget就是有狀態的(stateful)。
一個無狀態(stateless)的Widget是永遠不會發生改變的,Icon、IconButton、Text都是典型的無狀態的Widget,無狀態(stateless)的Widget都是StatelessWidget的子類。
一個有狀態(stateful)的Widget是動態的,比如它可以更改其外觀以響應用戶交互或接收數據時觸發的事件。CheckBox、Radio、Slider、InkWell、Form、TextField都是典型的有狀態的Widget,有狀態(stateful)的Widget都是StatefulWidget的子類。
Widget的狀態都是保存在State對象中的,從外觀上分析小部件的狀態。 狀態由可以更改的值組成,例如滑塊(slider)的當前值、是否選中復選框(CheckBox)。 當Widget的狀態發生變化時,State對象調用會setState()方法來告訴框架重繪該Widget。
明確幾點概念:
本節將創建一個自定義的有狀態(Stateful)的Widget,我們將用我們自定義的包含一個IconButton和一個Text的Widget來替代原有的紅色星星Widget和計數Widget。
實現一個自定義的Widget需要創建2個類:
我們通過簡單的幾步來構建一個名為FavoriteWidget的自定義Widget:
第1步:決定由那個對象來管理Widget的狀態(State)
Widget的狀態(State)可以有多種管理方式,在此處由于切換星星的狀態(實心還是空心)是一個獨立的操作,不會影響父Widget或UI的其余部分,所以我們讓Widget自己管理自己的狀態(State)。
關于詳細的狀態管理的內容,我會在后面的管理狀態一節介紹。
<span id="subclass-statefulWidget">第2步:創建StatefulWidget的子類</span>
由于第1步我們已經決定了FavoriteWidget自己管理自己的狀態(State),所以我們應該重寫createState()方法來創建一個State對象。Flutter框架會在構建Widget的時候調用對應Widget的createState()方法。在這個例子中,我們應該在createState()方法中返回一個我們將在下一步定義的_FavoriteWidgetState類的實例對象:
class FavoriteWidget extends StatefulWidget { @override _FavoriteWidgetState createState() => _FavoriteWidgetState(); }
注意:這里的_開頭指的是定義的對應類是私有的。
第3步:創建State類的子類
我們定義一個_FavoriteWidgetState類來存儲會在Widget不同生命周期變化的數據,當app第一次運行的時候,UI界面應該展示紅色的實心星星,代表當前已經選擇了”喜歡”狀態,并且傍邊展示的文字為”41”,我們本別使用bool _isFavorited和int _favoriteCount變量來存儲這兩個狀態:
class _FavoriteWidgetState extends State<FavoriteWidget> { bool _isFavorited = true; int _favoriteCount = 41; // ··· }
_FavoriteWidgetState類同樣也定義了一個build()方法,在該方法中創建一個Row(行),Row中包含有一個Iconbutton和一個Text,我們使用Iconbutton而不是Icon的原因是IconButton有onPressed屬性,我們可以通過這個onPressed屬性定義處理點擊事件的回調函數(_toggleFavorite),我們將在后面具體定義這個_toggleFavorite函數:
class _FavoriteWidgetState extends State<FavoriteWidget> { // ··· @override Widget build(BuildContext context) { return Row( mainAxisSize: MainAxisSize.min, children: [ Container( padding: EdgeInsets.all(0), child: IconButton( icon: (_isFavorited ? Icon(Icons.star) : Icon(Icons.star_border)), color: Colors.red[500], onPressed: _toggleFavorite, ), ), SizedBox( width: 18, child: Container( child: Text('$_favoriteCount'), ), ), ], ); } }
注意:我們這里將Text作為子Widget放置在了SizedBox中,并且設置了SizedBox的寬度,這樣做的作用是固定Text的寬度,設想一下,當Text中只顯示1位數字的時候Text的寬度和顯示2位數字的寬度一定是不一樣的,如果不固定Text的寬度,當數字變化的時候就會出現Text寬度發生跳變的情況,導致視覺效果很不好。
當IconButton被點擊的時候將會調用_toggleFavorite()方法,我們在_toggleFavorite()方法中調用setstate()方法并更新狀態,這樣Flutter框架就會知道需要重新繪制當前Widget了,從而達到更新界面的效果:
void _toggleFavorite() { setState(() { if (_isFavorited) { _favoriteCount -= 1; _isFavorited = false; } else { _favoriteCount += 1; _isFavorited = true; } }); }
setState()方法中的代碼邏輯很簡單,首先判斷當前_isFavorited的狀態,然后對_isFavorited和_isFavorited的值進行更新。
第4步:將我們自定義的Stateful Widget加入到Widget樹中
我們應該在app的build()方法中將我們自定義的Stateful Widget加入到Widget 樹中,首先找到原先Icon和Text的位置,然后刪除原來的代碼,加入新的我們創建的Stateful Widget:
Widget titleSection = Container( padding: const EdgeInsets.all(32), child: Row( children: [ Expanded( /*1*/ child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ /*2*/ Container( padding: const EdgeInsets.only(bottom: 8), child: Text( 'Oeschinen Lake Campground', style: TextStyle( fontWeight: FontWeight.bold, ), ), ), Text( 'Kandersteg, Switzerland', style: TextStyle( color: Colors.grey[500], ), ), ], ), ), FavoriteWidget(), ], ), );
然后運行代碼(推薦使用熱更新),可以看到效果圖:
在我們的設計中,到底應該由誰來管理Widget的狀態(State)?是Widget本身?是Widget的父Widget?還是二者共同管理?還是另一個對象來管理? 事實上有不止一種有效的方法可以使你的Widget小部件具有交互性, 作為Widget的設計者,你可以根據預期的Widget的使用方式做出決策。 以下是幾種最常用的管理狀態的方法:
你可能會有疑問,你應該如何決定具體使用哪一種狀態管理方法?這里提供幾個原則供你參考:
如果你不太確定自己的場景屬于以上哪種,可以直接使用父級Widget管理的方法,因為這個方法是通用的。
接下來我將通過創建三個簡單示例(TapboxA,TapboxB和TapboxC)來舉例說明管理狀態的不同方法。 這幾個示例的工作方式類似: 每個都創建了一個Container,當點擊時,可以在綠色或灰色框之間切換, _active布爾值確定顏色:true代表綠色,false代表灰色。
Widget自己管理自己本身的State
有時,由Widget自己管理自己的狀態可以產生很強大的功能。例如,ListView在其內容的總尺寸超出其最大渲染框的尺寸時會自動進行滾動,這個滾動的狀態是由ListView自己管理的,不需要我們開發人員去手動設置它什么時候應該開始滾動、什么時候應該停止滾動。
我們通過一個示例來進行說明,我們創建一個_TapboxAState類:
代碼如下:
// TapboxA 自己管理自己的狀態 //------------------------- TapboxA ---------------------------------- class TapboxA extends StatefulWidget { TapboxA({Key key}) : super(key: key); @override _TapboxAState createState() => _TapboxAState(); } class _TapboxAState extends State<TapboxA> { bool _active = false; void _handleTap() { setState(() { _active = !_active; }); } Widget build(BuildContext context) { return GestureDetector( onTap: _handleTap, child: Container( child: Center( child: Text( _active ? 'Active' : 'Inactive', style: TextStyle(fontSize: 32.0, color: Colors.white), ), ), width: 200.0, height: 200.0, decoration: BoxDecoration( color: _active ? Colors.lightGreen[700] : Colors.grey[600], ), ), ); } } //------------------------- MyApp ---------------------------------- class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', home: Scaffold( appBar: AppBar( title: Text('Flutter Demo'), ), body: Center( child: TapboxA(), ), ), ); } }
運行效果如下圖所示:
Widget的父級Widget管理其State
父Widget管理子Widget狀態的最大用處是在合適的時機通知子Widget進行UI更新。 例如,IconButton允許你將Icon視為可點擊的按鈕, IconButton是一個無狀態的Widget,所以我們應該通過父Widget來確定Iconutton是否已被點擊。
在以下例子中,TapboxB將其狀態回調給父Widget,因為TapboxB不管理任何狀態,所以它是StatelessWidget的子類。
在這個示例中我們應該實現2個類:ParentWidgetState(代表父Widget)、TapboxB(代表子Widget)
ParentWidgetState的主要功能:
TapboxB的主要功能:
代碼實現如下:
// ParentWidget為TapboxB管理狀態. //------------------------ ParentWidget -------------------------------- class ParentWidget extends StatefulWidget { @override _ParentWidgetState createState() => _ParentWidgetState(); } class _ParentWidgetState extends State<ParentWidget> { bool _active = false; void _handleTapboxChanged(bool newValue) { setState(() { _active = newValue; }); } @override Widget build(BuildContext context) { return Container( child: TapboxB( active: _active, onChanged: _handleTapboxChanged, ), ); } } //------------------------- TapboxB ---------------------------------- class TapboxB extends StatelessWidget { TapboxB({Key key, this.active: false, @required this.onChanged}) : super(key: key); final bool active; final ValueChanged<bool> onChanged; void _handleTap() { onChanged(!active); } Widget build(BuildContext context) { return GestureDetector( onTap: _handleTap, child: Container( child: Center( child: Text( active ? 'Active' : 'Inactive', style: TextStyle(fontSize: 32.0, color: Colors.white), ), ), width: 200.0, height: 200.0, decoration: BoxDecoration( color: active ? Colors.lightGreen[700] : Colors.grey[600], ), ), ); } }
代碼的運行效果如下:
混合使用前兩種管理方法
對于某些Widget,使用混合的方法管理其狀態很有有意義。 在這種情況下,有狀態(stateful)的Widget和其父Widget分別管理其一部分狀態(State)。
在TapboxC示例中,在點擊時,框周圍會出現深綠色邊框,點擊后,邊框消失,框的顏色也會改變。 TapboxC將其 _active狀態導出到其父Widget,在內部管理只其 _highlight狀態,所以 此示例有兩個State對象,_ParentWidgetState和_TapboxCState:
_ParentWidgetState的功能:
_TapboxCState的功能:
//---------------------------- ParentWidget ---------------------------- class ParentWidget extends StatefulWidget { @override _ParentWidgetState createState() => _ParentWidgetState(); } class _ParentWidgetState extends State<ParentWidget> { bool _active = false; void _handleTapboxChanged(bool newValue) { setState(() { _active = newValue; }); } @override Widget build(BuildContext context) { return Container( child: TapboxC( active: _active, onChanged: _handleTapboxChanged, ), ); } } //----------------------------- TapboxC ------------------------------ class TapboxC extends StatefulWidget { TapboxC({Key key, this.active: false, @required this.onChanged}) : super(key: key); final bool active; final ValueChanged<bool> onChanged; _TapboxCState createState() => _TapboxCState(); } class _TapboxCState extends State<TapboxC> { bool _highlight = false; void _handleTapDown(TapDownDetails details) { setState(() { _highlight = true; }); } void _handleTapUp(TapUpDetails details) { setState(() { _highlight = false; }); } void _handleTapCancel() { setState(() { _highlight = false; }); } void _handleTap() { widget.onChanged(!widget.active); } Widget build(BuildContext context) { // This example adds a green border on tap down. // On tap up, the square changes to the opposite state. return GestureDetector( onTapDown: _handleTapDown, // Handle the tap events in the order that onTapUp: _handleTapUp, // they occur: down, up, tap, cancel onTap: _handleTap, onTapCancel: _handleTapCancel, child: Container( child: Center( child: Text(widget.active ? 'Active' : 'Inactive', style: TextStyle(fontSize: 32.0, color: Colors.white)), ), width: 200.0, height: 200.0, decoration: BoxDecoration( color: widget.active ? Colors.lightGreen[700] : Colors.grey[600], border: _highlight ? Border.all( color: Colors.teal[700], width: 10.0, ) : null, ), ), ); } }
運行效果如下所示:
替代實現可能已將高亮狀態導出到父級,同時保持活動狀態為內部,但如果您要求某人使用該分接框,他們可能會抱怨它沒有多大意義。 開發人員關心該框是否處于活動狀態。 開發人員可能并不關心如何管理突出顯示,并且更喜歡點按框處理這些細節。
Flutter提供了很多按鈕和類似的交互式Widget。 這些Widget中的大多數都實現了Material Design準則,該準則定義了一組具有固定用戶界面的組件。
如果您愿意,可以使用GestureDetector在任何自定義的Widget中構建交互性。 您可以在管理狀態一節中找到GestureDetector的使用示例。
提示:Flutter還提供了一些IOS風格的Widget,稱之為Cupertino,具體地址:https://api.flutter.dev/flutter/cupertino/cupertino-library.html
當您需要交互性時,最簡單的方法是使用Flutter已經給我提供好的Widget,下面是一個部分列表:
標準庫中的Widget
Material庫中的Widget
單標簽
網頁(程序)如果要和用戶產生互動,則必須借助一定的中介,這個中介一般是:文本輸入框、按鈕、多選框、單選框。而表單則是這些中介和放置這些中介的空間(<form action=”” methon=””></form>)。
在網頁中,這些文本輸入框、按鈕等等必須放置在由<form></form>這個標簽所定義的空間中,否則沒有實際意義。所以,由<form></form>標簽所定義的空間就是表單存在的空間。
【各種輸入類型】
呈現結果
姓名:
原始碼
<form action=http://www.baidu.com/nameproject.aspmethon=”post”>
姓名:<input type="text" name="name" size="20">
</form>
它有下列可設定之屬性:
呈現結果
性別:男 女
原始碼
<form>
性別:
男 <input type="radio" name="sex" value="boy">
女 <input type="radio" name="sex" value="girl">
</form>
它有下列可設定之屬性:
呈現結果
喜好: 電影 看書
原始碼
<form>
喜好:
<input type="checkbox" name="sex" value="movie">電影
<input type="checkbox" name="sex" value="book">看書
</form>
它有下列可設定之屬性:
呈現結果
請輸入密碼:
原始碼
<form>
請輸入密碼:<input type="password" name="input">
</form>
它有下列可設定之屬性:
呈現結果
原始碼
<form>
<input type="submit" value="送出資料">
<input type="reset" value="重新填寫">
</form>
它有下列可設定之屬性:
呈現結果
請按下按鈕:
原始碼
<form>
請按下按鈕:<input type="button" name="ok" value="我同意">
</form>
它有下列可設定之屬性:
呈現結果
隱藏欄位:
原始碼
<form>
隱藏欄位:<input type="hidden" name="nosee" value="看不到">
</form>
它有下列可設定之屬性:
【大量文字輸入元件】
呈現結果
請輸入您的意見:
原始碼
<form>
請輸入您的意見:<br>
<textarea name="talk" cols="20" rows="3"></textarea>
</form>
它有下列可設定之屬性:
【下拉式選單】
呈現結果
您喜歡看書嗎?:
非常喜歡
還算喜歡
不太喜歡
非常討厭
原始碼
<form>
您喜歡看書嗎?:
<select name="like">
<option value="非常喜歡">非常喜歡
<option value="還算喜歡">還算喜歡
<option value="不太喜歡">不太喜歡
<option value="非常討厭">非常討厭
</select>
</form>
它有下列可設定之屬性:
multiple,是設定此一欄位為復選,可以一次選好幾個選項。
....................................................................
我的微信公眾號:UI嚴選 —越努力,越幸運
TMl 的標簽可以分為單個標簽和成對標簽。
單個標簽:html4 規定單個標簽要有一個 / 表示結尾, html5 則不用
<!--單個標簽-->
<meta>
<!--成對標簽 -->
<div></div>
以下是HTMl中常用的一些標簽
div 標簽 主要用來將相關的內容組合到一塊,就像菜市場把各個蔬菜分成不同種類區分擺放是一個道理。
div 是最常見也是比較重要的標簽,網頁布局中經常使用的一類標簽。通常布局被稱為 DIV + CSS 布局
<div>
div 就是一個分類的存儲箱子
</div>
p標簽表示段落, 在網頁文字中應用的比較多
<!--段落和段落間會換行-->
<p>第一段</p>
<p>第二段</p>
h標簽分為六個
標簽 | 語義 |
h1 | 一級標題 |
h2 | 二級標題 |
h3 | 三級標題 |
h4 | 四級標題 |
h5 | 五級標題 |
h6 | 六級標題 |
引用標題標簽后,字體會加粗、字號一會變大
無序標簽是沒有顯示順序的列表,無序列表前面通常會有一個“小點”, 這個小點可以用type屬性控制。其中有三個展示方式(不過這種方式比較固定,不夠靈活和美觀, 已經被CSS的效果代替),如下:
值(type屬性) | 描述 |
disc | 默認值,實心圓 |
circle | 空心圓 |
square | 實心方框 |
舉例:
<!--ul標簽內部只能放置li標簽-->
<!--li標簽內部可以放其他的標簽-->
<ul type=">
<li>無序列表元素1</li> <!--列表項-->
<li>無序列表元素2</li>
</ul>
實心圓
<ul type="disc">
<li>西紅柿</li>
<li>黃瓜</li>
</ul>
空心圓
<ul type="circle">
<li>西紅柿</li>
<li>黃瓜</li>
</ul>
實心方框
<ul type="square">
<li>西紅柿</li>
<li>黃瓜</li>
</ul>
type屬性值 | 意義 |
a | 小寫英文字母編號 |
A | 大寫英文字母編號 |
i | 小寫羅馬數字編號 |
I | 大寫羅馬數字編號 |
1 | 數字編號(默認) |
有序列表, 從2開始
<ol start="2">
<li>元素1</li>
<li>元素2</li>
</ol>
小寫字母表示
<ol type="a">
<li>元素1</li>
<li>元素2</li>
<li>元素3</li>
</ol>
倒敘
<ol reversed>
<li>元素1</li>
<li>元素2</li>
<li>元素3</li>
</ol>
dl標簽表示自定義列表
dt表示數據項,dd表示數據定義, dd是dt標簽的解釋
<dl>
<dt>西紅柿</dt>
<dd>紅、酸</dd>
<dt>黃瓜</dt>
<dd>綠、澀</dd>
</dl>
img 用來插入圖片,包括但不限于以下圖片格式
圖片格式 | 備注 |
.jpg、.jpeg | 通常用于照片,是一種有損壓縮格式 |
.png | 通常用于logo、背景,支持透明和半透明。便攜式網絡圖像 |
.svg | 矢量圖片 |
<!-- src(source)屬性, 圖片地址,可以為相對路徑,也可以為絕對路徑-->
<!-- alt 如果遇到圖片無法加載的情況,網頁上會展示 alt的 值 -->
<!-- width 和 height 表示 寬和高, 如果只設置一個, 那么另外一個就會跟著成比例縮放-->
<img src="./images/images.jpg" alt="星期一" width="120" height="20">
用a標簽來制作超級鏈接
<!-- href 屬性 表示 其他頁面的鏈接,支持相對路徑和絕對路徑,還可以鏈接到其它網站 -->
<!--target 屬性表示 打開其他鏈接的方式-->
<!-- title 屬性表示 鏈接的標題, 當鼠標移動到鏈接上,會展示出來-->
<a href="http://www.baidu.com" target="blank" title="文字標題">百度</a>
<!--也可以用a標簽作為錨點 錨點可以是本頁面的錨點,也可以是其他頁面的錨點-->
<h1 id="title">頭部標題</h1>
... 此處省略一些代碼
<a href="#title">返回標題</a>
<!--下載鏈接,指向 doc, zip, zip等文件格式時,a標簽將成為自動下載鏈接-->
<a href="./download/halou.zip">發郵件</a>
<!-- mailto:前綴的鏈接是郵件鏈接,系統將自動打開email相關軟件-->
<a href="mailto:halouworld@126.com">發郵件</a>
<!-- tel: 前綴鏈接是電話鏈接,系統將自動打開撥號鍵-->
<a href="tel:11111111111">打開撥號鍵盤</a>
audio標簽用來插入音頻標簽
<!--添加 controls 后才會顯示 播放控件-->
<!--常用音頻格式 mp3 和 ogg格式-->
<!--autoplay 自動播放屬性-->
<!--loop 屬性表示循環播放-->
<audio controls src="./video/demo.mp3">
您的瀏覽器不支持 audio標簽,請升級
</audio>
<audio controls src="./video/demo.mp3" autoplay loop>
您的瀏覽器不支持 audio標簽,請升級
</audio>
video 標簽用于插入一段視頻
<!--有的視頻不能播放 ,詳見 https://blog.csdn.net/weixin_34272308/article/details/94614657 -->
<!-- controls 顯示視頻播放控件 -->
<!-- autoplay 自動播放 -->
<!-- loop 循環播放 -->
<!-- 常見的 視頻格式 mp4 ogv webm 等-->
<video controls autoplay loop src="./video/5-4 RDB2.mp4" >
您的瀏覽器不支持 video標簽,請升級
</video>
以前的區塊標簽只有div,現在為了更好的方便搜索引擎抓取網站,因此有了以下語義更加明確的區塊標簽
<section> | 文檔的區域,比div語義上還要大一點 |
<header> | 頁頭 |
<main> | 網頁核心部分 |
<footer> | 頁腳 |
表單用來收集信息并且可以完成和后端的數據傳輸
表單中大致可以分為三種標簽
一些表單的示例
<!--action 表示要提交到后端的網址-->
<!--method 表示表單提交的方式,通常有 get 、 post 、put、delete等-->
<form action="/save" meththo="post"></form>
<!--<form> 標簽中 input 文本框 type="text" 表示文本框-->
<!-- value 表示文本框中的值 -->
<!--planceholder表示提示文字,在沒任何輸入值的情況下,作為提示信息-->
<!--disabled 表示禁用-->
<input type="text" value="123" planceholder="提示文字" disabled>
<!---單選按鈕,name相等,表示選擇了一個,另一個就不能選擇了-->
<!--checked 表示默認被選中-->
<!-- value 屬性表示要提交到后端服務器的值-->
<input type="radio" name="radio_group" checked>
<input type="radio" name="radio_group">
<label>
<input type="radio" name="sex"> 男
</label>
<label>
<input type="radio" name="sex"> 女
</label>
<!--html4 中的標簽 通過for 屬性 和 其他標簽的id屬性進行綁定-->
<input type="radio" name="sex" id="nan">
<label for="nan">男</label>
<input type="radio" name="sex" id="nv">
<label for="nv">女</label>
<!--復選框 type="checkbox" 同一組的的復選框,name值應該相同 ,復選框也有value值, 用于向服務器提交數據-->
<input type="checkbox" name="hobby" value="soccer" > 足球
<input type="checkbox" name="hobby" value="basket" > 籃球
<!--密碼框-->
<input type="password" placeholder="請輸入密碼">
<!-- 下拉菜單 -->
<select>
<option value="alipay">支付寶</option>
<option value="wxpay">微信支付</option>
</select>
<!--多文本框 rows 和 clos 分別用于設置 行數 和 列數-->
<textarea rows="3" cols="5"></textarea>
<!--三種按鈕 submit 提交按鈕 button 普通按鈕 可以簡寫為 <button></button> reset 按鈕 重置按鈕-->
<input type="button" value="普通按鈕">
<input type="reset" value="重置按鈕">
<input type="submit" value="提交表單">
<!--像 email 和 url 等格式,如果點擊提交按鈕,不符合格式,會有提示-->
<form>
日期空間: <input type="date"> <br/>
時間空間: <input type="time"> <br/>
日期時間空間 <input type="datetime-local"> <br/>
文件:<input type="file"> <br/> <br/>
數字控件: <input type="number"> <br/>
拖拽條: <input type="range"> <br/>
搜索框: <input type="search"> <br/>
網址控件: <input type="url"> <br/>
郵箱控件: <input type="email" >
<input type="submit" value="提交">
</form>
<!-- datalist 備選項示例 -->
<input type="text" list="province">
<datalist id="province">
<option value="陜西"></option>
<option value="山西"></option>
<option value="河北"></option>
<option value="山東"></option>
</datalist>
可以用html渲染表格
<!--表格示例-->
<table border="1">
<caption>我是標題</caption>
<tr>
<th>第一列標題</th>
<th>第二列標題</th>
</tr>
<tr>
<td>第一行第一列</td>
<td>第一行第二列</td>
</tr>
<tr>
<td>第二行第一列</td>
<td>第二行第二列</td>
</tr>
</table>
<!--跨列示例-->
<table border="1">
<caption>我是標題</caption>
<tr>
<th>第一列標題</th>
<th>第二列標題</th>
</tr>
<tr>
<td colspan="2">跨兩行</td>
</tr>
<tr>
<td>第二行第一列</td>
<td>第二行第二列</td>
</tr>
</table>
<!--跨行示例-->
<table border="1">
<caption>我是標題</caption>
<tr>
<th>第一列標題</th>
<th>第二列標題</th>
</tr>
<tr>
<td rowspan="2">第一行第一列</td>
<td>第一行第二列</td>
</tr>
<tr>
<td>第二行第二列</td>
</tr>
<tr>
<td>第三行第一列</td>
<td>第三行第二列</td>
</tr>
</table>
*請認真填寫需求信息,我們會在24小時內與您取得聯系。