传统的MVC是将模板放在其他地方,比如标签或者模板文件,再在JS中通过某种手段引用模板。一下React 官方的看法:
We strongly believe that components are the right way to separate concerns rather than “templates” and “display logic.” We think that markup and the code that generates it are intimately tied together. Additionally, display logic is often very complex and using template languages to express it becomes cumbersome.
翻译:
我们坚信组件是分离关注点的正确方法,而不是“模板”和“显示逻辑”,我们认为标记和生成它的代码紧密地联系在一起。此外,显示逻辑通常非常复杂,使用模板语言来表达它变得很麻烦。
简单来说,React认为组件才是王道,而组件是和模板紧密关联的,组件模板和组件逻辑分离能让问题复杂化了。
所以就有了JSX这种语法,就是为了把HTML模板直接嵌入到JS代码里面,这样就做到了模板和组件相关联,但是JS不支持这种包含HTML语法,所以需要通过工具将JSX编译输出成JS代码才能使用。
因为JSX最终是输出成JS代码来表达的,所以我们可以直接用React提供的这些DOM构建方法来写模板,比如一个JSX写的一个链接:
<a href="http://facebook.github.io/react/">Hello!</a>
用JS代码来写就成这样了:
React.createElement('a',{href:'http://facebook.github.io/react/'},'Hello!')
可以通过React.creatElement
来构造组件的DOM树。第一个参数是标签名,第二个参数是属性对象,第三个参数是子元素。
一个包含子元素的例子:
var child = React.createElement('li',null,'Text Content');
var root = React.createElement('ul',{className:'my-list'},child);
React.render(root,document.body);
对于常见的HTML标签,React已经内置了工厂方法:
var root = React.DOM.ul({className:'my-list'},React.DOM.li(null,'Text Content'));
利用JSX编写DOM结构,可以用原生的HTML标签,也可以直接像普通标签一样引用React组件。这两者约定通过大小来区分,小写的字符串是HTML标签,大写开头的变量是React组件。
使用HTML标签:
import React from 'react';
import {render} from 'react-dom';
var myDivElement = <div className="foo" />;
render(myDivElement,document.getElementById('mountNode'));
使用组件:
import React from 'react';
import {render} from 'react-dom';
import Mycomponent from './MyComponent';
var myElement = <MyComponent someProperty = {true} / >;
render(myElement,document.body);
属性值使用表达式,只要用{} 替换成 “”
// input(JSX)
var person = <Person name = {window.isLoggedIn? window.name:''}/>;
// output(JS)
var person = React.createElement(Person,{name:window.isLoggedIn ? window.name:''});
子组件也可以作为表达式使用:
// input(JSX)
var content = <Container>{window.isLoggedIn ? <Nav/>:<Login/>}</Container>;
// output(JS);
var content = React.createElement(Container,null,window.isLoggedIn?React.createElement(Nav):React.createElement(Login));
在JSX中使用注释也很简单,就是沿用JavaScript,唯一要注意的是在一个组件的子元素位置使用注释要用{}
包起来
var content = (
<Nav>
{ /* 这里是注释内容 */}
<Person
/* multi
line
comment */
name={window.isLoggedIn ? window.name:''} // end of line comment
/>
</Nav>
);
React会将所有要显示到DOM的字符串转义,防止XSS。所以如果JSX中含有转义后的实体字符比如©©
,最后显示到DOM中不会正确显示,因为React自动会把©
中的特殊字符转义了。有几种解决办法:
{['cc',©,'2015']}
<div dangerouslySetInnerHTML = {{__html:'cc &copr;2015'}}/>
如果在JSX中使用的属性不存在与HTML的规范中,这个属性会被忽略。如果要使用自定义属性,可以用data-
前缀。
可访问性属性的前缀 aria-
也是支持的
有时候需要组件设置多个属性,不想一个个写下这些属性,或者有时候也不知道属性名称,这时候spread attributes
的功能就很有用了。
比如:
var props = {}
props.foo = x;
props.bar = y;
var component = <Component {...props} />;
props
对象的属性会被设置成Component
的属性
属性也可以被覆盖:
var props = {foo:'default'};
var component = <Component {...props} foo = {'override'} />;
console.log(component.props.foo); // override
写在后面的属性值会覆盖前面的属性
除了前面提到的class
要写成className
,比较典型的还有:
style
属性接受有CSS属性构成的JS对象onChange
事件表现更接近我们的直觉(不需要onBlur去触发)