1.5 React 与 DOM
在这一节中,主要的讨论范围为 React 与 DOM 相关的处理,包括:
如何获取 DOM 元素
如何做事件响应处理
表单处理
style 属性
如何获取 DOM 元素
如何做事件响应处理
表单处理
style 属性
这节讲述过后,我们将会为 TODO 应用添加完整的事件响应,包括新增,删除,标记完成等。
1.5.1 获取 DOM 元素
上一节我们已经讲过组件的生命周期,DOM 真正被添加到 HTML 中的 hook 为
componentDidMount
componentDidUpdate
在这两个 hook 函数中, 我们可以获取真正的 DOM 元素,React 提供的获取方法两种方式
findDOMNode()
通过 ReactDOM 提供的 findDOMNode 方法, 传入参数我组件实例,eg
var MyComponent = React.createClass({
render: function() {
return <div> .... </div>
},
componentDidMount: function() {
var $root = ReactDOM.findDOMNode(this);
console.log($root);
}
})
需要注意的是此方法不能应用到无状态组件上
Refs
上面的方法只能获取到 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);
}
})
1.5.2 DOM 事件
绑定事件
在 React 中绑定事件的方式很简单,只需要在元素中添加事件名称的属性已经对应的处理函数,如:
var MyComponent = React.creatClass({
render: function() {
return <div><button onClick={this.onClick}>Click Me</button></div>
},
onClick: function() {
console.log('click me');
}
});
事件名称和其他属性名称一样,服从驼峰式命名。
合成事件(SyntheticEvent)
在 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); // => nullconsole.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 如:
onClickonClickCapture
支持事件列表
粘贴板事件 {
事件名称: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
}
}
1.5.3 表单事件
在 React 中比较特殊的事件是表单事件,大多数组件都是通过属性和状态来决定的,但是表单组件如 input
, select
, option
这些组件的状态用户可以修改,在 React 中会特殊处理这些组件的事件。
onChange 事件
和普通 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>
textara
在 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>
}
}
select 组件
在 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
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 事件
1.5.4 style 属性
在 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' 为小写
};
为什么要用 inline 的样式?
在以前的前端开发方式是 样式结构和逻辑要分离, 而现在 React 中却有很多人推崇 inline 的样式。 在我看来因人而异,React 的这种模式也能做到样式模块化,样式重用(借用 Js 的特点)。并且因为 React 的实现方式,Inline 样式的性能甚至比 class 的方式高。
1.5.5 实例练习:完整功能的 TODO 应用
1.5 React 与 DOM的更多相关文章
- React虚拟DOM浅析
在Web开发中,需要将数据的变化实时反映到UI上,这时就需要对DOM进行操作,但是复杂或频繁的DOM操作通常是性能瓶颈产生的原因,为此,React引入了虚拟DOM(Virtual DOM)的机制. 什 ...
- React虚拟DOM具体实现——利用节点json描述还原dom结构
前两天,帮朋友解决一个问题: ajax请求得到的数据,是一个对象数组,每个对象中,具有三个属性,parentId,id,name,然后根据这个数据生成对应的结构. 刚好最近在看React,并且了解到其 ...
- react虚拟dom diff算法
react虚拟dom:依据diff算法 前端:更新状态.更新视图:所以前端页面的性能问题主要是由Dom操作引起的,解放Dom操作复杂性 刻不容缓 因为:Dom渲染慢,而JS解析编译相对非常非常非常快! ...
- React/虚拟DOM
在说虚拟DOM之前,先来一个引子,从输入url到展现出整个页面都有哪些过程? 1.输入网址 2.DNS解析 3.建立tcp连接 4.客户端发送HTPP请求 5.服务器处理请求 6.服务器响应请求 7. ...
- 初识React,Virutal DOM, State以及生命周期
这是React分类下的第一篇文章,是在了解了一些基本面后,看Tyler文章,边看边理解边写的. React可以看做是MVC中的V,关注的是视图层.React的组件就像Angular的Directive ...
- React 点击删除列表中对应项(React 获取DOM中自定义属性)
点击删除按钮,删除列表中对应项本来是React比较基础的应用,可是应用情况变得复杂了以后,我还真想了一会儿才搞定. 简化一下应用场景:点击新增按钮,增加一条输入框,点击输入框旁边的按钮,删除该输入框( ...
- React 虚拟 DOM 的差异检测机制
React 使用虚拟 DOM 将计算好之后的更新发送到真实的 DOM 树上,减少了频繁操作真实 DOM 的时间消耗,但将成本转移到了 JavaScript 中,因为要计算新旧 DOM 树的差异嘛.所以 ...
- 关于react虚拟DOM的研究
1.传统的前端是这样的,我在学校也都是这样做的,html(jsp)主要负责提供所有的DOM节点,而javascript负责动态效果,比如按钮点击,图片轮播等,这样的话javascript如何组织结构是 ...
- react系列一,react虚拟dom如何转成真实的dom
react,想必作为前端开发一定不陌生,组件化以及虚拟dom使得react成为最受欢迎额前端框架之一.我们知道react是基于虚拟dom的,但是什么是虚拟dom呢,其实就是一组js对象,那么我们今天就 ...
随机推荐
- (转)MAVEN的安装和Myeclipse+maven的配置和使用
转:https://blog.csdn.net/shikongshengzhu/article/details/51779159 MAVEN的安装和Myeclipse+maven的配置和使用 步骤如下 ...
- Apache2.2+mod_encoding解决URL中文编码问题
我们经常在论坛上看到这样的求救贴: 为什么我看不了网站上中文文件名的文件?这时一定会有好心的大侠告诉说,到IE6的工具,Internet选项, 高级里,把"总是以UTF-8发送URL&quo ...
- HDU 1724 Ellipse (自适应辛普森积分)
题目链接:HDU 1724 Problem Description Math is important!! Many students failed in 2+2's mathematical tes ...
- shell 字符串匹配变量(只取数字或者取固定字符串)
var1=abc3559 #想要获得3559 操作: var1_key=`echo $var1 | tr -cd "[0-9]"` https://www.cnblogs.co ...
- 巧妙的使用jmeter来发送json格式数据
1. header-manager 修改content-type值. 如果不修改该值, 则默认会是urlencode的数据格式(例如a=5&b=6). 修改为json后,会告诉服务器,发送的数 ...
- 将excle表中得数据生成insert语句插入到数据库中
第一步:输入公式 第二步:拽住右下角得+往下拖拽
- datepicker时间选择弹窗
准备工作 首先请到jqueryui.com官网下载datepicker插件代码,注意官网提供了整个jquery ui的所有插件下载,但是您可以选择其中几个用到的插件下载,本文中只用到datepicke ...
- MySQL中的关系
关系 将实体与实体的关系,反应到最终数据库表的设计中来.将关系分为三种:一对一,一对多(多对一)和多对多.所有的关系都是指的是表与表之间的关系. 一对一 一张表中的一条记录一定只能与另外一张表的一条记 ...
- MySQL用户管理及权限设置
mysql 用户管理和权限设置 用户管理 mysql>use mysql; 查看 mysql> select host,user,password from user ; 创建 mysql ...
- Linux部分常用命令详解(二)
date 命令详解 date命令可以按照指定格式显示日期,只键入date则以默认格式显示当前时间 例如: 如果需要以指定的格式显示日期,可以使用“+”开头的字符串指定其格式,详细格式如下: %n : ...