246
技術社區[雲棲]
實戰json、html、jsx的互轉
jsx2html
場景
將下麵的jsx轉換為html
const items = ['one', 'two', 'three'];
const SearchData = ({ data = [] }) => {
let list = null;
if (data.length) {
list = data.map((l, k) => (<p key={k}>{l}</p>));
} else {
list = (<p>暫無數據</p>);
}
return (
<div className="mod-search-data">
<div>
<h3>匹配的員工:</h3>
<div>{list}</div>
</div>
</div>
);
};
const jsx = (
<div className="foo">
<p>列表展示 {items.length} 項:</p>
<div>
<p>SEARCH DATA:</p>
<SearchData data={items} />
</div>
</div>
);
方案
方案一:自己遍曆
所有的jsx你拿到的時候,都已經是 Babel 幫你轉義過的了。所以,你其實拿到的是轉義後的對象。所以你隻需要將這對象轉成你想要的結果。我們知道 Props 除了 key、ref、children 這幾個特殊的,剩下的都對應到 dom 的 attribute。
做法
1、獲取 displayName 作為 Tag
2、處理 props 作為 attribute
3、如果有children,則重複1、2、3、4,遍曆 children,作為子元素
4、拚裝 html 字符串
代碼
function getDisplayName(ele) {
if (typeof ele.type === 'string') {
return ele.type;
}
return ele.type.name || ele.type.displayName || 'No Name';
}
function getAttrs(attrs) {
return Object.keys(attrs).map(attr => (attr === 'children' ? '' : `${attr}="${attrs[attr]}"`)).join('');
}
function transfer(ele) {
if (typeof ele === 'string' || typeof ele === 'number') {
return ele;
}
const props = ele.props || {};
const children = React.Children.toArray(props.children || []);
const html = children.map(transfer);
const tag = getDisplayName(ele);
return `<${tag} ${getAttrs(props)}>${html.join('')}</${tag}>`;
}
console.log(transfer(jsx));
// 如果函數式的組件你也需要解析的話,則需要執行這個函數
// congsole.log(transfer(SearchData({items: data})))
類庫
方案二:通過 Babel 直接轉
我們可以指定 Babel 在編譯的時候調用某個函數。我們可以通過這個函數來生成我們需要的操作。
做法
- 方法一
配置 .babelrc
json { "plugins": [ ["transform-react-jsx", { "pragma": "dom" // default pragma is React.createElement }] ] }
但是這種方法修改全部的 babel 轉換行為。非常不推薦
- 方法二
在代碼中加一個注釋/** @jsx h */,告訴 Babel ,用 h 函數處理 Babel 編譯後的行為。參考WTF is JSX
代碼
/** @jsx h */
function getDisplayName(ele) {
if (typeof ele === 'string') {
return ele;
}
return ele.name || ele.displayName || 'No Name';
}
function h(name, attrs, ...children) {
const html = Array.isArray(children) ? children.join('') : children;
console.log('###################################');
console.log('name:', name);
console.log('attrs:', attrs);
console.log('children:', children);
const attr = Object.keys(attrs || {}).map(a => `${a}='${attrs[a]}'`).join(' ');
return `<${name} ${attr}>${html}</${name}>`;
}
console.log(jsx);
類庫
jsx2json
與上麵的情況了類似,如果我們要將那部分 jsx 轉換為 json 格式的怎麼辦呢?答案很簡單,不用刻意去轉(?!)。因為 Babel 已經幫你轉過了。你需要做的是把 Babel 編譯後的 json 轉成你想要的格式。此外,剛才的兩種方案也是生效的。不同的是,之前的返回值是一段 html 文本,現在需要返回 json 格式的。我們以上麵的方案二舉例:
/** @jsx h */
function h(name, attrs, ...children) {
/*
// 函數式的組件(functional component)請根據需要轉換
if (typeof name === 'function') {
return name(attrs);
}
*/
return {
tag: name,
attrs,
children,
};
}
console.log(jsx);
html2jsx
場景
將下麵的 html 轉換為 jsx:
const html = `
<div className='foo' data-node="12">
<h1>Hi!</h1>
<p>Here is a list of 3 items:</p>
<ul>
<li>one</li>
<li>two</li>
<li>three</li>
</ul>
</div>
`;
方案
將 html 轉為 jsx,實際上就是用 React.createElement 將 html 的結構重新生成一下,做到without jsx
做法
1、將 html 片段轉成 dom
2、讀取 dom 的 attributes, 處理特殊的 attribute,作為 ReactElement 的 props
3、讀取 dom 的 tagName, 作為 ReactElement 的 type
4、如果 dom 有 children,則重複 2、3、5步,將返回值作為 ReactElement 的 children
5、返回 React.createElement(type, props, children)
代碼
const div = document.createElement('div');
div.innerHTML = html;
function makeArray(arrayLike) {
return [].slice.call(arrayLike, 0);
}
function getProps(ele) {
const props = {};
makeArray(ele.attributes).forEach(({ name, value }) => {
props[name === 'class' ? 'className' : name] = value;
});
return props;
}
// Node.nodeValue https://developer.mozilla.org/zh-CN/docs/Web/API/Node/nodeValue
// Node.nodeName https://developer.mozilla.org/zh-CN/docs/Web/API/Node/nodeName
// Element.tagName https://developer.mozilla.org/zh-CN/docs/Web/API/Element/tagName
function transfer(ele) {
if (ele.tagName) {
return React.createElement(ele.tagName, getProps(ele), makeArray(ele.childNodes).map(transfer));
}
return ele.nodeValue;
}
ReactDOM.render(transfer(div.firstElementChild), document.body);
類庫
html2json
將 html 轉為 json的做法與上麵轉為 jsx 的做法雷同。隻不過第 5 步返回的是一個 json 對象,而不是一個 ReactElement。
function getProps(ele) {
const props = {};
makeArray(ele.attributes).forEach(({ name, value }) => {
props[name === 'class' ? 'className' : name] = value;
});
return props;
}
function transfer(ele) {
if (ele.tagName) {
return {
type: ele.tagName,
props: getProps(ele),
children: makeArray(ele.childNodes).map(transfer),
};
}
return ele.nodeValue;
}
console.log(transfer(div.firstElementChild));
最後更新:2017-06-05 15:32:29
上一篇:
測不準原理?記一次Guava隊列問題的排查
下一篇:
他是現代計算機科學的鼻祖,編程界的上帝
《STM32庫開發實戰指南:基於STM32F4》----第3章 初識STM32 3.1 什麼是STM32
Real-Time Personalized Recommendation System
Tomcat5發布項目問題(1):jstl java.lang.NoClassDefFoundError javaxelValueExpression
Windows將有重大調整 或進軍移動終端
Picasso and Android-Universal-Image-Loader緩存框架
CentOS6.2編譯gcc失敗,kernel-headers錯誤
753個大獎邀請各位老博主入駐雲棲,請技術人員廣而告之
Top100論文導讀:深入理解卷積神經網絡CNN(Part Ⅰ)
新技術助力電子商務到新時代
maven項目的測試目錄中報類找不到異常