实战json、html、jsx的互转

    xiaoxiao2024-05-13  106

    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 作为 Tag2、处理 props 作为 attribute3、如果有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})))
    类库

    react-element-to-jsx-string

    方案二:通过 Babel 直接转

    我们可以指定 Babel 在编译的时候调用某个函数。我们可以通过这个函数来生成我们需要的操作。

    做法
    方法一配置 .babelrc { "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);
    类库

    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

    做法

    1、将 html 片段转成 dom2、读取 dom 的 attributes, 处理特殊的 attribute,作为 ReactElement 的 props3、读取 dom 的 tagName, 作为 ReactElement 的 type4、如果 dom 有 children,则重复 2、3、5步,将返回值作为 ReactElement 的 children5、返回 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);
    类库

    react-magic

    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)); 相关资源:敏捷开发V1.0.pptx
    最新回复(0)