好吧,我得到了這一切工作。這是一個醜陋的黑客,但它的作品。基本上,我將類的每個新實例都存儲在一個數組中,並且將數組鍵(1,2等)傳遞到類中,因此它可以在幾個關鍵位置根據需要在外部引用它自己。
我需要該類在外部引用自己的位置是我傳遞給addEventListener的字符串,並且在一些setTimeout函數中,「this」顯然丟失了它的上下文(就我而言,無論如何,因爲唯一的這樣我可以他們的工作是不斷變化的「本」使用外部引用來代替。
下面是完整的代碼。
在已Youtube視頻的頁面,他們正在使用SWFObject注入該_ytmeta對象存儲的標題爲每個視頻都是可選的,但是它是登錄視頻標題的唯一方式,因爲Youtube的API不會提供給你,這意味着你必須事先知道標題,但是點i 。只不過,如果你想要的標題在我們的報告中顯示,你必須創建該對象:
<div id='yt1'></div>
<script src='youtube.js'></script>
<script src='swfobject.js'></script>
<script>
var _ytmeta = {}
_ytmeta.yt1 = { 'title': 'Moonwalking in Walmart' };
var params = { allowScriptAccess: "always" };
swfobject.embedSWF("http://www.youtube.com/v/gE1ZvCnwkYk?enablejsapi=1&playerapiid=yt1", "yt1", "425", "356", "8", null, null, params);
</script>
所以我們包括SWFObject的JavaScript代碼,還有youtube.js文件,該文件託管在我們的服務器上,幷包含在您要跟蹤視頻的頁面上。
這裏是youtube.js的內容:
// we're storing each youtube object (video) in an array, and passing the array key into the class, so the class instance can refer to itself externally
// this is necessary for two reasons
// first, the event listener function we pass to Youtube has to be globally accessible, so passing "this.blah" doesn't work
// it has to be passed as a string also, so putting "this" in quotes makes it lose its special meaning
// second, when we create timeout functions, the meaning of "this" inside that function loses its scope, so we have to refer to the class externally from there too.
// _yt is the global youtube array that stores each youtube object. yti is the array key, incremented automatically for each new object created
var _yt = [], _yti = 0;
// this is the function the youtube player calls once it's loaded.
// each time it's called, it creates a new object in the global array, and passes the array key into the class so the class can refer to itself externally
function onYouTubePlayerReady(id) {
_yti++;
_yt[ _yti ] = new _yta(id, _yti);
}
function _yta(id, i) {
if(!id || !i) return;
this.id = id;
this.mytime;
this.scrubTimer;
this.startTimer;
this.last = 'none';
this.scrubbing = false;
this.o = document.getElementById(this.id);
this.o.addEventListener("onStateChange", "_yt["+i+"].onPlayerStateChange");
this.onPlayerStateChange = function(newState) {
// some events rely on a timer to determine what action was performed, we clear it on every state change.
if(this.myTime != undefined) clearTimeout(this.myTime);
// pause - happens when clicking pause, or seeking
// that's why a timeout is used, so if we're seeking, once it starts playing again, we log it as a seek and kill the timer that would have logged the pause
// we're only giving it 2 seconds to start playing again though. that should be enough for most users.
// if we happen to log a pause during the seek - so be it.
if(newState == '2') {
this.myTime = setTimeout(function() {
_yt[i].videoLog('pause');
_yt[i].last = 'pause';
_yt[i].scrubbing = false;
}, 2000);
if(this.scrubbing == false){
this.last = 'pre-scrub';
this.scrubbing = true;
}
}
// play
else if(newState == '1') {
switch(this.last) {
case 'none':
this.killTimers();
this.startTimer = setInterval(this.startRun, 200);
break;
case 'pause':
this.myTime = setTimeout(function() {
_yt[i].videoLog('play');
_yt[i].last = 'play';
}, 2000);
break;
case 'pre-scrub':
this.killTimers();
this.scrubTimer = setInterval(this.scrubRun, 200);
break;
}
}
// end
else if(newState == '0') {
this.last = 'none';
this.videoLog('end');
}
}
// have to use external calls here because these are set as timeouts, which makes "this" change context (apparently)
this.scrubRun = function() {
_yt[i].videoLog('seek');
_yt[i].killTimers();
_yt[i].last = 'scrub';
_yt[i].scrubbing = false;
}
this.startRun = function() {
_yt[i].videoLog('play');
_yt[i].killTimers();
_yt[i].last = 'start';
}
this.killTimers = function() {
if(this.startTimer) {
clearInterval(this.startTimer);
this.startTimer = null;
}
if(this.scrubTimer){
clearInterval(this.scrubTimer);
this.scrubTimer = null;
}
}
this.videoLog = function(action) {
clicky.video(action, this.videoTime(), this.videoURL(), this.videoTitle());
}
this.videoTime = function() {
return Math.round(this.o.getCurrentTime());
}
this.videoURL = function() {
return this.o.getVideoUrl().split('&')[0]; // remove any extra parameters - we just want the first one, which is the video ID.
}
this.videoTitle = function() {
// titles have to be defined in an external object
if(window['_ytmeta']) return window['_ytmeta'][ this.id ].title || '';
}
}
希望有人將來會有所幫助,因爲它是在屁股疼痛嚴重得到它的工作!
謝謝大家誰發佈了他們的想法在這裏。 :)
假設'this'實際上指向你認爲當'var me = this;'執行時,你能不能把this.onPlayerStateChange分配給一個變量,然後將_that_傳遞給'使用addEventListener()'?例如:'var callback = this.onPlayerStateChange; //稍後this.addEventListener(「onStateChange」,回調);' – 2010-07-28 23:31:26
我也試過了。我忘記在我的文章中加入這個內容,我將其添加進來,但收到答案後您無法編輯帖子:\ – Sean 2010-07-28 23:57:14