资讯专栏INFORMATION COLUMN

【速记】借助ES6的模版字符串,在不用Babel插件的情况下实现一个轻量级类JSX功能

wayneli / 3253人阅读

摘要:引发此篇文章是看到了阮一峰的在掘金上的转载的作者创建的利用字符串标签模版实现的类的库,可以将标签模版的类字符串转化成类或函数用来创建对象的函数字符串介绍重点阅读模版字符串和标签模版两节浏览器级别将字符串解析成对象原始的思考原文如下

引发此篇文章是看到了阮一峰的twitter在掘金上的转载: https://juejin.im/pin/5bf6463...

Preact 的作者创建的利用字符串标签模版实现的类JSX的库,可以将标签模版的类JSX字符串转化成类React.createElement或h函数(用来创建 virtual DOM对象的函数): https://github.com/developit/htm

ES6字符串介绍(重点阅读模版字符串和标签模版两节):http://es6.ruanyifeng.com/#do...

浏览器级别API将字符串解析成DOM对象:https://developer.mozilla.org...

原始的思考原文如下:

JSX Quasi-Literal

I"ve been struggling to get the JSX transpiler playing nicely with the traceur compiler, specifically the flags hidden behind --experimental.

The problem is that the since both the JSX transpiler and the traceur compiler are actually parsing the full javascript AST, they would have to mutually agree on the syntax extensions you use: traceur can"t parse the faux-xml syntax JSX adds, and JSX can"t parse the async or await keywords, for example, or generator functions.

This proof-of-concept is a potential solution: instead of using an external JSX transpiler, we"ll parse the faux-xml ourselves, using an ES6 feature called quasi-literals.

Example

define(function(require) {
    var React   = require("react");
    var jsx     = require("lib/jsxquasi");
    var EchoComponent = React.createClass({
        getInitialState: function() {
            return { value: "" };
        },
        handleChange: function() {
            this.setState({ value: this.refs.input.getDOMNode().value });
        },
        render: function() {
            return jsx`
                
                                       ${this.state.value}                
           `;       }   })    return function() {        var comp = jsx`<${EchoComponent} />`;        React.renderComponent(comp, document.body);   }; });

A couple of things to notice:

This is valid javascript! Or harmony or es6 or whatever, but importantly, it"s not happening outside the js environment. This also allows us to use our standard tooling: the traceur compiler knows how to turn jsx

Hello
; into the equivalent browser compatible es3, and hence we can use anything the traceur compile accepts!

This is not exactly the same as JSX according to the spec: it includes quotes around the attributes, etc. This is because this parser is based on DOMParser, and hence needs to be valid XML. It would be straighforward though to change it so it matched exactly, or to remove the browser dependency (so it could run on the server, eg.)

index.js

