書籍完整目錄javascript
在這一節中,主要的討論範圍爲 React 與 DOM 相關的處理,包括:html
如何獲取 DOM 元素前端
如何作事件響應處理java
表單處理react
style 屬性git
這節講述事後,咱們將會爲 TODO 應用添加完整的事件響應,包括新增,刪除,標記完成等。github
上一節咱們已經講過組件的生命週期,DOM 真正被添加到 HTML 中的 hook 爲web
componentDidMountsegmentfault
componentDidUpdate數組
在這兩個 hook 函數中, 咱們能夠獲取真正的 DOM 元素,React 提供的獲取方法兩種方式
經過 ReactDOM 提供的 findDOMNode 方法, 傳入參數我組件實例,eg
var MyComponent = React.createClass({ render: function() { return <div> .... </div> }, componentDidMount: function() { var $root = ReactDOM.findDOMNode(this); console.log($root); } })
須要注意的是此方法不能應用到無狀態組件上
上面的方法只能獲取到 root 元素,那若是個人 DOM 有不少層級,我想獲取一個子級的元素呢?
React 提供了 ref 屬性來實現這種需求。
每一個組件實例都有一個 this.refs
屬性,會自動引用全部包含 ref 屬性組件的 DOM, eg:
var MyComponent = React.createClass({ render: function() { return <div> <button ref="btn">...</button> <a href="" ref="link"></a> </div> }, componentDidMount: function() { var $btn = this.refs.btn; var $link = this.refs.link; console.log($btn, $link); } })
在 React 中綁定事件的方式很簡單,只須要在元素中添加事件名稱的屬性已經對應的處理函數,如:
var MyComponent = React.creatClass({ render: function() { return <div> <button onClick={this.onClick}>Click Me</button> </div> }, onClick: function() { console.log('click me'); } });
事件名稱和其餘屬性名稱同樣,服從駝峯式命名。
在 React 中, 事件的處理由其內部本身實現的事件系統完成,觸發的事件都叫作 合成事件(SyntheticEvent),事件系統對瀏覽器作了兼容,其提供的 API 與原生的事件無異。
boolean bubbles boolean cancelable DOMEventTarget currentTarget boolean defaultPrevented number eventPhase boolean isTrusted DOMEvent nativeEvent void preventDefault() boolean isDefaultPrevented() void stopPropagation() boolean isPropagationStopped() DOMEventTarget target number timeStamp string type
和原生事件的區別在於,事件不能異步話,如:
function onClick(event) { console.log(event); // => nullified object. console.log(event.type); // => "click" var eventType = event.type; // => "click" setTimeout(function() { console.log(event.type); // => null console.log(eventType); // => "click" }, 0); this.setState({clickEvent: event}); // Won't work. this.state.clickEvent will only contain null values. this.setState({eventType: event.type}); // You can still export event properties. }
緣由是在事件系統的內部實現當中, 一個事件對象可能會被重用(也就是事件作了池化 Pooling)。當一個事件響應函數執行事後,事件的屬性被設置爲 null, 若是想用保持事件的值的話,能夠調用
event.persist()
這樣,屬性會被保留,而且事件也會被從池中取出。
在 DOM2.0 事件分爲捕獲階段和冒泡階段,React 中一般咱們註冊的事件爲冒泡事件,若是要註冊捕獲階段的事件,能夠在事件名稱後加 Capture 如:
onClick onClickCapture
粘貼板事件 { 事件名稱:onCopy onCut onPaste 屬性:DOMDataTransfer clipboardData } 編輯事件 { 事件名稱:onCompositionEnd onCompositionStart onCompositionUpdate 屬性:string data } 鍵盤事件 { 事件名稱:onKeyDown onKeyPress onKeyUp 屬性: { boolean altKey number charCode boolean ctrlKey boolean getModifierState(key) string key number keyCode string locale number location boolean metaKey boolean repeat boolean shiftKey number which } } // 焦點事件除了表單元素之外,能夠應用到全部元素中 焦點事件 { 名稱:onFocus onBlur 屬性:DOMEventTarget relatedTarget } 表單事件 { 名稱:onChange onInput onSubmit } 鼠標事件 { 名稱:{ onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp } 屬性:{ boolean altKey number button number buttons number clientX number clientY boolean ctrlKey boolean getModifierState(key) boolean metaKey number pageX number pageY DOMEventTarget relatedTarget number screenX number screenY boolean shiftKey } } 選擇事件 { 名稱:onSelect } 觸摸事件 { 名稱:onTouchCancel onTouchEnd onTouchMove onTouchStart 屬性:{ boolean altKey DOMTouchList changedTouches boolean ctrlKey boolean getModifierState(key) boolean metaKey boolean shiftKey DOMTouchList targetTouches DOMTouchList touches } } UI 事件 { 名稱:onScroll 屬性:{ number detail DOMAbstractView view } } 滾輪事件 { 名稱:onWheel 屬性:{ number deltaMode number deltaX number deltaY number deltaZ } } 媒體事件 { 名稱:{ onAbort onCanPlay onCanPlayThrough onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting } } 圖像事件 { 名稱:onLoad onError } 動畫事件 { 名稱:onAnimationStart onAnimationEnd onAnimationIteration 屬性:{ string animationName string pseudoElement float elapsedTime } } 漸變事件 { 名稱:onTransitionEnd 屬性: { string propertyName string pseudoElement float elapsedTime } }
在 React 中比較特殊的事件是表單事件,大多數組件都是經過屬性和狀態來決定的,可是表單組件如 input
, select
, option
這些組件的狀態用戶能夠修改,在 React 中會特殊處理這些組件的事件。
和普通 HTML 中的 onChange 事件不一樣, 在原生組件中,只有 input 元素失去焦點纔會觸發 onChange 事件, 在 React 中,只要元素的值被修改就會觸發 onChange 事件。
var MyComponent = React.createClass({ getInitialState: function() { return { value: '' } }, render: function() { return <div onChange={this.onChangeBubble}> <input value={this.state.value} onChange={this.onChange}/> </div> }, onChange: function(ev) { console.log('change: ' + ev.target.value); this.setState({ value: ev.target.value }); }, // onChange 事件支持全部組件,能夠被用於監聽冒泡事件 onChangeBubble: function(ev) { console.log('bubble onChange event', + ev.target.value); } })
表單組件中能被用戶修改的屬性叫交互屬性,包括:
value
=> <input> 和 <select> 組件
checked
=> <input type="checkbox|radio">
selected
=> <opiton>
在 HTML 中,textarea 的值是像以下定義的:
<textarea name="" id="" cols="30" rows="10"> some value </textarea>
而在 React 中, TextArea 的使用方式同 input 組件,使用 value 來設置值
var MyComponent = function() { render: function() { return <div> <textarea value={...} onChange={...}/> </div> } }
在 React 中 select 組件支持 value 值,value 值還支持多選
<select value="B"> <option value="A">Apple</option> <option value="B">Banana</option> <option value="C">Cranberry</option> </select> <select multiple={true} value={['B', 'C']}> <option value="A">Apple</option> <option value="B">Banana</option> <option value="C">Cranberry</option> </select>
在 React 中表單組件可分爲兩類,受控與非受控組件,受控組件是包含了 value 值的,如:
render: function() { return <input type="text" value="....."/> }
爲何叫受控組件? 由於這個時候用戶不能修改 input 的值, input 的值永遠是 value 固定了的值。
若是去掉 value 屬性,那麼就能夠輸入值了。
那如何修改受控組件的值呢? 如上面的例子中, 添加 onChange 事件,事件內修改 value 屬性,value 屬性的值會被設置到組件的 value 中。
對應受控組件,也有非受控組件,那麼那種是非受控組價呢?
沒有 value 值的 input
render: function() { return <input type="text"/> }
那若是想設置默認值呢?
能夠經過 defaultValue 屬性來設置
render: function() { return <input type="text" defaultValue="Default Value"> }
相似的對於 checkbox 有 defaultChecked 屬性
須要注意的是,默認值只適用於第一次渲染,在重渲染階段將不會適用。
checkbox 和 radio 比較特殊, 若是在 onChange 事件中調用了 preventDefault ,那麼瀏覽器不會更新 checked 狀態,即使事實上組件的值已經 checked 或者 unchecked 了 。
eg:
var CheckBox = React.createClass({ getInitialState: function(){ return { checked: false } }, render: function() { return <div> <input type="checkbox" checked={this.state.checked} onChange={this.onChange}/> </div> }, onChange: function(ev) { this.setState({ checked: true }); ev.preventDefault(); } })
這個例子裏邊,checked 雖然更新爲 true ,可是 input 的值 checked 爲 false
那應如何處理 checkbox 呢?
避免調用 ev.preventDefault 就行
在 setTimeout 中處理 checked 的修改
使用 click 事件
在 React 中,能夠直接設置 style 屬性來控制樣式,不過與 HTML 不一樣的是, 傳入的 style 值爲一個對象, 對象的全部 key 都是駝峯式命名,eg:
render: function() { var style = { backgroundColor: 'red', height: 100, width: 100 } return <div style={style}></div> }
其中還能夠看到不一樣的地方時,爲了簡寫寬度高度值,能夠直接設置數字,對應 100 -> 100px
。若是某些屬性不須要添加 px 後綴,React 也會自動去除。
經過屬性值駝峯式的緣由是 DOM 內部訪問 style 也是駝峯式。若是須要添加瀏覽器前綴瑞 -webkit-
、-ms-
大駝峯(除了 ms ), 如:
var divStyle = { WebkitTransition: 'all', // 'W' 是大寫 msTransition: 'all' // 'ms' 爲小寫 };
在之前的前端開發方式是 樣式結構和邏輯要分離, 而如今 React 中卻有不少人推崇 inline 的樣式。 在我看來因人而異,React 的這種模式也能作到樣式模塊化,樣式重用(借用 Js 的特色)。而且由於 React 的實現方式,Inline 樣式的性能甚至比 class 的方式高。
@todo