目錄
- 1 前言
- 2 babel
- 3 webpack配置說(shuō)明
- 1 webpack.config.js
- 2 .babelrc
- 4 解析JSX轉(zhuǎn)義后的語(yǔ)法
- 5 完整項(xiàng)目
- 6 參考
前言
這篇文章是上一篇Use JSX without React 1: Virtual DOM的繼續(xù)蛤签,如果你對(duì)Virtual DOM不夠了解栅哀,建議先閱讀上一篇震肮。
這篇文章將介紹脫離React的情況下称龙,使用webpack配置打包JSX轉(zhuǎn)義成JavaScript戳晌,并將會(huì)簡(jiǎn)單實(shí)現(xiàn)幾種常用的React組件。
cr:本文大部分參考Lessons learned using JSX without React
babel
轉(zhuǎn)義JavaScript第一當(dāng)然會(huì)想到到巴別塔疫向,JSX語(yǔ)法插件需要用到的主要有
yarn add -D @babel/cli @babel/core @babel/plugin-syntax-jsx @babel/plugin-transform-react-jsx
個(gè)人比較喜歡使用webpack豪嚎,所以這里以webpack工程化為例搔驼。為直接進(jìn)入正題疙渣,這里就不介紹npm init
等初始化命令了匙奴,完整代碼請(qǐng)戳這里??https://github.com/1uokun/jsx-render/blob/master/examples/webpack.config.js
webpack配置說(shuō)明
webpack.config.js
module: {
rules: [{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
extends: path.resolve(__dirname, './.babelrc'),
},
}]
},
.babelrc
配置{ "pragma": "dom" }
暴露一個(gè)dom(tag, attrs, ...children)
方法用于解析JSX轉(zhuǎn)義JavaScript之后的DOM樹(shù)
{
"presets": ["@babel/preset-env"],
"plugins": [
"@babel/plugin-syntax-jsx",
["@babel/plugin-transform-react-jsx", { "pragma": "dom" }]
]
}
解析JSX轉(zhuǎn)義后的語(yǔ)法
根據(jù)上一篇文章我們得知妄荔,JSX轉(zhuǎn)義后的語(yǔ)法為
"use strict";
var dom= React.createElement;
var ul = dom('ul', {id: 'list'}, [
dom('li', {class: 'item'}, ['Item 1']),
dom('li', {class: 'item'}, ['Item 2']),
dom('li', {class: 'item'}, ['Item 3'])
])
dom方法
不依賴React,我們就需要自己寫(xiě)dom()
方法替代React. createElement
谍肤,具體實(shí)現(xiàn)方法如下:
確定參數(shù) tag
, attrs
, ...children
tag 存在的類型[1]有
DOM節(jié)點(diǎn)
const element = document.createElement(tag)
SVG
document.createElementNS('http://www.w3.org/2000/svg', tag)
function
tag類型為function
情況存在于函數(shù)名作為標(biāo)簽引用,也就是組件荒揣,組件類型也可分成既有組件和自定義組件
1.既有組件
什么是既有組件?就是類庫(kù)里已經(jīng)定義好的組件系任,比如React.Fragments
或者React.Portals
組件,既然是提前定義好的俩滥,在節(jié)點(diǎn)類型判斷中就要考慮進(jìn)去
2.自定義組件
可以是Dumb Component 啞巴組件,如<HeadLine />
也可以是Smart Component 智能組件错忱,如<Dialog>{this.props.children}</Dialog>
if (typeof tag === 'function') {
tag.defaultProps = tag.defaultProps || {}
const result = tag(Object.assign({}, tag.defaultProps, attrs, { children }))
switch (result) {
case 'FRAGMENT':
return createFragmentFrom(children)
// createFragmentFrom為自定義函數(shù)挂据,解析children
// Fragments和Portals組件具體作用請(qǐng)閱讀React文檔
case 'PORTAL':
tag.target.appendChild(createFragmentFrom(children))
return document.createComment("Portal Used")
default:
return result
}
}
attrs 存在的類型[2]有
style
// old: style={{color:'red',fontSize:'5px'}}
// new: { style: { color: 'red', fontSize: '5px' } },
function objectToStyleString(styles) {
return Object.keys(styles)
.map(prop => `${prop}: ${styles[prop]}`)
.join(';')
}
element.style.cssText = objectToStyleString(attrs[prop])
className
element.setAttribute('class', attrs[prop])
xlinkHref (SVG xlink:href)
element.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', attrs[prop])
dangerouslySetInnerHTML (替代innerHTML)[1]
element.innerHTML = attrs[prop].__html;
events(上一篇有介紹)
element.addEventListener(...)
實(shí)現(xiàn)
接下來(lái)就是我們熟悉的React語(yǔ)法
import dom from './dom.js' //每一個(gè)jsx文件都必須引入
function HeadLine(){
return <Head><div>頭部信息</div><hr/></Head>
}
function Main(){
return (
<Fragments>
<HeadLine />
<div>...</div>
</Fragments>
)
}
完整項(xiàng)目
https://github.com/alecsgone/jsx-render
參考
- [1] DOM Elements – React
reactjs.org
- [2] Styling and CSS – React
reactjs.org
- [3] 不引入react的情況下使用JSX
唐霜
- [4] Lessons learned using JSX without React
medium.com
- [5] https://github.com/alecsgone/jsx-render
github