實戰json、html、jsx的互轉

全文連接html

jsx2html

場景

將下面的jsx轉換爲htmlnode

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 的 attributereact

作法

一、獲取 displayName 做爲 Tag
二、處理 props 做爲 attribute
三、若是有children,則重複一、二、三、4,遍歷 children,做爲子元素
四、拼裝 html 字符串git

代碼
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})))
類庫

react-element-to-jsx-stringgithub

方案二:經過 Babel 直接轉

咱們能夠指定 Babel 在編譯的時候調用某個函數。咱們能夠經過這個函數來生成咱們須要的操做。json

作法
  • 方法一 配置 .babelrcjson { "plugins": [ ["transform-react-jsx", { "pragma": "dom" // default pragma is React.createElement }] ] }babel

可是這種方法修改所有的 babel 轉換行爲。很是不推薦dom

  • 方法二ide

在代碼中加一個註釋/** @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);
類庫

vhtml

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' id="18" 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

作法

一、將 html 片斷轉成 dom二、讀取 dom 的 attributes, 處理特殊的 attribute,做爲 ReactElement 的 props三、讀取 dom 的 tagName, 做爲 ReactElement 的 type四、若是 dom 有 children,則重複 二、三、5步,將返回值做爲 ReactElement 的 children五、返回 React.createElement(type, props, children)

相關文章
相關標籤/搜索