键入动画时的奇怪行为

时间:2015-07-28 12:14:07

标签: javascript regex

当我使用str.replace时,我有一种非常奇怪的行为。我有一个模仿打字的功能,一切都很好,但我添加了选项skipTags,如果设置为true,我使用的是:

str = str.replace(/(<([^>]+)>)/ig,"");

但在那之后动画只打印第一行。键入结束后,将显示所有文本。如果skipTags设置为false,一切正常。

&#13;
&#13;
/*
 *
 *
 *
 * Copyright (c) 2015 Michał Baryś
 * Licensed under the MIT license.
 */
(function($) {
  $.fn.jQueryTypingAnimationPlugin = function(options) {

    var settings = $.extend({
      // These are the defaults.
      startDelay: 0,
      speed: 50,
      skipTags: false,
      onStart: null,
      onTyping: null,
      onComplete: null
    }, options);

    return this.each(function(idx) {
      // Do something to each selected element.


      var $elem = $(this);

      if ($elem.prop("tagName") !== 'INPUT') {

        var sizes = [];
        console.log($elem.css('box-sizing'));
        switch ($elem.css('box-sizing')) {
          // case 'padding-box':
          // 	sizes = [ $(this).innerWidth(), $(this).innerHeight() ];
          // 	console.log('padding-box');
          // break;

          // case 'border-box':
          // 	sizes = [ $(this).outerWidth(), $(this).outerHeight() ];
          // 	console.log('border-box');
          // break;

          default: sizes = [$elem.width(), $elem.height()];
          console.log('content-box');

        }



        $elem.width(sizes[0]);
        $elem.height(sizes[1]);
      }
      $elem.addClass('typing-animation');



      var str,
        i = 0,
        isTag;

      if ($elem.prop("tagName") === 'INPUT') {
        str = $elem.val();
        $elem.val('');
        $elem.focus();
      } else {
        str = $elem.html();
        $elem.html('');
      }


      if (settings.skipTags === true) {
        str = str.replace(/(<([^>]+)>)/ig, "");
      }

      console.log('str', str);


      function type() {

        if (i === 0 && settings.onStart) {
          settings.onStart();
        }

        var text = str.slice(0, ++i);


        if (settings.onTyping) {
          settings.onTyping(i - 1, text.slice(-1), text);
        }
        if ($elem.prop("tagName") === 'INPUT') {
          $elem.val(text);
        } else {
          $elem.html(text);
        }

        var char = text.slice(-1);
        if (char === '<') {
          isTag = true;
        }
        if (char === '>') {
          isTag = false;
        }

        if (isTag) {
          return type();
        }

        if (text === str) {
          $elem.removeAttr('style');
          if (settings.onComplete) {
            settings.onComplete();
          }
          return;
        }

        setTimeout(type, settings.speed);

      };

      setTimeout(type, settings.startDelay);




    });
  };
}(jQuery));


// init plugin
$('p').jQueryTypingAnimationPlugin({
  startDelay: 0,
  speed: 100,
  skipTags: true,
  onStart: function() {
    console.log('start typing');
  },
  onTyping: function(idx, char, text) {
    //console.log( 'on index ' + idx + ' is letter "' + char + '", current text: "'+text+'"' ); 
  },
  onComplete: function() {
    console.log('Typing complete');
  }
});
&#13;
.typing-animation {
  -webkit-transform: translateZ(0);
  -moz-transform: translateZ(0);
  -ms-transform: translateZ(0);
  -o-transform: translateZ(0);
  transform: translateZ(0);
}
.typing-animation:after {
  content: "|";
  -moz-animation: blink 1.1s steps(5, start) infinite;
  -webkit-animation: blink 1.1s steps(5, start) infinite;
  animation: blink 1.1s steps(5, start) infinite;
  font-weight: 100;
  /*width: 10px;
				min-height: 45px;
				height: 100%;
			  background: #000;
			  display: inline-block;*/
}
@-moz-keyframes blink {
  to {
    visibility: hidden;
  }
}
@-webkit-keyframes blink {
  to {
    visibility: hidden;
  }
}
@keyframes blink {
  to {
    visibility: hidden;
  }
}
p {
  background: yellow;
  width: 300px;
  margin: 20px auto;
  padding: 30px;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p><em>Lorem</em> ipsum dolor <a href="#" target="_blank">sit amet</a>, consectetur adipisicing elit. Fuga, similique necessitatibus tenetur beatae suscipit, voluptatum repellat doloremque saepe, in dicta numquam. Ad impedit voluptatum ipsa id, consequuntur
  hic eaque dignissimos minima laboriosam, enim fuga praesentium commodi nisi laudantium non dolores voluptatibus veniam numquam eligendi fugit. Et, voluptas. Cum minus, cupiditate.</p>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:1)

看起来像一个奇怪的浏览器错误。我看不出你的代码有什么问题。

