JSX 是一个语法扩展,可以让你在 JavaScript 中直接使用 HTML 语法。它不是任何 JavaScript 标准的一部分,也不是构建应用所必需的,你可以根据你的喜好来决定是否使用它。
var MyComponent = {
view: function() {
return m("main", [
m("h1", "Hello world"),
])
}
}
// 使用 JSX 可以写成:
var MyComponent = {
view: function() {
return (
<main>
<h1>Hello world</h1>
</main>
)
}
}
当使用 JSX 语法时,可以使用大括号在 JSX 中插入 JavaScript 表达式:
var greeting = "Hello"
var url = "http://google.com"
var link = <a href={url}>{greeting + "!"}</a>
// 以上代码将生成 <a href="http://google.com">Hello</a>
可以通过首字母大写的组件名来调用组件:
m.mount(document.body, <MyComponent />)
// 等效于 m.mount(document.body, m(MyComponent))
可以通过 Babel 插件来使用 JSX。
如果你没有使用 Webpack,可以把 Babel 作为一个独立的工具进行使用。
确保你已经安装 Node.js,在项目文件夹下执行命令来初始化项目:
npm init -y
执行以下命令来安装 Babel:
npm install babel-cli babel-preset-es2015 babel-plugin-transform-react-jsx --save-dev
安装完后会创建 .babelrc
文件:
{
"presets": ["es2015"],
"plugins": [
["transform-react-jsx", {
"pragma": "m"
}]
]
}
然后在命令行中运行:
babel src --out-dir bin --source-maps
如果你的项目已经使用了 Webpack,你可以按以下步骤把 Babel 集成到 Webpack 中。首先执行以下命令安装 Babel:
npm install babel-core babel-loader babel-preset-es2015 babel-plugin-transform-react-jsx --save-dev
安装完后会创建 .babelrc
文件:
{
"presets": ["es2015"],
"plugins": [
["transform-react-jsx", {
"pragma": "m"
}]
]
}
然后,创建一个 webpack.config.js
配置文件:
module.exports = {
entry: './src/index.js',
output: {
path: './bin',
filename: 'app.js',
},
module: {
loaders: [{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}]
}
}
这个配置文件设置了应用的入口文件为 src/index.js
,且打包后输出到 bin/app.js
。
要运行 bundler,需要设置一个 npm 脚本。打开 package.json
文件并在 "scripts"
中添加一行命令:
{
"name": "my-project",
"scripts": {
"start": "webpack -d --watch"
}
}
现在,可以在命令行中执行以下命令来运行 bundler:
npm start
要压缩生成的文件,请打开 package.json
文件,并添加一个新的 npm 脚本 build
:
{
"name": "my-project",
"scripts": {
"start": "webpack -d --watch",
"build": "webpack -p",
}
}
在生产环境中,你可以使用钩子来自动运行构建脚本。这是一个使用 Heroku 的例子:
{
"name": "my-project",
"scripts": {
"start": "webpack -d --watch",
"build": "webpack -p",
"heroku-postbuild": "webpack -p"
}
}
JSX 引入了一个非标准的语法,它必须借助工具才能运行,但它允许开发者直接在 JavaScript 使用 HTML 语法。使用 JSX 代替 HTML 语法的好处是 JSX 的语法更加严格,它会在适当时候提示语法错误;而 HTML 的语法太宽松了,可能产生了语法错误但你很难发现。
和 HTML 不同的是,JSX 区分大小写。比如 <div className="test"></div>
和 <div classname="test"></div>
是不同的,前者会编译成 m("div", {className: "test"})
,而后者会编译成 m("div", {classname: "test"})
,后者并不是创建类属性的正确方式。幸运的时,Mithril 支持标准的 HTML 属性名,因此,这个例子可以像普通 HTML 一样来写:<div class="test"></div>
。
JSX 对于那些以写 HTML 为主,且 JavaScript 经验不足的团队比较有用,但它需要大量的工具来维护,而纯 HTML 大多数情况下都可以直接在浏览器中打开。
Hyperscript 是指 JSX 编译后生成的语法。Hyperscript 的语法也是可读的,你可以直接使用它的语法来编写,不一定要用 JSX 来生成(文档中大多数地方用的都是 Hyperscript)。Hyperscript 往往比 JSX 更简洁,因为:
m("div")
VS <div></div>
)m("a.button")
VS <div class="button"></div>
)此外,因为 hyperscript 是标准的 javaScript 语法,所以它的缩进会比 JSX 更自然:
//JSX
var BigComponent = {
activate: function() {/*...*/},
deactivate: function() {/*...*/},
update: function() {/*...*/},
view: function(vnode) {
return [
{vnode.attrs.items.map(function(item) {
return <div>{item.name}</div>
})}
<div
ondragover={this.activate}
ondragleave={this.deactivate}
ondragend={this.deactivate}
ondrop={this.update}
onblur={this.deactivate}
></div>
]
}
}
// hyperscript
var BigComponent = {
activate: function() {/*...*/},
deactivate: function() {/*...*/},
update: function() {/*...*/},
view: function(vnode) {
return [
vnode.attrs.items.map(function(item) {
return m("div", item.name)
}),
m("div", {
ondragover: this.activate,
ondragleave: this.deactivate,
ondragend: this.deactivate,
ondrop: this.update,
onblur: this.deactivate,
})
]
}
}
在较复杂的应用中,组件的控制流和配置的代码可能比标签更多,因此 hyperscript 比 JSX 代码可能有更好的可读性。
另外,hyperscript 是纯 JavaScript 代码,不像 JSX 那样需要编译才能产生可运行的代码。
在 Mithril 中,要把一个格式规范的 HTML 文件集成到使用 JSX 的项目中,除了复制粘贴外,只需要做少量的修改。
使用 hyperscript 时,需要把 HTML 代码转为 hyperscript 语法才能运行。为方便起见,你可以使用HTML-to-Mithril 模版转换器。