第1步 新建文件
mkdir toy-myreact
cd toy-myreact
第2步 npm 初始化
npm init
第3步 配置webpack
npm install webpack webpack-cli --save-dev
第3步 執行webpack
打包
npx webpack
因爲沒有指定好webpack的config文件,會發現報錯
第4步 新建webpack
的config
文件 webpack.config.js
module.exports = {
entry: {
main: './main.js',
},
};
指定一個入口文件,module.exports node的寫法 配置裏不做babel轉化
第5步 新建webpack
的入口文件 main.js
空文件並執行npx webpack
打包
打包成功後,輸出一個dist目錄,發現這個文件的內容並看不懂,想要看懂打包出來的文件怎麼辦呢??? 請看下一步
第6步 webpack 配置內加入兩個配置項
module.exports = {
entry: {
main: './main.js',
},
mode: "development",
optimization: {
minimize: false,
},
};
第7步 使用babel
babel 把新版本的js文件翻譯成老版本的js文件
安裝
npm install --save-dev babel-loader @babel/core @babel/preset-env
配置babel-loader
presets babel一系列的快捷方式
module.exports = {
entry: {
main: './main.js',
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
],
},
mode: "development",
optimization: {
minimize: false,
},
};
在main.js
內寫一個for
循環, 執行webpack
,看是否會翻譯成舊版本的js
for (let i of [1, 2, 3]) {
console.log(i);
}
可以看到一個正常的for循環代碼
第8步 處理jsx
@babel/preset-env
是不包含jsx的執行能力的
在main.js
內 寫jsx
並執行,報錯
const a = <div />;
安裝包
npm install @babel/plugin-transform-react-jsx --save-dev
@babel/plugin-transform-react-jsx
是專門用來處理jsx
的plugin
配置 webpack
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-transform-react-jsx'],
},
},
},
],
執行後 成功
直接翻譯出帶React
的函數名字, React.createElement
第9步 帶React的函數名字改成我們想要的設置
繼續更改webpack配置
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [['@babel/plugin-transform-react-jsx', {pragma: 'xixiToy.createElement'}]],
},
},
},
],
執行webpack, 發現React
函數名已經去掉了 變成了我們自己想要的名字
第10步 如何去實現jsx翻譯出來的函數
增加屬性和子節點
const xixiToy = {
createElement,
};
/**
* @name: chelsea.jiang
* @test:
* @msg:
* @param {*} tagName 標籤名
* @param {*} attributes 屬性
* @param {array} children 子節點
* @return {*}
*/
function createElement(tagName, attributes, ...children) {
let e = document.createElement(tagName);
for (let attr in attributes) {
e.setAttribute(attr, attributes[attr]);
}
for (let child of children) {
e.appendChild(child);
}
return e;
}
window.a = (<div id="a" class="x">
<div></div>
</div>);
執行webpack編譯之後,發現已不再報錯
jsx 已具備初步的可用性
但是當文本節點的時候怎麼辦呢???
第11步 文本節點處理
for (let child of children) {
if (typeof child === 'string') {
child = document.createTextNode(child);
}
e.appendChild(child);
}
div
改爲自己的組件呢??
window.a = (<div id="a" class="x">
<div>aaaa</div>
<div>bbb</div>
<MyComponent>cccc</MyComponent>
</div>);
MyComponent
編譯後已不是帶引號的標籤
第12步 組件特殊處理
main.html
<body></body>
<script src="main.js"></script>
xixiToy.js
const xixiToy = {
createElement,
render,
};
class ElementWrapper {
constructor(type) {
this.root = document.createElement(type);
}
setAttribute(name, value) {
this.root.setAttribute(name, value);
}
appendChild(component) {
this.root.appendChild(component.root);
}
}
class TextWrapper {
constructor(content) {
this.root = document.createTextNode(content);
}
}
export class Component {
constructor() {
this._root = null;
this.props = Object.create(null);
this.children = [];
}
setAttribute(name, value) {
this.props[name] = value;
}
appendChild(component) {
this.children.push(component);
}
get root() {
if (!this._root) {
this._root = this.render().root;
}
return this._root;
}
}
function createElement(type, attributes, ...children) {
let e;
if (typeof type === 'string') {
e = new ElementWrapper(type);
} else {
e = new type;
}
for (let attr in attributes) {
e.setAttribute(attr, attributes[attr]);
}
for (let child of children) {
if (typeof child === 'string') {
child = new TextWrapper(child);
}
e.appendChild(child);
}
return e;
}
function render(component, parentElement) {
parentElement.appendChild(component.root);
}
export default xixiToy;
main.js
import xixiToy, { Component } from './xixiToy.js';
const { render } = xixiToy;
class MyComponent extends Component {
render() {
return (
<div>
<h1>111111</h1>
{this.children}
</div>
);
}
}
render(<div id="a" class="x">
<div>aaaa</div>
<div>bbb</div>
<MyComponent id='c'>cccc</MyComponent>
</div>, document.body);
最後會發現控制檯還是報錯
是因爲在createElement
child做處理的時候沒有考慮到數組的情況
做完改造後,運行正常
function createElement(type, attributes, ...children) {
let e;
if (typeof type === 'string') {
e = new ElementWrapper(type);
} else {
e = new type;
}
for (let attr in attributes) {
e.setAttribute(attr, attributes[attr]);
}
const insertChildren = (children) => {
for (let child of children) {
if (typeof child === 'string') {
child = new TextWrapper(child);
}
if (typeof child === 'object' && child instanceof Array) {
insertChildren(child);
} else {
e.appendChild(child);
}
}
}
insertChildren(children);
return e;
}