在Chrome中,似乎解决方法是将display: inline-block;添加到应用于闪烁光标的样式中:

.typing-animation:after {
  content: "|";
  -moz-animation: blink 1.1s steps(5, start) infinite;
  -webkit-animation: blink 1.1s steps(5, start) infinite;
  animation: blink 1.1s steps(5, start) infinite;
  font-weight: 100;
  display: inline-block;  /** workaround for Chrome bug **/
}

然而,我没有在任何其他浏览器中测试过这个。

/*
 *
 *
 *
 * Copyright (c) 2015 Michał Baryś
 * Licensed under the MIT license.
 */
(function($) {
  $.fn.jQueryTypingAnimationPlugin = function(options) {

    var settings = $.extend({
      // These are the defaults.
      startDelay: 0,
      speed: 50,
      skipTags: false,
      onStart: null,
      onTyping: null,
      onComplete: null
    }, options);

    return this.each(function(idx) {
      // Do something to each selected element.


      var $elem = $(this);

      if ($elem.prop("tagName") !== 'INPUT') {

        var sizes = [];
        console.log($elem.css('box-sizing'));
        switch ($elem.css('box-sizing')) {
          // case 'padding-box':
          // 	sizes = [ $(this).innerWidth(), $(this).innerHeight() ];
          // 	console.log('padding-box');
          // break;

          // case 'border-box':
          // 	sizes = [ $(this).outerWidth(), $(this).outerHeight() ];
          // 	console.log('border-box');
          // break;

          default: sizes = [$elem.width(), $elem.height()];
          console.log('content-box');

        }



        $elem.width(sizes[0]);
        $elem.height(sizes[1]);
      }
      $elem.addClass('typing-animation');



      var str,
        i = 0,
        isTag;

      if ($elem.prop("tagName") === 'INPUT') {
        str = $elem.val();
        $elem.val('');
        $elem.focus();
      } else {
        str = $elem.html();
        $elem.html('');
      }


      if (settings.skipTags === true) {
        str = str.replace(/(<([^>]+)>)/ig, "");
      }

      console.log('str', str);


      function type() {

        if (i === 0 && settings.onStart) {
          settings.onStart();
        }

        var text = str.slice(0, ++i);


        if (settings.onTyping) {
          settings.onTyping(i - 1, text.slice(-1), text);
        }
        if ($elem.prop("tagName") === 'INPUT') {
          $elem.val(text);
        } else {
          $elem.html(text);
        }

        var char = text.slice(-1);
        if (char === '<') {
          isTag = true;
        }
        if (char === '>') {
          isTag = false;
        }

        if (isTag) {
          return type();
        }

        if (text === str) {
          $elem.removeAttr('style');
          if (settings.onComplete) {
            settings.onComplete();
          }
          return;
        }

        setTimeout(type, settings.speed);

      };

      setTimeout(type, settings.startDelay);




    });
  };
}(jQuery));


