类jsx 实现(一)
这是第一次在掘金上发表文章,一些概念就不说了自己上主题。
最近面试经常问的问题 比如:讲一下vue原理,react原理,或者什么是虚拟dom。说实话我不知道怎么回答。源码我还没看,最多百度或者掘金上搜索看看,没深入研究就感觉很难回答,所有在这里我自己用自己的方放实现一下(可能代码有很多bug)
代码已经写了一部分就先上代码后面边写代码边写文章 ( 全角加空格怎么都没空格啊)
首先看一下Bable转化成React.createElement模式
const testEle = '<div class="swrap">我是你大哥<span>李白</span></div>' //转化jsx例子
let rule = /(.*?)(<\w+.*?>)(.*)(<\/\w+>)(.*?)$/; //html标签分解
let tagR = /<\/(\w+)/;//标签
let classR = /class="(\w+)"/;//class
let idR = /id="(\w+)"/;//id
const changeEleDeepToJsx = function (ele, lastResult) {//html深度转化jsx数据
let result = [];
var sliceEle = ele.match(rule)
if (sliceEle === null) {
return
}
console.log(sliceEle[2])
let tag = sliceEle[4].match(tagR) && sliceEle[4].match(tagR)[1] //获取标签
let classAid = { //class和id
class: sliceEle[2].match(classR) && sliceEle[2].match(classR)[1],
id: sliceEle[2].match(idR) && sliceEle[2].match(idR)[1],
}
let content = sliceEle[3] // 该父标签下的所有内热
// result.push(sliceEle[1])
result.push(tag)
result.push(classAid)
// result.push([contentEle]) //内部元素
if (sliceEle[5]) {
result.push(sliceEle[5])
}
if (lastResult) {
if (sliceEle[1]) { //标签前面有文字等内容
lastResult.splice(2, 0, sliceEle[1])
lastResult.splice(3, 0, result)
} else {
lastResult.splice(3, 0, result)
}
}
if (content) {
changeEleDeepToJsx(content, result)
}
return lastResult ? lastResult : result
}
let jsxResult = changeEleDeepToJsx(testEle)
console.log(jsxResult)
复制代码
运行后的结果如下:
接下来写 createElement方法,发现应该传5个参数(不考虑多元素问题)而且还有多个子元素问题,代码进行优化,5个参数改下传值就好
createElement 方放简单实现
createElement([tag, ciObj, content1, childNode, content2]) {
console.log(ciObj)
if (!ciObj) { //有问题的
return ''
}
return `
<${tag} class='${ciObj && ciObj.class}' id='${ciObj && ciObj.id}'>
${content1}
${this.createElement.bind(this, childNode)()}
${content2}
</${tag}>
`
}
}
let react = new React()
let jsx = react.createElement(jsxResult)
console.log(jsx)
复制代码
先实验一下,新建html文件
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
* {
margin: 0;
padding: 0;
}
.swrap {
background: #409EFF;
padding: 10px;
}
.swrap a{
cursor: pointer;
color: #FFF;
}
</style>
<body>
<div id="root"></div>
</body>
<script type="module">
import { changeEleDeepToJsx, jsx } from './jsx2.js'
let render = function () {
return (
' <div class="swrap">{{name}}<span>你的<a>大哥</a></span>啊</div>'
)
}
console.log(changeEleDeepToJsx(render()))
//虚拟dom模拟
/*
*/
document.getElementById('root').innerHTML = render()
</script>
</html>
** js **
const testEle = '<div class="swrap">我是<span>你的<a>大哥<a></span>啊</div>'
let rule = /(.*?)(<\w+.*?>)(.*)(<\/\w+>)(.*?)$/;
let tagR = /<\/(\w+)/;//标签
let classR = /class="(\w+)"/;//class
let idR = /id="(\w+)"/;//id
const changeEleDeepToJsx = function (ele, lastResult) {//html深度转化jsx数据
let result = [];
var sliceEle = ele.match(rule)
if (sliceEle === null) { //没有子元素
console.log(ele, 57)
lastResult.splice(3, 0, '')
lastResult.splice(2, 0, ele)
return
}
let tag = sliceEle[4].match(tagR) && sliceEle[4].match(tagR)[1] //获取标签
let classAid = { //class和id
class: sliceEle[2].match(classR) && sliceEle[2].match(classR)[1] || '',
id: sliceEle[2].match(idR) && sliceEle[2].match(idR)[1] || '',
}
console.log(classAid)
let content = sliceEle[3] // 该父标签下的所有内热
// result.push('')
result.push(tag)
result.push(classAid)
// result.push([contentEle]) //内部元素
// if (sliceEle[5]) {
result.push(sliceEle[5])
// }
if (lastResult) {
// if (sliceEle[1]) { //标签前面有文字等内容
// lastResult.splice(3, 0, result)
// } else {
lastResult.splice(2, 0, sliceEle[1])
lastResult.splice(3, 0, result)
// }
}
if (content) {
changeEleDeepToJsx(content, result)
}
return lastResult ? lastResult : result
}
let jsxResult = changeEleDeepToJsx(testEle)
console.log(jsxResult)
class React {
createElement([tag, ciObj, content1, childNode, content2]) {
console.log(ciObj)
if (!ciObj) { //有问题的
return ''
}
return `
<${tag} class='${ciObj && ciObj.class}' id='${ciObj && ciObj.id}'>
${content1}
${this.createElement.bind(this, childNode)()}
${content2}
</${tag}>
`
}
}
let react = new React()
let jsx = react.createElement
console.log(jsx)
export {changeEleDeepToJsx,jsx}
复制代码
写到这里发现还有像这个符号{{}}的监听啥的还没写,还是无法测试。
总结一下
一、实现html转化成数组结构,数组结构转化为html格式,转化数组结构暂时没实现多个子元素情况
二、vue react 是转化成树结构的,下一篇先实现树的
三、js代码没封装好,写了个function 和 class类
四、markdown不熟悉文章写的烂的要死
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END