使用Typedjs

时间:2018-03-15 04:59:54

标签: javascript html css audio typedjs

我想用声音制作逼真的打字效果。我使用的是Typed.js,我已经创建了一个简单的例子。

这是我的代码:



var keystrokeSound = new Audio('http://www.freesfx.co.uk/rx2/mp3s/6/18660_1464810669.mp3');

function playSound () {
    keystrokeSound.pause();
    keystrokeSound.currentTime = 0;
    keystrokeSound.play();
}

var typed = new Typed('.element', {
    strings: ["Play sound each I type character", "It's only play on start of string"],
    typeSpeed: 50,
    preStringTyped : function(array, self){
        playSound();
    }
});

.typed-cursor{
  opacity: 1;
  animation: typedjsBlink 0.7s infinite;
  -webkit-animation: typedjsBlink 0.7s infinite;
          animation: typedjsBlink 0.7s infinite;
}
@keyframes typedjsBlink{
  50% { opacity: 0.0; }
}
@-webkit-keyframes typedjsBlink{
  0% { opacity: 1; }
  50% { opacity: 0.0; }
  100% { opacity: 1; }
}

.typed-fade-out{
  opacity: 0;
  transition: opacity .25s;
  -webkit-animation: 0;
          animation: 0;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/typed.js/2.0.6/typed.min.js"></script>
<span class="element" style="white-space:pre"></span>
&#13;
&#13;
&#13;

打字效果的作用是例外。但没有声音,声音只播放时只有第一个字句。我已经阅读了docs,但我找不到每个键入的字符的回调。如何在每个打字的字符上播放声音?

这里是fiddle

5 个答案:

答案 0 :(得分:1)

尝试此代码:

&#13;
&#13;
var keystrokeSound = new Audio('http://www.freesfx.co.uk/rx2/mp3s/6/18660_1464810669.mp3');
var interval ;
    function playSound () {
         clearInterval(interval);
         interval = setInterval(function(){
                 keystrokeSound.pause();
                 keystrokeSound.currentTime = 0;
                 keystrokeSound.play();
         },220);
    }

    var typed = new Typed('.element', {
        strings: ["Play sound each I type character", "It's only play on start of string"],
        typeSpeed: 100,
        preStringTyped : function(array, self){
            playSound();
        },
        onStringTyped : function(array, self){
            clearInterval(interval);
        },
        onComplete: function(array, self){
            clearInterval(interval);
        }
    });
&#13;
.typed-cursor{
      opacity: 1;
      animation: typedjsBlink 0.7s infinite;
      -webkit-animation: typedjsBlink 0.7s infinite;
              animation: typedjsBlink 0.7s infinite;
    }
    @keyframes typedjsBlink{
      50% { opacity: 0.0; }
    }
    @-webkit-keyframes typedjsBlink{
      0% { opacity: 1; }
      50% { opacity: 0.0; }
      100% { opacity: 1; }
    }

    .typed-fade-out{
      opacity: 50;
      transition: opacity .25s;
      -webkit-animation: 0;
              animation: 0;
    }
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/typed.js/2.0.6/typed.min.js"></script>
    <span class="element" style="white-space:pre"></span>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

你也可以尝试循环声音,并从typed.js调用onStringTyped方法:

&#13;
&#13;
import { Injectable } from '@angular/core';
import { NgModule } from '@angular/core';
import { OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { Mobster } from './mobster.model';
import 'rxjs/add/operator/map';

@Injectable()
export class DataService {
  url = 'http://localhost:3000/api/mobsters' || 'https://mobster-api.herokuapp.com/api/mobsters';
  constructor(private http: HttpClient) { }

  getData() {
    return this.http.get(this.url);
  }

}
&#13;
var keystrokeSound = new Audio('http://www.freesfx.co.uk/rx2/mp3s/6/18660_1464810669.mp3');

function playSound () {
    if (typeof keystrokeSound.loop == 'boolean')
    {
        keystrokeSound.loop = true;
    }
    else
    {
        keystrokeSound.addEventListener('ended', function() {
            this.currentTime = 0;
            this.play();
        }, false);
    }
    keystrokeSound.play();
}

function stopSound () {
    keystrokeSound.pause();
}

var typed = new Typed('.element', {
    strings: ["Play sound each I type character", "It's only play on start of string"],
    typeSpeed: 50,
    preStringTyped : function(array, self){
        playSound();
    },
    onStringTyped : function(array, self){
        stopSound();
    }    
});
&#13;
.typed-cursor{
  opacity: 1;
  animation: typedjsBlink 0.7s infinite;
  -webkit-animation: typedjsBlink 0.7s infinite;
          animation: typedjsBlink 0.7s infinite;
}
@keyframes typedjsBlink{
  50% { opacity: 0.0; }
}
@-webkit-keyframes typedjsBlink{
  0% { opacity: 1; }
  50% { opacity: 0.0; }
  100% { opacity: 1; }
}

.typed-fade-out{
  opacity: 0;
  transition: opacity .25s;
  -webkit-animation: 0;
          animation: 0;
}
&#13;
&#13;
&#13;

答案 2 :(得分:1)

回答我自己的问题,最好的方法是直接编辑源代码,并为每个键入的char创建一个回调。我只是编辑了一点源代码(未压缩版本)

找到typewrite函数,并在函数结束前添加此脚本

// fires callback function
this.options.onCharAppended(substr.charAt(0), this);

另外,找到了defaults对象,有回调的默认函数集合,我只是添加

onCharAppended: function onCharAppended(char, self){},

然后我可以使用额外的回调播放同步和精确时间的声音

var typed = new Typed('.element', {
    strings: ["Test ^1000 with delay"],
    typeSpeed: 100,
    onCharAppended : function(char, self){
        playSound();
    }
});

答案 3 :(得分:0)

我想最好的方法是直接调整源代码,以便使这样的事件可用。

以下是我现在最好的尝试结果,使用Web Audio API以尽可能最佳的计时精度触发声音,并且...它不是那么棒......

无论出于何种原因,打字代码似乎不是很规律,我怀疑是有问题,但是不能确定,并且还不想解剖插件的来源

无论如何,这是我的尝试,如果它可以暂时帮助你。

&#13;
&#13;
/* A simple player using the Web Audio API */
class Player {
  constructor(url) {
    this.media_url = url;
  }
  init() {
    this.ctx = new AudioContext();
    return fetch(this.media_url)
      .then(resp => resp.arrayBuffer())
      .then(buf => this.ctx.decodeAudioData(buf))
      .then(audioBuffer => this.audioBuffer = audioBuffer);
  }
  play() {
    const node = this.ctx.createBufferSource();
    node.buffer = this.audioBuffer;
    node.connect(this.ctx.destination);
    node.start(0);
  }
}

// I have absolutely no rights on the given sound so neither do any reader
// If authors have concerns about it, simply leave me a comment, I'll remove right away
const keystrokePlayer = new Player('https://dl.dropboxusercontent.com/s/hjx4xlxyx39uzv7/18660_1464810669.mp3');

function playSound (string, delay) {
  // It seems space is typed twice?
  const l = string.length + string.match(/\s/g).length;
  let current = 0;
  function loop() {
    // start our sound (1 time)
    keystrokePlayer.play();
    // if all have been played stop
    if(current++ >= l) return;
    // otherwise restart in 'delay' ms
    setTimeout(loop, delay);
  }
  loop();
}
// load our sound
keystrokePlayer.init().then(()=> {
  inp.disabled = false;
  btn.onclick();
});

btn.onclick = e => {
  var elem = makeNewElem();
  var typed = new Typed(elem, {
      strings: ["Play sound each I type character", "It's only play on start of string"],
      typeSpeed: +inp.value || 50,
      preStringTyped : function(index, self){
        const opts = self.options;
        playSound(opts.strings[index], opts.typeSpeed);
      }
  });
};
function makeNewElem(){
  var cont = document.createElement('div');
  var elem = document.createElement('span');
  elem.classList.add('element');
  cont.appendChild(elem);
  document.body.appendChild(cont);
  return elem;
}
&#13;
.typed-cursor{
  opacity: 1;
  animation: typedjsBlink 0.7s infinite;
  -webkit-animation: typedjsBlink 0.7s infinite;
          animation: typedjsBlink 0.7s infinite;
}
@keyframes typedjsBlink{
  50% { opacity: 0.0; }
}
@-webkit-keyframes typedjsBlink{
  0% { opacity: 1; }
  50% { opacity: 0.0; }
  100% { opacity: 1; }
}

.typed-fade-out{
  opacity: 0;
  transition: opacity .25s;
  -webkit-animation: 0;
          animation: 0;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/typed.js/2.0.6/typed.min.js"></script>
<label>typeSpeed (ms)<input id="inp" type="number" value="50"><button id="btn">do it</button></label><br>
&#13;
&#13;
&#13;

答案 4 :(得分:0)

我的解决方案有点不同。我使用音频的持续时间和playbackRate属性将音频同步到打字速度:

var typeSpeed = (audio.duration * 1000) / audio.playbackRate;

然后将onCompletepreStringTyped道具添加到option对象:

var options = {
    typeSpeed: typeSpeed,
    preStringTyped: (arrPos) => {
         // Start the playing the looped audio when the typing's about to start
         audio.loop = true;
         audio.play();
    },
    onComplete: () => {
         // When the typing ends we stop the looping
         audio.loop = false;
         audio.stop();
    }
}

这会产生令人信服的重复输入声音效果。

或者,如果您想获得更多随机效果,则可以在preStringTyped函数中启动声音,并在其中保留一个标记来代替audio.loop(例如repeat = true)。然后,您将为onend事件添加一个事件侦听器,如果repeat标志仍处于打开状态,则再次播放音频。除非这次您选择随机音频文件播放。最后,在onComplete回调中,停止当前播放的音频并将repeat标志设置为false