// init plugin
$('p').jQueryTypingAnimationPlugin({
  startDelay: 0,
  speed: 100,
  skipTags: true,
  onStart: function() {
    console.log('start typing');
  },
  onTyping: function(idx, char, text) {
    //console.log( 'on index ' + idx + ' is letter "' + char + '", current text: "'+text+'"' ); 
  },
  onComplete: function() {
    console.log('Typing complete');
  }
});
.typing-animation {
  -webkit-transform: translateZ(0);
  -moz-transform: translateZ(0);
  -ms-transform: translateZ(0);
  -o-transform: translateZ(0);
  transform: translateZ(0);
}
.typing-animation:after {
  content: "|";
  -moz-animation: blink 1.1s steps(5, start) infinite;
  -webkit-animation: blink 1.1s steps(5, start) infinite;
  animation: blink 1.1s steps(5, start) infinite;
  font-weight: 100;
  display: inline-block;
}
@-moz-keyframes blink {
  to {
    visibility: hidden;
  }
}
@-webkit-keyframes blink {
  to {
    visibility: hidden;
  }
}
@keyframes blink {
  to {
    visibility: hidden;
  }
}
p {
  background: yellow;
  width: 300px;
  margin: 20px auto;
  padding: 30px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p><em>Lorem</em> ipsum dolor <a href="#" target="_blank">sit amet</a>, consectetur adipisicing elit. Fuga, similique necessitatibus tenetur beatae suscipit, voluptatum repellat doloremque saepe, in dicta numquam. Ad impedit voluptatum ipsa id, consequuntur
  hic eaque dignissimos minima laboriosam, enim fuga praesentium commodi nisi laudantium non dolores voluptatibus veniam numquam eligendi fugit. Et, voluptas. Cum minus, cupiditate.</p>

答案 1 :(得分:1)

使用.text()代替.html()

第92行:

$elem.text(text);

我不知道为什么这样做除了注意浏览器在jQuery的.html()方法中被挂起,但在使用.text()时不会挂起。

值得注意的是,更改字符串会产生影响(请尝试删除necessitatibus之后的空格。)

如果单词边界落在一行的末尾并且没有空间可以闪烁光标,那么浏览器可能与浏览器不知道在哪里重新呈现::after伪元素有关。 / p>

As another answerer noted,只需将CSS中伪元素的display值更改为inline-block即可解决问题。

我怀疑通过使用.html()方法,每次迭代都会重新呈现::after元素,而使用.text()时,只有文本节点在每次迭代时都会更新,所以尝试重新呈现::after元素时,浏览器不会挂起。

/*
 *
 *
 *
 * Copyright (c) 2015 Michał Baryś
 * Licensed under the MIT license.
 */
(function($) {
  $.fn.jQueryTypingAnimationPlugin = function(options) {

    var settings = $.extend({
      // These are the defaults.
      startDelay: 0,
      speed: 50,
      skipTags: false,
      onStart: null,
      onTyping: null,
      onComplete: null
    }, options);

    return this.each(function(idx) {
      // Do something to each selected element.


      var $elem = $(this);

      if ($elem.prop("tagName") !== 'INPUT') {

        var sizes = [];
        console.log($elem.css('box-sizing'));
        switch ($elem.css('box-sizing')) {
          // case 'padding-box':
          // 	sizes = [ $(this).innerWidth(), $(this).innerHeight() ];
          // 	console.log('padding-box');
          // break;

          // case 'border-box':
          // 	sizes = [ $(this).outerWidth(), $(this).outerHeight() ];
          // 	console.log('border-box');
          // break;

          default: sizes = [$elem.width(), $elem.height()];
          console.log('content-box');

        }



        $elem.width(sizes[0]);
        $elem.height(sizes[1]);
      }
      $elem.addClass('typing-animation');



      var str,
        i = 0,
        isTag;

      if ($elem.prop("tagName") === 'INPUT') {
        str = $elem.val();
        $elem.val('');
        $elem.focus();
      } else {
        str = $elem.html();
        $elem.html('');
      }


      if (settings.skipTags === true) {
        str = str.replace(/(<([^>]+)>)/ig, "");
      }

      console.log('str', str);


      function type() {

        if (i === 0 && settings.onStart) {
          settings.onStart();
        }

        var text = str.slice(0, ++i);


        if (settings.onTyping) {
          settings.onTyping(i - 1, text.slice(-1), text);
        }
        if ($elem.prop("tagName") === 'INPUT') {
          $elem.val(text);
        } else {
          $elem.text(text);
        }

        var char = text.slice(-1);
        if (char === '<') {
          isTag = true;
        }
        if (char === '>') {
          isTag = false;
        }

        if (isTag) {
          return type();
        }

        if (text === str) {
          $elem.removeAttr('style');
          if (settings.onComplete) {
            settings.onComplete();
          }
          return;
        }

        setTimeout(type, settings.speed);

      };

      setTimeout(type, settings.startDelay);




    });
  };
}(jQuery));


// init plugin
$('p').jQueryTypingAnimationPlugin({
  startDelay: 0,
  speed: 100,
  skipTags: true,
  onStart: function() {
    console.log('start typing');
  },
  onTyping: function(idx, char, text) {
    //console.log( 'on index ' + idx + ' is letter "' + char + '", current text: "'+text+'"' ); 
  },
  onComplete: function() {
    console.log('Typing complete');
  }
});
.typing-animation {
  -webkit-transform: translateZ(0);
  -moz-transform: translateZ(0);
  -ms-transform: translateZ(0);
  -o-transform: translateZ(0);
  transform: translateZ(0);
}
.typing-animation:after {
  content: "|";
  -moz-animation: blink 1.1s steps(5, start) infinite;
  -webkit-animation: blink 1.1s steps(5, start) infinite;
  animation: blink 1.1s steps(5, start) infinite;
  font-weight: 100;
  /*width: 10px;
				min-height: 45px;
				height: 100%;
			  background: #000;
			  display: inline-block;*/
}
@-moz-keyframes blink {
  to {
    visibility: hidden;
  }
}
@-webkit-keyframes blink {
  to {
    visibility: hidden;
  }
}
@keyframes blink {
  to {
    visibility: hidden;
  }
}
p {
  background: yellow;
  width: 300px;
  margin: 20px auto;
  padding: 30px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p><em>Lorem</em> ipsum dolor <a href="#" target="_blank">sit amet</a>, consectetur adipisicing elit. Fuga, similique necessitatibus tenetur beatae suscipit, voluptatum repellat doloremque saepe, in dicta numquam. Ad impedit voluptatum ipsa id, consequuntur
  hic eaque dignissimos minima laboriosam, enim fuga praesentium commodi nisi laudantium non dolores voluptatibus veniam numquam eligendi fugit. Et, voluptas. Cum minus, cupiditate.</p>