2015-06-25 1 views
0

Я превращаю компонент React.js в модуль Common.js, используя module.exports, и у меня есть проблема с доступом к этому «элементу» в контексте элемента компонента из одного из его методы.область действия «this» in module.exports

Ниже представлен весь компонент. Я разместил комментарий над строкой, где возникает проблема. Сначала я попробовал менее подробный пример, но я не думаю, что этого было достаточно, чтобы объяснить проблему.

var React = require('react'); 
    var GSAP = require('gsap'); 

    var Psychedelicon = React.createClass({ 

     cycleColors: function() { 
      var touchPlatforms = ['iPhone', 'iPad', 'iPod', 'Android', 'Linux armv7l', 'WinCE']; 
         isTouch = false; 
         iDevice = false; 
         isDroid = false; 
         plat = navigator.platform; 

      if(plat === 'iPhone' || plat === 'iPad' || plat === 'iPod') { 
       isTouch = true; 
       iDevice = true; 
      } 
      else if (plat === 'Linux armv7l' || plat === 'Android') { 
       isTouch = true; 
       isDroid = true; 
      } 
      else { 
       for (var i = 0; i < touchPlatforms.length; i++) { 
        if (plat === touchPlatforms[i]) { 
         isTouch = true; 
         break; 
        } 
        else { 
         isTouch = false; 
        } 
       } 
      } 

      var isIE = false 
       if (navigator.userAgent.toLowerCase().indexOf('msie') > -1 || navigator.userAgent.toLowerCase().indexOf('trident') > -1) { 
       isIE = true 
      } 

      var isFF = false 
       if (navigator.userAgent.toLowerCase().indexOf('firefox') != -1) { 
       isFF = true 
      } 

      if(!isTouch) { 
       var ColorSwirl = function(colorSet,defaultColor,time) { 
        var storedResult; 
        var randomColor = function(theArray) { 
         var result = theArray[Math.floor(Math.random() * (theArray.length))]; 
         if(result === storedResult){ 
          return(defaultColor)       
         } 
         else { 
          storedResult = result; 
          return(result); 
         } 
        } 
        var theLuckyColors = {top:randomColor(colorSet),bottom:randomColor(colorSet)}; 
        var swirl = function(){ 
    //!!!!On this line the problem occurs onUpdateParams must reference the element accepting the execution event (onMouseEneter) 
         TweenLite.to(theLuckyColors, time, {colorProps:{top:randomColor(colorSet), bottom:randomColor(colorSet)}, onUpdate:colorize, onUpdateParams:[this],onComplete:swirl}); 
        } 
gradients 
        var colorize = function(el) { 
         if(isIE) { 
          TweenLite.set(el, { 
           backgroundImage:'-ms-radial-gradient(center,circle cover,' + theLuckyColors.top + ' 0%, ' + theLuckyColors.bottom + ' 100%)' 
          }); 
         } 
         else if(isFF) { 
          TweenLite.set(el, { 
           backgroundImage:'-moz-radial-gradient(center,circle cover,' + theLuckyColors.top + ' 0%, ' + theLuckyColors.bottom + ' 100%)' 
          }); 
         } 
         else { 
          TweenLite.set(el, { 
           backgroundImage:'radial-gradient(circle,' + theLuckyColors.top + ', ' + theLuckyColors.bottom + ')', 
           backgroundImage:'-webkit-radial-gradient(circle,' + theLuckyColors.top + ', ' + theLuckyColors.bottom + ')' 
          }); 
         } 
        } 
        swirl(); 
       } 
       ColorSwirl(['red','green','#4B0082','#9F00FF','yellow','orange'],'blue',.15); 
      } 

     }, 
     stopTheCycle: function() { 

     }, 

     render: function() { 
      return (
       <a className="psychedelicon" href={this.props.href} target={this.props.target} onMouseEnter={this.cycleColors} onMouseLeave={this.stopTheCycle}> 
        <i className={"fa fa-" + this.props.icon}></i> 
       </a> 
      ) 
     } 

    }); 
    module.exports = Psychedelicon; 

До сих пор я пытался связать «это» в элемент, принимающий событие:

onMouseEnter={this.cycleColors.bind(this)} 

