toyReact 一时失言乱红尘 2022-09-08 03:54 9阅读 0赞 从0开始构建一个玩具react * react基本组件原理 * 学习vdom的实现思路 * 突破编写自我的难点代码 ### 创建webpack ### 首先我们创建package.json npm init 接下来我们创建webpack npm install webpack --save-dev 创建好后新建webpack.config.js 添加entry 开发者模式 以及不压缩代码 module.exports = { entry: './main.js', mode: 'development', optimization: { minimize: false } }; 接下来我们创建main.js然后随便写点代码 console.log('hello world') 当然你不想一次一次使用webpack我们也可以使用webpack dev server npm install webpack-dev-server --save-dev 如果启动报错的的话说明没有webpack-cli npm install webpack-cli --save-dev 接下来我们修改package.json "start": "webpack-dev-server --open" 添加devserver进webpack.config.json var path = require('path'); module.exports = { entry: './main.js', devServer: { contentBase: path.join(__dirname, 'dist'), }, // mode: 'development', optimization: { minimize: false } }; 我们先在控制台run webpack 这样会自动生成dist folder 看下是不是已经生成main.js 然后创建index.html 引入dist目录下的main.js <!-- index.html --> <script src="main.js"></script> 接下来我们用命令跑起来 npm start ![65946b9dc76cf0cb26f1c7b3ad893ca5.png][] 此时我们的目录结构为 ![110db1913618b67c2755cf6d74d2eb2a.png][] ### 安装配置需要的loader ### 在我们webpack中我们需要用到的就是lodaer > loader 用于对模块的源代码进行转换。loader 可以使你在 import 或"加载"模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的强大方法。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件! 我们需要babel-loader > 加载 ES2015+ 代码,然后使用 Babel 转译为 ES5 npm install --save-dev babel-loader @babel/core @babel/preset-env @babel/plugin-transform-react-js 接下来添加webpack.config module: { rules: [ { test: /\.js$/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'], plugins: [[ "@babel/plugin-transform-react-jsx", // 使用JSX {pragma:"ToyReact.createElement"} //不加就是React.createElement ]] } } } ] }, 我们测试下看是否ES6变为了ES5 修改main.js console.log('hello world') for (let i of [1,2,3]) { console.log(i) } 打开dev tool 果然变成了ES5语法 ![86080cbb01d6558f706ec236353f66a5.png][] ### 编写JSX ### 新建Toyreact.js file export let ToyReact = { createElement() { console.log(arguments) } } 然后在main.js引入 import {ToyReact} from './Toyreact' let a = <div name="a"> <span></span> <span></span> <span></span> </div> 注意Toyreact.js中的ToyReact和createElement必须对应webpack的pragma 此时我们看dev tool 发现是先create里面元素再是外面元素 ![2c8bc2fbf0f63333459f786c62f8de3c.png][] 我们可以发现里面的参数分别为type,attr和children 但是第三个参数不确定,所以我们修改Toyreact.js并传入参数然后创建DOM export let ToyReact = { createElement(type,attr,...children) { console.log(type,attr,children) let ele = document.createElement(type) // 创建DOM for (let name in attr) { console.log(name) ele.setAttribute(name, attr[name]) // 设置属性 } for (let child of children){ console.log(child) ele.appendChild(child) // 将Children append进去 } return ele; } } 我们打印main.js的a ![58e03d4b9b233cfc3bb4b837470b2aaa.png][] 如果要在main函数中添加值得话就会报错 例如 import {ToyReact} from './Toyreact' let a = <div name="a"> <span>hello</span> <span>1</span> <span>2</span> </div> console.log(a) 所以此时我们要在Toyreact.js中加一句判断 if( typeof child === 'string') child = document.createTextNode(child) export let ToyReact = { createElement(type,attr,...children) { console.log(type,attr,children) let ele = document.createElement(type) // 创建DOM for (let name in attr) { console.log(name) ele.setAttribute(name, attr[name]) // 设置属性 } for (let child of children){ if( typeof child === 'string') child = document.createTextNode(child) // 转换成文本节点 ele.appendChild(child) // 将Children append进去 } return ele; } } ### 渲染 ### react中我们都是渲染采用render所以我们在Toyreact.js中加入render方法 class EleWrapper { constructor(type) { this.root = document.createElement(type) } setAttribute(name, value) { this.root.setAttribute(name, value) } appendChild(vchild){ vchild.mountTo(this.root) } mountTo(parent) { parent.appendChild(this.root) } } export class Component { mountTo(parent){ let vdom = this.render() vdom.mountTo(parent) } setAttribute(name, value) { this[name] = value; } } class TextWrapper { constructor(content) { this.root = document.createTextNode(content) } mountTo(parent) { parent.appendChild(this.root) } } export let ToyReact = { createElement(type,attr,...children) { let ele; if( typeof type === 'string') ele = new EleWrapper(type) // 创建DOM else ele= new type; for (let name in attr) { console.log(name) ele.setAttribute(name, attr[name]) // 设置属性 } for (let child of children){ if( typeof child === 'string') child = new TextWrapper(child) // 转换成文本节点 ele.appendChild(child) // 将Children append进去 } return ele; }, render(vdom, ele){ vdom.mountTo(ele) } } 修改main.js import {ToyReact, Component} from './Toyreact' class MyCom extends Component{ render() { return <span>1</span> } } let a = <MyCom name="a"> </MyCom> ToyReact.render( a, document.body ) 但是你会发现当MyCom组件中有子元素时依然有问题, 我们继续修改 class EleWrapper { constructor(type) { this.root = document.createElement(type) } setAttribute(name, value) { this.root.setAttribute(name, value) } appendChild(vchild){ vchild.mountTo(this.root) } mountTo(parent) { parent.appendChild(this.root) } } export class Component { constructor(){ this.children = [] } mountTo(parent){ let vdom = this.render() vdom.mountTo(parent) } setAttribute(name, value) { this[name] = value; } appendChild(vchild){ this.children.push(vchild) } } class TextWrapper { constructor(content) { this.root = document.createTextNode(content) } mountTo(parent) { parent.appendChild(this.root) } } export let ToyReact = { createElement(type,attr,...children) { let ele; if( typeof type === 'string') ele = new EleWrapper(type) // 创建DOM else ele= new type; for (let name in attr) { console.log(name) ele.setAttribute(name, attr[name]) // 设置属性 } let insertChildren = (children) => { for (let child of children){ if(typeof child === 'object' && child instanceof Array) { insertChildren(child) } else { if(!(child instanceof Component) && !(child instanceof EleWrapper) && !(child instanceof TextWrapper)) child = String(child) if( typeof child === 'string') child = new TextWrapper(child) // 转换成文本节点 ele.appendChild(child) // 将Children append进去 } } } insertChildren(children) return ele; }, render(vdom, ele){ vdom.mountTo(ele) } } main.js import {ToyReact, Component} from './Toyreact' class MyCom extends Component{ render() { return <span>1<span>{this.children}</span></span> } } let a = <MyCom name="a"> <span>hello</span> <span>1</span> <span>2</span> </MyCom> ToyReact.render(a, document.body) console.log(a) [65946b9dc76cf0cb26f1c7b3ad893ca5.png]: /images/20220829/993eabb5e7f64aaa86e3d042f2d5ed4c.png [110db1913618b67c2755cf6d74d2eb2a.png]: /images/20220829/4e10ae8a842541fbb42432387c0ceae5.png [86080cbb01d6558f706ec236353f66a5.png]: /images/20220829/3bad3cfbe4274afa8ff63a7c3dd4f8f6.png [2c8bc2fbf0f63333459f786c62f8de3c.png]: /images/20220829/2489ac8b0e914300b5d071f381b8a56e.png [58e03d4b9b233cfc3bb4b837470b2aaa.png]: /images/20220829/4d06de6935734d0b9988e8cf889c7a63.png
相关 手把手带你实现ToyReact框架 ![format_png][] 去年我面试一位前端工程师的时候,看他简历上写着“熟练掌握 React、Vue 等框架”,所以我就试探着问了他几个原理方面的问题,比如,“大概说 刺骨的言语ヽ痛彻心扉/ 2023年02月26日 02:29/ 0 赞/ 27 阅读
相关 toyReact 从0开始构建一个玩具react react基本组件原理 学习vdom的实现思路 突破编写自我的难点代码 创建webpack 首先我们创建packag 一时失言乱红尘/ 2022年09月08日 03:54/ 0 赞/ 10 阅读
还没有评论,来说两句吧...