Topic describes
HTML can be treated as a kind of serialization, where the browser interprets (deserializes) the HTML text, and then builds a DOM tree. In addition to xmL-based solutions, we can also try JSON. If you print the React representation for element, it looks like this:
const el = <div>
<h1> this is </h1>
<p className="paragraph"> a <button> button </button> from <a href="https://bfe.dev"><b>BFE</b>.dev</a>
</p>
</div>;
console.log(el)
Copy the code
The following data structure is obtained:
{
type: 'div'.props: {
children: [{type: 'h1'.props: {
children: ' this is '}}, {type: 'p'.props: {
className: 'paragraph'.children: [
' a ',
{
type: 'button'.props: {
children: ' button '}},' from',
{
type: 'a'.props: {
href: 'https://bfe.dev'.children: [{type: 'b'.props: {
children: 'BFE'}},'.dev']}}]}}Copy the code
Topic link
Thought analysis
To implement JSX <=> virtual DOM, it is not very good to judge the difficulty, from the process of processing data to generate HTML more in line with the usual development logic, from vDOM -> JSX start it! The most intuitive rule, virtual DOM is a tree, we need to determine the parent-child relationship
- a
type
There is *children
children
Contains string nodes and labeled nodes- a
type
Corresponds to aprops
props
In addition tochildren
The rest are attributes on the element
With these four points sorted out, you can start writing code
function render(json) {
// textNode
if (typeof json === 'string') {
return document.createTextNode(json);
}
// element
const {type, props: {children, ... attrs}} = json;// Create a node when type occurs
const element = document.createElement(type);
// Add attributes to the node
Object.entries(attrs).forEach(([attr, value]) = > element[attr] = value);
// Add children to the node
const childrenArr = Array.isArray(children) ? children : [children];
childrenArr.forEach(child= > element.append(render(child)));
return element;
}
Copy the code
JSX => vDOM. The first reaction is that the vDOM data structure (looks) is the same as JSX
function virtualize(element) {
const result = {
type: element.tagName,
props: {}};// Add attributes first
element.attributes.forEach... props[k] = v;
// Add children to loop node recursion (add attributes and children)
element.childNodes.forEach... props.children = newChildren
}
Copy the code
Follow this thread to complete the code:
function virtualize(element) {
const result = {
type: element.tagName.toLowerCase(),
props: {}}// attrs
element.attributes.forEach(attr= > {
const name = attr.name === 'class' ? 'className' : attr.name;
result.props[name] = attr.value;
});
// children
const children = [];
element.childNodes.forEach(node= > {
if (node.nodeType === 3) {
children.push(node.textContent);
} else{ children.push(virtualize(node)); }}); result.props.children = children.length ===1 ? children[0] : children;
return result;
}
Copy the code
AC code
function render(json) {
// textNode
if (typeof json === 'string') {
return document.createTextNode(json);
}
// element
const {type, props: {children, ... attrs}} = json;// Create a node when type occurs
const element = document.createElement(type);
// Add attributes to the node
Object.entries(attrs).forEach(([attr, value]) = > element[attr] = value);
// Add children to the node
const childrenArr = Array.isArray(children) ? children : [children];
childrenArr.forEach(child= > element.append(render(child)));
return element;
}
function virtualize(element) {
const result = {
type: element.tagName.toLowerCase(),
props: {}}// attrs
element.attributes.forEach(attr= > {
const name = attr.name === 'class' ? 'className' : attr.name;
result.props[name] = attr.value;
});
// children
const children = [];
element.childNodes.forEach(node= > {
if (node.nodeType === 3) {
children.push(node.textContent);
} else{ children.push(virtualize(node)); }}); result.props.children = children.length ===1 ? children[0] : children;
return result;
}
Copy the code
conclusion
After the simple conversion of vDOM and JSX, we can try to write a simple version of the React. CreateElement title link to write a render and h function to generate JSX and VDOM, respectively
render(h(
'div',
{},
h('h1', {}, ' this is '),
h(
'p',
{ className: 'paragraph' },
' a ',
h('button', {}, ' button '),
' from ',
h('a',
{ href: 'https://bfe.dev' },
h('b', {}, 'BFE'),
'.dev'))))Copy the code
Function h corresponds to vDOM above
function h(type, props, ... children) { return { type, props: { ... props, children } }; }Copy the code
Render function as above
This article is participating in the “Nuggets 2021 Spring Recruitment Campaign”, click to see the details of the campaign