и я получил: ` 'Вы связыванием метод компонента к компоненту. React делает это для вас автоматически высокопроизводительным способом, поэтому вы можете безопасно удалить этот вызов ».

Я также попытался:

onMouseEnter={this.cycleColors.call(Psychedelicon)} 

и OnMouseEnter = {this.cycleColors.bind (Psychedelicon)}

которые оба произведены без ошибки, но не работает

Я знаю, что функция работает иначе, потому что когда я меняю

onUpdateParams:[this] 

в

onUpdateParams:['.psychedelicon'] 

Компонент производит желаемое поведение, за исключением того, что он производит эффект все компоненты одновременно (что мне нужно, чтобы избежать необходимости, следовательно, использовать «это»).

Должно быть, что-то не хватает. Любая помощь приветствуется.

+0

ваш второй фрагмент также не работает http://jsfiddle.net/arunpjohny/ssogpue2/1/ –

+0

@ArunPJohny хм ... вы правы, я удалил его – HelloWorld

+0

Попробуйте '$ ('# foo'). нажмите (Module.addClass) '! В вашем html-фрагменте вы даже не * вызываете * метод. – Bergi

ответ

1

Так что я смог решить свою собственную проблему.Вот код, который сделал трюк:

var React = require('react'); 
var GSAP = require('gsap'); 
var $  = require('jquery') 

var Psychedelicon = React.createClass({ 

    componentDidMount: function() { 

     var that = React.findDOMNode(this.refs.psicon); 
     $(that).hover(function() { 
    //detect device type for Psychedelicon 
      var touchPlatforms = ['iPhone', 'iPad', 'iPod', 'Android', 'Linux armv7l', 'WinCE']; 
         isTouch = false; 
         iDevice = false; 
         isDroid = false; 
         plat = navigator.platform; 

      if(plat === 'iPhone' || plat === 'iPad' || plat === 'iPod') { 
       isTouch = true; 
       iDevice = true; 
      } 
      else if (plat === 'Linux armv7l' || plat === 'Android') { 
       isTouch = true; 
       isDroid = true; 
      } 
      else { 
       for (var i = 0; i < touchPlatforms.length; i++) { 
        if (plat === touchPlatforms[i]) { 
         isTouch = true; 
         break; 
        } 
        else { 
         isTouch = false; 
        } 
       } 
      } 

    //sniff the for ie 
      var isIE = false 
       if (navigator.userAgent.toLowerCase().indexOf('msie') > -1 || navigator.userAgent.toLowerCase().indexOf('trident') > -1) { 
       isIE = true 
      } 

    //sniff for firefox 
      var isFF = false 
       if (navigator.userAgent.toLowerCase().indexOf('firefox') != -1) { 
       isFF = true 
      } 


    //Begin ColorSwirl on non-touch devices 
      if(!isTouch) { 
    //Define the Color Sets 
       var ColorSwirl = function(colorSet,defaultColor,time) { 
    //Pick random color. If the color is the same as the previous one pick blue instead. 
        var storedResult; 
        var randomColor = function(theArray) { 
         var result = theArray[Math.floor(Math.random() * (theArray.length))]; 
         if(result === storedResult){ 
          return(defaultColor)       
         } 
         else { 
          storedResult = result; 
          return(result) 
         } 
        } 
    //Pick our colors for the initial state 
        var theLuckyColors = {top:randomColor(colorSet),bottom:randomColor(colorSet)}; 
    //Start swirling 
        $(that).addClass('swirling'); 
        var swirl = function(){ 
         if($(that).hasClass('swirling')) { 
          TweenLite.to(theLuckyColors, time, {colorProps:{top:randomColor(colorSet), bottom:randomColor(colorSet)}, onUpdate:colorize, onUpdateParams:[that],onComplete:swirl}); 
         } 
        } 
    //Detect Browser and Pass Psychedelicon the appropriate radial gradients 
        var colorize = function(el) { 
         if(isIE) { 
          TweenLite.set(el, { 
           backgroundImage:'-ms-radial-gradient(center,circle cover,' + theLuckyColors.top + ' 0%, ' + theLuckyColors.bottom + ' 100%)' 
          }); 
         } 
         else if(isFF) { 
          TweenLite.set(el, { 
           backgroundImage:'-moz-radial-gradient(center,circle cover,' + theLuckyColors.top + ' 0%, ' + theLuckyColors.bottom + ' 100%)' 
          }); 
         } 
         else { 
          TweenLite.set(el, { 
           backgroundImage:'radial-gradient(circle,' + theLuckyColors.top + ', ' + theLuckyColors.bottom + ')', 
           backgroundImage:'-webkit-radial-gradient(circle,' + theLuckyColors.top + ', ' + theLuckyColors.bottom + ')' 
          }); 
         } 
        } 
        swirl(); 
       } 
       ColorSwirl(['red','green','#4B0082','#9F00FF','yellow','orange'],'blue',.15); 
      } 

     },function() { 
      var theLuckyColors = {top:'#FFFFFF',bottom:'#FFFFFF'}; 
      var stopNow = function(time){ 
       $(that).removeClass('swirling'); 
       TweenLite.to(theLuckyColors, time, {colorProps:{top:'#FFFFFF', bottom:'#FFFFFF'}, onUpdate:whiteWash, onUpdateParams:[that]}); 
      } 
      var whiteWash = function(el) { 
        TweenLite.set(el, { 
         backgroundImage:'-ms-radial-gradient(center,circle cover,#FFFFFF 0%, #FFFFFF 100%)', 
         backgroundImage:'-moz-radial-gradient(center,circle cover,#FFFFFF 0%, #FFFFFF 100%)', 
         backgroundImage:'radial-gradient(circle,#FFFFFF,#FFFFFF)', 
         backgroundImage:'-webkit-radial-gradient(circle,#FFFFFF,#FFFFFF)' 
        }); 
      } 
      stopNow(.15);  
     }); 
    }, 
    render: function() { 
     return (
      <a className="psychedelicon" ref="psicon" href={this.props.href} target={this.props.target} onMouseEnter={this.cycleColors} onMouseLeave={this.stopTheCycle}> 
       <i className={"fa fa-" + this.props.icon}></i> 
      </a> 
     ) 
    } 

}) 

module.exports = Psychedelicon; 

Вот как я получил от проблемы к решению:

Когда я не смог получить результат с помощью «вызова», как было предложено @ Александр О'Мар, я обязательно JQuery для ускорения тестирования и добавил переменную

var that = $(this) 

для внешней рамки компоненты, так что я мог бы получить доступ к самому компоненту из сферы внутренних функций следующим образом:

//Note that onUpdateParams now references "that" which is equal to "this" in the scope of the actual component. 
TweenLite.to(theLuckyColors, time, {colorProps:{top:randomColor(colorSet), bottom:randomColor(colorSet)}, onUpdate:colorize, onUpdateParams:[that],onComplete:swirl}); 

это не удалось, поэтому я зарегистрировал значение «this» на консоли и увидел, что я действительно ссылаюсь на конструктор компонента, а не на вывод обработанного!

Я снова посмотрел на docs и увидел, что я могу ссылаться на отображаемый вывод на каждый экземпляр визуализации, используя атрибут reactjs под названием refs. Мне нужно было только дать обработанный элемент в «реф» атрибут:

render: function() { 
     return (
      <a className="psychedelicon" ref="psicon" href={this.props.href} target={this.props.target} onMouseEnter={this.cycleColors} onMouseLeave={this.stopTheCycle}> 
       <i className={"fa fa-" + this.props.icon}></i> 
      </a> 
     ) 
    } 

и ссылка рефа в моем методе, который я решил бежать из «componentDidMount» вместо этого.

var that = React.findDOMNode(this.refs.psicon); 

Теперь, каждый раз, когда я ссылаться на «что» я сам ссылаюсь обработанный элемент (довольно impresive считая, что это вновь делают каждые .15 секунд при наведении курсора мыши), и все это радужно!

1

ОБНОВЛЕНИЕ: Этот ответ не применяется к Реагированию, но был в ответ на более общую предыдущую версию вопроса.


Это выглядит как еще один аргумент в пользу не используя атрибут onclick, но вы можете использовать call или apply метод, и передать this в качестве первого аргумента.

<div id="foo" onClick="Module.addClass.call(this)"></div> 

Однако вы можете рассмотреть возможность использования addEventListener или делегирования событий Jquery вместо этого.

+0

Правильно, но я использую React, поэтому встроенный способ пойти, я думаю ... Я дам вам попытку – HelloWorld

+0

Спасибо за вашу помощь, но это не работает. Я обновил вопрос и добавил код целиком для ясности. – HelloWorld

+0

Хорошо, я решил эту проблему. Из-за проблемы, которую я описал, у React есть способ получить доступ к рендерированному элементу, называемому refs. Я смог использовать это для ссылки на обработанный элемент. Не удалось выполнить код, потому что «this» ссылался на конструктор компонента вместо отображаемого элемента. – HelloWorld

Смежные вопросы