Here we build a component system from scratch. First of all, we know from the previous articles "Basics of Front-end Componentization" and "Using JSX to Establish Component Parser" that a component is an environment that can be accessed through Markup and JavaScript. So our first step is to create an environment where we can use markup. Here we will learn how to use JSX to style our markup. Here we use JSX, the same as React, to style our components. JSX environment constructionIn general, JSX is considered to be a part of React. In fact, Facebook defines JSX as a pure language extension. And this JSX can also be used by other component systems.
Setting up the project So let's start from the basics. First we need to create a new project directory: mkdir jsx-component Initialize NPM Of course, create this project folder in the directory you like. After creating the folder, we can enter the directory and initialize npm init After executing the above command, some project configuration options will appear. You can fill them in if necessary. However, we can also just keep pressing Enter, and then students who need it can open Install webpackMany students should have known about Wepack, which can help us turn an ordinary JavaScript file into a file that can package different import and require files together. So we need to install So here we use the global installation of webpack-cli: npm install -g webpack webpack-cli After the installation is complete, we can check the installed webpack version by entering the following command. If there is no error after execution and a version number appears, it proves that we have installed it successfully. webpack --version Install BabelBecause JSX is a babel plugin, we need to install webpack, babel-loader, babel and babel plugin in sequence. Another use of Babel here is that it can compile a new version of JavaScript into an old version of JavaScript, so that we can support running in more older versions of browsers. To install Babel we just need to execute the following command. npm install --save-dev webpack babel-loader What we need to note here is that we need to add After execution, we should see the message shown in the image above. To verify that we have installed it correctly, we can open { "name": "jsx-component", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "devDependencies": { "babel-loader": "^8.1.0", "webpack": "^5.4.0" } } OK, we can see that under Configure webpack At this point we need to configure the webpack configuration. Configure webpack We need to create a Create a First of all, webpack config is a nodejs module, so we need to use module.exports to write its settings. This is a common configuration method for early nodejs tools. It uses a JavaScript file to configure it, so that some logic can be added to the configuration. module.exports = {} The most basic thing about Webpack is that you need to set up an entry (set its entry file). Here we just set up a module.exports = { entry: "./main.js" } At this time, we can first create our // main.js file content for (let i of [1, 2, 3]) { console.log(i); } In this way, the basic configuration of our webpack is configured. Let's execute webpack in the root directory to package our webpack After the execution is completed, we can see a prompt like the above in the command line interface.
At this time we will find that a new folder Here we will find that there is a packaged Then we open it and we will see the JavaScript code after it is compiled by babel. We will find that a lot of things have been added to our few lines of code, but we don’t need to worry about these things, this is the “meow power” of Webpack. At the end of the code, you can still see Install Babel-loader Next, let's install babel-loader. In fact, babel-loader does not directly depend on babel, so we need to install npm install --save-dev @babel/core @babel/preset-env The final result is as shown above, proving that the installation was successful. At this time we need to configure it in Add an option called Then we can also add a
The value of
loader: Just add the name of our
presets:
Finally our configuration file will look like this: module.exports = { entry: './main.js', module: { rules: { test: /\.js$/, use: { loader: 'babel-loader', options: presets: ['@babel/preset-env'], }, }, }, ], }, }; After configuring this, we can run babel to try it out. As before, we just need to execute If our configuration file is written correctly, we should see the results shown in the figure above. Then we go to After compilation, we will find that At this point we have installed and built the environment required for our JSX. Mode ConfigurationFinally, we also need to add an environment configuration in webpack.config.js, but this can be said to be optional, but we do it for the convenience of daily development. So we need to add a Generally speaking, the webpack configuration we write in the code repository will add this module.exports = { entry: './main.js', mode: 'development', module: { rules: { test: /\.js$/, use: { loader: 'babel-loader', options: presets: ['@babel/preset-env'], }, }, }, ], }, }; After the modification, we use Obviously we found that the compiled code is not compressed into one line. This way we can debug the code generated by webpack. Here we can notice that our code in Importing JSX Everything is ready, except for the east wind. Finally, how do we introduce JSX? Before importing, let's see what happens if we use the JSX syntax in our So we add this code to our
Then let's run webpack and see! Good job! Sure enough, it reported an error. The error here tells us that the "less than sign" cannot be used after So what should we do to make our webpack compilation process support JSX syntax? Here we actually need to add a most critical package, and the name of this package is very long, called npm install --save-dev @babel/plugin-transform-react-jsx After installation, we also need to add it to the webpack configuration. We need to add Then finally our webpack configuration file looks like this: module.exports = { entry: './main.js', mode: 'development', module: { rules: { test: /\.js$/, use: { loader: 'babel-loader', options: presets: ['@babel/preset-env'], plugins: ['@babel/plugin-transform-react-jsx'], }, }, }, ], }, }; After configuration, let's execute webpack. At this time we found that there was no more error. This proves that our code now supports writing using JSX syntax. Finally, let’s take a look at the final effect of the programming. We will find that So let's take a look at how we should implement Basic JSX usage First, let's try to understand JSX. JSX is actually just a shortcut in code syntax. At the end of the previous section, we saw that after the JSX syntax is compiled, a call to JSX BasicsSo here we first modify the JSX plug-in in webpack and give it a custom element creation function name. We open webpack.config.js and modify it in the plugins section. module.exports = { entry: './main.js', mode: 'development', module: { rules: { test: /\.js$/, use: { loader: 'babel-loader', options: presets: ['@babel/preset-env'], plugins: [ [ '@babel/plugin-transform-react-jsx', { pragma: 'createElement' } ] ], }, }, }, ], }, }; Above we just changed the original With this change, our JSX has nothing to do with the React framework. Let's execute webpack and look at the final generated effect. We will find that Next, we add an HTML file to execute our main.js and try it out. First create a <script src="./main.js"></script> Then we execute and open this HTML file in the browser. At this time, our console will throw us an error, and our So we need to write a function createElement() { return; } let a = <div />; Here we just return empty and make this function callable first. We recompile once with webpack and then refresh our main.html page. At this time we will find that there is no error and it can run normally. Implementing the createElement function In our compiled code, we can see that the JSX element passes two parameters when calling createElement. The first argument is Why is the second parameter We will find that the second parameter becomes a JavaScript object stored in Key-Value mode. If we think about it now, JSX is not that mysterious. It just compiles the HTML we usually write into a JavaScript object. We can think of it as a kind of "syntactic sugar".
Next, let's write some more complex JSX. We'll add some children elements to our original div. function createElement() { return; } let a = ( <div id="a"> <span></span> <span></span> <span></span> </div> ); Finally, let's execute webpack packaging to see the effect. In the console, we can see that the final compiled result is a recursive call to the The parent is the first-level div element, and the child is the parameter passed into the first createElement function. Then, because our spans have no attributes, the second parameter of all subsequent createElements is Based on the compilation result we see here, we can analyze what the parameters of our createElement function should be.
Then our function createElement(type, attributes, ...children) { return; } We have the function, but what can this function do? In fact, this function can be used to do anything. Because it looks like a DOM API, we can make it into an entity DOM that has nothing to do with React. For example, we can return the To create an element we can use function createElement(type, attributes, ...children) { // Create an element let element = document.createElement(type); //Hang attributes for (let attribute in attributes) { element.setAttribute(attribute); } //Hang all child elements for (let child of children) { element.appendChild(child); } //Finally our element is a node// so we can return directly return element; } Here we implement the logic of // Add this code to the end of main.js let a = ( <div id="a"> <span></span> <span></span> <span></span> </div> ); document.body.appendChild(a); It should also be noted here that there is no body tag in our main.html. Otherwise, we cannot mount it on the body. So here we need to add the body tag to main.html. <body></body> <script src="dist/main.js"></script> OK, now we can package it with webpack and see the effect. Wonderful! We have successfully generated the node and attached it to the body. But if we add a piece of text to our Next we will add the logic for processing text nodes, but before that we will delete the span tag in the div and replace it with a text "hello world". let a = <div id="a">hello world</div>; Before we add the logic of the text node, let's package it with webpack first. Before we hang up the child node, let's see what specific errors will be reported. First, we can see that where Through this debugging method, we can immediately locate where we need to add logic to implement our function. This method can also be considered a shortcut. So let's go back to function createElement(type, attributes, ...children) { // Create an element let element = document.createElement(type); //Hang attributes for (let name in attributes) { element.setAttribute(name, attributes[name]); } //Hang all child elements for (let child of children) { if (typeof child === 'string') child = document.createTextNode(child); element.appendChild(child); } //Finally our element is a node// so we can return directly return element; } let a = <div id="a">hello world</div>; document.body.appendChild(a); After we use this latest code webpack to package, we can see our text is displayed on the browser. At this point, Here we can verify that we add our previous three spans back into the div and add text to each span. 11 let a = ( <div id="a"> hello world: <span>a</span> <span>b</span> <span>c</span> </div> ); Then after we re-pack the webpack, we can see that this DOM operation can indeed be completed. The current code can already achieve certain basic component capabilities. Implementing custom tagsBefore, we were using some tags that came with HTML. What happens if we now change the d in div to a capital D? let a = ( <Div id="a"> hello world: <span>a</span> <span>b</span> <span>c</span> </Div> ); As expected, it will report an error. But this is the key to finding the root cause of the problem. Here we find that when we change div to Div, the div passed to our Of course, the Div class is not defined in our JavaScript, so an error indicating that Div is not defined will be reported. Knowing where the problem lies, we can solve it. First, we need to solve the undefined problem, so we first create a Div class. // Add class Div {} after the createElment function Then we need to do type judgment in function createElement(type, attributes, ...children) { // Create element let element; if (typeof type === 'string') { element = document.createElement(type); } else { element = new type(); } //Hang attributes for (let name in attributes) { element.setAttribute(name, attributes[name]); } //Hang all child elements for (let child of children) { if (typeof child === 'string') child = document.createTextNode(child); element.appendChild(child); } //Finally our element is a node// so we can return directly return element; } Here we have another question, is there any way we can make custom tags operate like our ordinary HTML tags? There is a way to do this in the latest version of the DOM standard. We just need to register the name and type of our custom tag. However, in our current more secure browsing version, it is not recommended to do so. Therefore, when using our custom element, it is recommended that we write an interface ourselves. First we need to create a tag class, which allows any tag to be mounted on our DOM tree like the elements of our previous ordinary HTML tags. It will contain the following methods:
First, let's simply implement the class Div { setAttribute() {} appendChild() {} mountTo(parent) { this.root = document.createElement('div'); parent.appendChild(this.root); } } This is actually very simple. First, create a div element node for Then we can change our original body.appendChild code to use the // document.body.appendChild(a); a.mountTo(document.body); With the current code, we package it with webpack to see the effect: We can see that our Div custom element is correctly mounted on the body. But the span tags in Div are not mounted. If we want it to work like a normal div, we need to implement our Next, let's try to complete the remaining implementation logic. Before we start writing setAttribute and appendChild, we need to add a constructor() { this.root = document.createElement('div'); } Then the class Div { // Constructor // Create DOM node constructor() { this.root = document.createElement('div'); } // Mount the element's attributes setAttribute(name, attribute) { this.root.setAttribute(name, attribute); } // Mount element child element appendChild(child) { this.root.appendChild(child); } // Mount the current element mountTo(parent) { parent.appendChild(this.root); } } Let's package it with webpack to see the effect: We can see that both div and span are successfully mounted on body. It also proves that our self-made div can work normally. There is another problem here, because we finally called So here we also need to add a Wrapper class to ordinary elements so that they can maintain the standard format of our element class. It is also called a standard interface. Let's first write an When creating a DOM node, you can pass the current element name class ElementWrapper { // Constructor // Create DOM node constructor(type) { this.root = document.createElement(type); } // Mount the element's attributes setAttribute(name, attribute) { this.root.setAttribute(name, attribute); } // Mount element child element appendChild(child) { child.mountTo(this.root); } // Mount the current element mountTo(parent) { parent.appendChild(this.root); } } class Div { // Constructor // Create DOM node constructor() { this.root = document.createElement('div'); } // Mount the element's attributes setAttribute(name, attribute) { this.root.setAttribute(name, attribute); } // Mount element child element appendChild(child) { child.mountTo(this.root); } // Mount the current element mountTo(parent) { parent.appendChild(this.root); } } We still have a problem here, that is, when we encounter a text node, it is not converted into our custom class. So we also need to write one for the text node, called class TextWrapper { // Constructor // Create DOM node constructor(content) { this.root = document.createTextNode(content); } // Mount the element's attributes setAttribute(name, attribute) { this.root.setAttribute(name, attribute); } // Mount element child element appendChild(child) { child.mountTo(this.root); } // Mount the current element mountTo(parent) { parent.appendChild(this.root); } } With these element class interfaces, we can rewrite the logic in our function createElement(type, attributes, ...children) { // Create element let element; if (typeof type === 'string') { element = new ElementWrapper(type); } else { element = new type(); } //Hang attributes for (let name in attributes) { element.setAttribute(name, attributes[name]); } //Hang all child elements for (let child of children) { if (typeof child === 'string') child = new TextWrapper(child); element.appendChild(child); } //Finally our element is a node// so we can return directly return element; } Then we package it with webpack and see. Without any surprises, our entire element is mounted on the body normally. Similarly, if we change our Div back to div, it will also work properly. Of course, we generally don't write a meaningless Div element. Here we will write the name of our component, such as Full code - please give me a ⭐️ if this helps you, thanks! This concludes this article about using JSX to create a Markup component style development example (front-end componentization). For more related JSX scripts, JSX group component creation, and JSX style content, please search for previous articles on 123WORDPRESS.COM or continue browsing the related articles below. I hope you will support 123WORDPRESS.COM in the future! You may also be interested in:
|
<<: Shell script nginx automation script
>>: MySQL error: Deadlock found when trying to get lock; try restarting transaction solution
Before webpack packaging, we must ensure that the...
According to major websites and personal habits, ...
Remote connection to MySQL fails, there may be th...
I wrote a jsp page today. I tried to adjust <di...
1. Function Mainly used to preserve component sta...
Table of contents Undo Log Undo Log Generation an...
A. Installation of MySQL backup tool xtrabackup 1...
Preface: Integer is one of the most commonly used...
The MySQL built on Tencent Cloud is always very s...
The specific code is as follows: /*Scroll bar wid...
This article mainly introduces CSS circular hollo...
Preface Recently, I encountered a program using S...
one. wget https://dev.mysql.com/get/mysql57-commu...
The layui table has multiple rows of data. Throug...
Introduction to Text Shadows In CSS , use the tex...