define(function(require) {

    var React = require("react");
    var paramRegex  = /__(d)+/;
    var parser      = new DOMParser();
    var errorDoc    = parser.parseFromString("INVALID", "text/xml");
    var errorNs     = errorDoc.getElementsByTagName("parsererror")[0].namespaceURI;
    // turns the array of string parts into a DOM
    // throws if the result is an invalid XML document.
    function quasiToDom(parts) {
    
        // turn ["
Hi
"]        // into "
Hi
"        var xmlstr = parts.reduce((xmlstr, part, i) => {            xmlstr += part;            if (i != parts.length - 1) { // the last part has no ending param                xmlstr += `__${i}`;           }            return xmlstr;       }, "");       // parse into DOM, check for a parse error       // browser"s DOMParser is neat, but error handling is awful       var doc      = parser.parseFromString(xmlstr, "text/xml");       var errors   = doc.getElementsByTagNameNS(errorNs, "parsererror");       var error    = "";       if (errors.length > 0) {           error = errors[0].textContent.split(" ")[0];           throw `invalid jsx: ${error} ${xmlstr}`;       }       return doc;   }    // turn a document into a tree of react components    // replaces tags, attribute values and text nodes that look like the param    // placeholder we add above, with the values from the parameters array.    function domToReact(node, params) {        var match;                // text node, comment, etc        if (node.nodeValue) {            var value = node.nodeValue.trim();            if (value.length === 0) {                return undefined;           }            match = value.match(paramRegex);            return match ? params[parseInt(match[1])] : value;       }        // node to get react for        // if the node name is a placeholder, assume the param is a component class        var reactNode;        match = node.localName.match(paramRegex)        reactNode = match ? params[parseInt(match[1])] : React.DOM[node.localName];                    // if we don"t have a component, give a better error message        if (reactNode === undefined) {            throw `Unknown React component: ${node.localName}, bailing.`;       }        // attributes of the node        var reactAttrs = {};        for (var i = node.attributes.length - 1; i >= 0; i--) {            var attr = node.attributes[i];            reactAttrs[attr.name] = attr.value;            match = attr.value.match(paramRegex);            if (match) {                reactAttrs[attr.name] = params[parseInt(match[1])];           }       }        // recursively turn children into react components        var reactChildren = [];        for (var i = 0; i < node.childNodes.length; i++) {            var child = node.childNodes[i];            var reactChild = domToReact(child, params);            if (reactChild) {                reactChildren.push(reactChild);           }       }        return reactNode(reactAttrs, reactChildren);   }    return function jsx(parts, ...params) {        var doc     = quasiToDom(parts);        var react   = domToReact(doc.firstChild, params);        return react;   } });

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/99392.html

相关文章

  • webpack实战

    摘要:和类似的预处理器还有等。的用处非常多,包括给自动加前缀使用下一代语法等,目前越来越多的人开始用它,它很可能会成为预处理器的最终赢家。 webpack实战 查看所有文档页面:全栈开发,获取更多信息。快马加鞭,加班加点,终于把这个文档整理出来了,顺便深入地学习一番,巩固知识,就是太累人,影响睡眠时间和质量。极客就是想要把事情做到极致,开始了就必须到达终点。 原文链接:webpack实战,原...

    cyrils 评论0 收藏0
  • 手把手教你从零搭建react局部热加载环境

    摘要:有没有办法实现就局部刷新呢当然是有第十步执行为了实现局部热加载,我们需要添加插件。 前言 用了3个多月的vue自认为已经是一名合格的vue框架api搬运工,对于vue的api使用到达了一定瓶颈,无奈水平有限,每每深入底层观赏源码时候都迷失了自己。 遂决定再找个框架学习学习看看能否突破思维局限,加上本人早已对React、RN技术垂涎已久,于是决定找找教程来学习。无奈第一步就卡在了环境搭...

    quietin 评论0 收藏0
  • ES6,你不得不学!

    摘要:但是,的本质仍然是函数,是构造函数的另外一种写法。报错原生构造函数的继承对于一些原生的构造函数,比如,,,等,在是无法通过方法实现原生函数的内部属性,原生函数内部的无法绑定,内部属性获得不了。 在没有学习 ES6 之前,学习 React,真的是一件非常痛苦的事情。即使之前你对 ES5 有着很好的基础,包括闭包、函数、原型链和继承,但是 React 中已经普遍使用 ES6 的语法,包括 ...

    CKJOKER 评论0 收藏0
  • webpack从零开始

    摘要:一基础配置项目安装安装并新建文件,并初始化文件入口出口配置插件安装配置用来解析文件转译成浏览器可以识别的文件。以形式在页面中插入代码加载文件是否开启代码压缩。 一.基础配置 1.init项目 mkdir react-webpack-demo cd react-webpack-demo mkdir src mkdir dist npm init -y 2.安装webpack 安装webp...

    darkbug 评论0 收藏0
  • React项目从Javascript到Typescript迁移经验总结

    摘要:面对越来越火的,我们公司今年也逐渐开始拥抱。综上所述,我个人觉得是要删除相关的东西,降低项目复杂度。但是有一个例外情况。这个配置项有三个值可选择,分别是和。模式会生成,在使用前不需要再进行转换操作了,输出文件的扩展名为。 抛转引用 现在越来越多的项目放弃了javascript,而选择拥抱了typescript,就比如我们熟知的ant-design就是其中之一。面对越来越火的typesc...

    zhisheng 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<