IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    为React扩展jsReady

    TAT.dnt发表于 2015-04-29 06:47:49
    love 0

    写在前面

    因为用React就会需要写jsx。
    React会将jsx编译成js。然后append到head当中。从fiddler的请求和JSXTransformer源码来看,当在页面使用下面的html时候:

    会发送两次请求react_test.js文件,一次是JSXTransformer发送的,一次是浏览器识别script标签自动发送的。
    上面的react_test.js里面全是jsx语法,和javascript有点像,如:

    var Timer = React.createClass({
        getInitialState: function() {
            return {secondsElapsed: 0};
        },
        tick: function() {
            this.setState({secondsElapsed: this.state.secondsElapsed + 1});
        },
        componentDidMount: function() {
            this.interval = setInterval(this.tick, 1000);
        },
        componentWillUnmount: function() {
            clearInterval(this.interval);
        },
        render: function() {
            return (
                
    Seconds Elapsed: {this.state.secondsElapsed}
    ); } });

    
    React.render(, document.getElementById('timerExample'));

    现在问题来了:

    
    

    上面打印的信息的是undefined。所以迫切地希望能够有个这样的事件,这样就能拿到Timer,也就能够调用它的相关方法:

    React.jsReady(function () {
        console.log(Timer)  //希望这里可以拿到Timer
    })

    主要是为了让封装的多个组件能够更加直接的调用,希望jsx以外的js文件能够拿到jsx内部定义的对象,或者React.render的返回值(React.render的返回值就是该对象的实例)。如:

    var tt=React.render(, document.getElementById('timerExample'));
    上面的tt其实就是Timer的实例(也就是new Timer..)。
    
    需要监听jsx已经编译执行完成,编译执行完成就可以使用jsx内部的变量。那么如果扩展?

    react_jsready.js

    (function (root, factory) {
        if (typeof define === 'function' && define.amd) {
            define(['react', "JSXTransformer"], factory);
        } else if (typeof exports === 'object') {
            module.exports = factory(require('react'), require('JSXTransformer'));
        } else {
            root.returnExports = factory(root.React, root.JSXTransformer);
        }
    }(this, function (React, JSXTransformer) {
        React.jsReady = function (fn) {
            React.jsReady._readyCallbacks.push(fn);
        }
        React.jsReady._readyCallbacks = [];
    
        if (window.addEventListener) {
          window.addEventListener('DOMContentLoaded', runScripts, false);
        } else {
          window.attachEvent('onload', runScripts);
        }
    
        function runScripts() {
            JSXTransformer.runScripts(React.jsReady._readyCallbacks);
        }
    
    }));

    上面是UMD的写法,据说现在已经有AMD\CMD\UMD\KMD了 = =!

    第一步:在react和JSXTransformer下方引用react_jsready.js

          
        
    
         

    第二步:注释掉JSXTransformer.js中的

        if (window.addEventListener) {
          window.addEventListener('DOMContentLoaded', runScripts, false);
        } else {
          window.attachEvent('onload', runScripts);
        }

    第三步:JSXTransformer.js中

    //171行加上
    var  _loadedScriptCount = 0;
    
    //run方法加上(180行左右)
    if (_loadedScriptCount === count) {
      var i = 0, len = callbacks.length;
      for (; i < len; i++) {
          callbacks[i]();
      }
    }
    
    //270行左右
          load(script.src, function(content) {
            result[i].loaded = true;
            result[i].content = content;
            _loadedScriptCount++;
            check();
          }, function() {
              result[i].error = true;
              _loadedScriptCount++;
            check();
          });
        } else {
            _loadedScriptCount++;
       ...
       ...

    这里就不依依列举了,下方了提供演示地址,可自行下载JSXTransformer.js。
    这里的基本原理就是计数,当执行了的jsx和页面的jsx(包括页面内嵌和外链的)的个数相等的时候,去执行注册的回调函数。
    这里需要注意的是:如果不需要jsready这功能,也需要引用该js,因为已经把JSXTransformer.js中的runScripts禁用掉了暴露给外部调用:),改由jsready触发。

    地址

    点击这里: jsready demo
    React的Class base的风格还是非常讨人喜欢的,自我感觉jsready这个特性非常重要,刚接触reactjs半天= =!,欢迎吐槽:)



沪ICP备19023445号-2号
友情链接