是不是觉得写createElement很抽象?vue和react官方都是提供了相应的转化jsx的支持,这些支持靠的的强大的转换器babel。
react
1.安装依赖以及相关配置
首先我们cd 到 react-jsx目录下,npm init -y初始化项目。
cd react-jsx && npm init -y
安装babel相关依赖
npm i --save-dev @babel/core @babel/cli @babel/preset-react
对babel相关配置,预设@babel/preset-react的选项详见 官方说明。
// react-vue-jsx\react-jsx\babel.config.js
module.exports = function(api){
api.cache(false);
const presets =[[
"@babel/preset-react",
{
// "pragma": "dom", // default pragma is React.createElement
"pragmaFrag": "DomFrag", // default is React.Fragment
"throwIfNamespace": false // defaults to true
}
]]
return {
presets
}
}
因为我们没有全局安装babel-cli命令行工具,环境变量中找不到@babel/cli/bin文件。你可以直接终端运行以下命令用babel转换我们的文件:
node.\node_modules\@babel\cli\bin\babel.js react-component.js -o dist/transformed-react-component.js
这里为了方便在package.json文件中配置babel运行脚本。
{
"name": "react-jsx",
...
"scripts": {
...
"transform": "babel react-component.js -o dist/transformed-react-component.js"
},
}
2.jsx写react组件
写一个简单的react组件
// react-vue-jsx\react-jsx\react-component.js
// 类组件
class JsxComponetOne extends React.Component {
render(){
return(<div className="red" style={{color:"blue"}}>
我是jsx语法渲染出来的内容1
</div>)
}
}
// 函数组件
function JsxComponetTwo(){
return (<div className="red">
我是jsx语法渲染出来的内容2
</div>)
}
ReactDOM.render(
// 遍历渲染需要唯一的key标识
[<JsxComponetOne key="one" />, <JsxComponetTwo key="two"/>],
document.getElementById("app")
);
3.转换代码以及主页引入转换后组件代码。
终端运行以下转换我们写的jsx组件
npm run transform
实际上转换后代码如下图1-1:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Add React in One Minute</title>
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
</head>
<style>
.red{
background-color: red;
color: white;
}
</style>
<body>
<div id="app"></div>
</body>
// 引入转换后的代码
<script src="./dist/transformed-react-component.js"></script>
</html>
在游览器打开页面看到显示正常如图1-2:
vue
vue官方也提供了相应的 预设 支持jsx。
相应的配置和以上react的配置差不多。
1.安装依赖以及相关配置
cd到相应目录下npm初始化项目然后安装:
npm i --save-dev @babel/core @babel/cli @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props
// react-vue-jsx\vue-jsx\babel.config.js
module.exports = function(api){
api.cache(false);
const presets =[
"@vue/babel-preset-jsx"
]
return {
presets
}
}
// react-vue-jsx\vue-jsx\package.json
{
"name": "vue-jsx",
...
"scripts": {
...
"transform": "babel vue-component.js -o dist/transformed-vue-component.js"
},
}
2.jsx写vue组件
// react-vue-jsx\vue-jsx\vue-component.js
// Vue需要注册组件
CustomComponetOne= Vue.component('CustomComponetOne', {
render(){
const{ text,textCovert }= this
return(<div class="red" style="color:blue">
我是vue组件--------{{text1}}
</div>)
},
props:["prop"]
})
const CustomComponet = Vue.component('CustomComponet', {
render(){
// 这里请注意 由于没有配置模块化支持,被注入的import _mergeJSXProps from "@vue/babel-helper-vue-jsx-merge-props"这行代码会报错如图1-4,故若浏览器直接引用转换后的文件,不能用props,这个helper就是对props进行支持的;
return(<custom-componet-one props={{prop:1312}} text1="我是父组件传给我的属性" />)
}
})
3.babel转换后主页引用
终端运行转换命令
npm run transform
转换后的文件,实际上也是会转换成createElement的形式。若绑定了props会被helper合并到子组件的props接受,父组件上绑定的其他自定义属性被默认为attrs如demo中的text1,见图1-3。
// Vue需要注册组件
CustomComponetOne = Vue.component('CustomComponetOne', {
render() {
const h = arguments[0];
const {
text1
} = this;
return h("div", {
"class": "red",
"style": "color:blue"
}, ["\u6211\u662Fvue\u7EC4\u4EF6--------", {
text1
}]);
}
});
const CustomComponet = Vue.component('CustomComponet', {
render() {
const h = arguments[0];
return h("custom-componet-one", {
"attrs": {
"text1": "我是父组件传给我的属性"
}
});
}
});
如组件源文件中使用了props直接在浏览器引入转换后的文件会报错如图1-4
index.html引用转换后的代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<style>
.red{
background-color: red;
color: white;
}
</style>
<body>
<div id="app"></div>
</body>
<script src="./dist/transformed-vue-component.js"></script>
<script>
new Vue({
el:"#app",
render(createELement){
return createELement(CustomComponet)
}
})
</script>
</html>
打开页面显示正常如图1-5: