我正在尝试编写一个函数,其中一部分只运行一次。到目前为止我已经完成了它的工作,但我理想的是它可以在不添加全局变量的情况下工作。我已经阅读了关于闭包但我要么不理解它们,要么我不能让我的实例工作。
请记住,这是我第一次尝试使用vanilla javascript而非jQuery的项目。所以没有jQuery的答案。
这是我的代码:
var videoLoaded = false;
function loadItem(element) {
// If item is Video
if( element.tagName == 'VIDEO' ) {
if(videoLoaded != true) {
// Load and play the video;
element.setAttribute('preload', 'auto');
element.play();
videoLoaded = true;
/* Push the dimensions through
* to the videoFill function
*/
element.addEventListener( 'loadedmetadata', function(e) {
var dimensions = [element.videoWidth, element.videoHeight, document.documentElement.clientWidth, document.documentElement.clientHeight]
videoFill(element, dimensions);
});
}
dimensions = [element.videoWidth, element.videoHeight, document.documentElement.clientWidth, document.documentElement.clientHeight]
videoFill(element, dimensions);
}
}
感谢您的帮助!
答案 0 :(得分:1)
首次通话后更换功能
function loadItem(element) {
// Code
// replace function with dummy function
// next time when it will be called, will do nothing
loadItem = function() {
dimensions = [element.videoWidth, element.videoHeight, document.documentElement.clientWidth, document.documentElement.clientHeight]
videoFill(element, dimensions);
};
}
答案 1 :(得分:1)
以下是如何使用闭包(在本例中为立即调用的函数表达式[IIFE])来防止创建全局变量:
var loadItem = (function() { // This function will be immediately invoked
var videoLoaded = false; // This var only exists in our IIFE context, not global scope
function loadItem(element) {
if( element.tagName == 'VIDEO' ) {
// loadItem() will still have access to videoLoaded even after the IIFE has completed and returned
if(videoLoaded != true) {
element.setAttribute('preload', 'auto');
element.play();
videoLoaded = true;
element.addEventListener( 'loadedmetadata', function(e) {
var dimensions = [element.videoWidth, element.videoHeight, document.documentElement.clientWidth, document.documentElement.clientHeight]
videoFill(element, dimensions);
});
}
dimensions = [element.videoWidth, element.videoHeight, document.documentElement.clientWidth, document.documentElement.clientHeight]
videoFill(element, dimensions);
}
}
return loadItem; // Return the function
}()); // Immediately invoke the IIFE closure
答案 2 :(得分:1)
使用像这样的帮手
var once = function (fn) {
var ran = false;
return function () {
if (!ran) {
ran = true;
return fn.apply(null, arguments);
}
};
};
将您只希望运行一次的代码解压缩到函数
var runMeOnce = once(function (msg) {
console.log(msg);
});
var doSomething = function () {
setInterval(function () {
runMeOnce("you will only see this once");
}, 1000);
};
或者您可以采用OO方法并将其包装在类
中var VideoLoader = function (element) {
this.loaded = false;
this.el = element;
};
VideoLoader.prototype.fill = function (dimensions) {
// ?
};
VideoLoader.prototype.load = function () {
var element = this.el,
_this = this;
// If item is Video
if( element.tagName == 'VIDEO' ) {
if(this.loaded != true) {
// Load and play the video;
element.setAttribute('preload', 'auto');
element.play();
this.loaded = true;
/* Push the dimensions through
* to the videoFill function
*/
element.addEventListener( 'loadedmetadata', function(e) {
var dimensions = [
element.videoWidth,
element.videoHeight,
document.documentElement.clientWidth,
document.documentElement.clientHeight
];
_this.fill(dimensions);
});
}
dimensions = [
element.videoWidth,
element.videoHeight,
document.documentElement.clientWidth,
document.documentElement.clientHeight
];
this.fill(dimensions);
}
};
答案 3 :(得分:0)
使用函数的参数来存储全局(这样你不需要闭包):
var f = function(){if(!f.b)alert('x');f.b = true;}
以上功能会提醒" x"只有一次。
答案 4 :(得分:0)
videoLoaded不一定需要是全球性的。您可以使用模块模式:
var itemLoader = (function (videoFill) {
'use strict';
var videoLoaded = false;
return {
load: function (element) {
var dimensions;
if (element.tagName === 'VIDEO') {
if (videoLoaded !== true) {
// Load and play the video;
element.setAttribute('preload', 'auto');
element.play();
videoLoaded = true;
/* Push the dimensions through
* to the videoFill function
*/
element.addEventListener('loadedmetadata', function (e) {
var dimensions = [element.videoWidth, element.videoHeight, document.documentElement.clientWidth, document.documentElement.clientHeight]
videoFill(element, dimensions);
});
}
dimensions = [element.videoWidth, element.videoHeight, document.documentElement.clientWidth, document.documentElement.clientHeight]
videoFill(element, dimensions);
}
}
};
}(window.videoFill));
itemLoader.load(document.getElementById('your-video'));