Два трюка . В основном, инвертирование HTML-кода ваших желаемых элементов в HTML и использование ~
Оператора следующего сиблинга :
float-right
+ инвертирует порядок HTML элементы
div{ /* Do with the parent whatever you know just to make the
inner float-right elements appear where desired */
display:inline-block;
}
span{
float:right; /* float-right the elements! */
}
span:hover ~ span{ /* On hover target it's "previous";) elements */
background:red;
}
<div>
<!-- Reverse the order of inner elements -->
<span>5</span>
<span>4</span>
<span>3</span>
<span>2</span>
<span>1</span>
</div>
direction: rtl;
+ инвертирует порядок внутренних элементов
.inverse{
direction: rtl;
display: inline-block; /* inline-block to keep parent at the left of window */
}
span:hover ~ span{ /* On hover target it's "previous";) elements */
background:gold;
}
Hover one span and see the previous elements being targeted!<br>
<div class="inverse">
<!-- Reverse the order of inner elements -->
<span>5</span>
<span>4</span>
<span>3</span>
<span>2</span>
<span>1</span>
</div>
Не используйте тайм-ауты. Это эффективный eval
, который является Bad Thing. Он работает, потому что он преобразует currentaudio.id
и noteTime
в строковые представления самих себя и скрывает его в коде. Это работает только до тех пор, пока эти значения имеют toString()
s, которые генерируют буквенный синтаксис JavaScript, который воссоздает значение, которое истинно для Number
, но не для других.
setTimeout(playNote(currentaudio.id, noteTime), delay);
- это функция вызов. playNote
вызывается немедленно, и возвращаемый результат функции (возможно undefined
) передается на setTimeout()
, а не на то, что вы хотите.
Как упоминаются другие ответы, вы можете использовать встроенное выражение функции с закрытием ссылки currentaudio
и noteTime
:
setTimeout(function() {
playNote(currentaudio.id, noteTime);
}, delay);
Однако, если вы находитесь в цикле, а currentaudio
или noteTime
каждый раз различаются по циклу, у вас возникла проблема замкнутого контура: в каждый тайм-аут будет указана одна и та же переменная, поэтому при их вызове вы будете получать одинаковое значение каждый раз, значение, которое осталось в переменной, когда цикл был закончен ранее.
Вы можете обойти это с помощью другого закрытия , взяв копию значения переменной для каждой итерации цикла:
setTimeout(function() {
return function(currentaudio, noteTime) {
playNote(currentaudio.id, noteTime);
};
}(currentaudio, noteTime), delay);
, но это становится немного теперь уродливо. Лучше Function#bind
, что частично применит для вас функцию:
setTimeout(playNote.bind(window, currentaudio.id, noteTime), delay);
(window
для установки значения this
внутри функции, что является признаком bind()
вам здесь не нужно.)
Однако это функция ECMAScript Fifth Edition, которая еще не поддерживается всеми браузерами. Поэтому, если вы хотите использовать его, вам нужно сначала взломать поддержку, например ::
// Make ECMA262-5 Function#bind work on older browsers
//
if (!('bind' in Function.prototype)) {
Function.prototype.bind= function(owner) {
var that= this;
if (arguments.length<=1) {
return function() {
return that.apply(owner, arguments);
};
} else {
var args= Array.prototype.slice.call(arguments, 1);
return function() {
return that.apply(owner, arguments.length===0? args : args.concat(Array.prototype.slice.call(arguments)));
};
}
};
}
Попробуйте это.
setTimeout(function() { playNote(currentaudio.id,noteTime) }, delay);
Поскольку второй из них вы говорите ему сначала вызвать функцию playNote, а затем передать возвращаемое значение из него в setTimeout.
Я буквально создал учетную запись на этом сайте, чтобы прокомментировать ответ Питера Айтай (в настоящее время самый высокий голос), только чтобы обнаружить, что вам требуется 50 rep (что бы это ни было), чтобы комментировать, поэтому я сделаю это как ответ, так как это вероятно, стоит отметить пару вещей.
В своем ответе он утверждает следующее:
Вы также можете передать
setTimeout
ссылку, так как ссылка не выполняется немедленно, но тогда вы не можете передавать аргументы:blockquote>setTimeout(playNote, delay);
Это неверно. После предоставления
setTimeout
значения функции и суммы задержки любые дополнительные аргументы анализируются как аргументы для ссылочной функции. Нижеследующее будет лучше, чем завершение вызова функции в функции.setTimeout(playNote, delay, currentaudio.id, noteTime)
Всегда обращайтесь к документам.
Тем не менее, как указывает Питер, рекурсивная функция будет хорошая идея, если вы хотите изменить задержку между каждым
playNote()
или подумайте об использованииsetInterval()
, если вы хотите, чтобы между каждойplayNote()
была такая же задержка.Также стоит отметить, что если вы хотите для синтаксического анализа
i
вашего цикла for вsetTimeout()
, вам нужно обернуть его в функцию, как описано здесь .
Первая форма, которую вы перечислите, работает, так как она будет оценивать строку в конце delay
. Использование eval()
, как правило, не является хорошей идеей, поэтому вам следует избегать этого.
Второй метод не работает, поскольку вы немедленно выполняете объект функции с помощью оператора функции ()
. Что происходит, так это то, что playNote
выполняется немедленно, если вы используете форму playNote(...)
, поэтому в конце задержки ничего не произойдет.
Вместо этого вы должны передать анонимную функцию setTimeout , поэтому правильная форма:
setTimeout(function() { playNote(currentaudio.id,noteTime) }, delay);
Обратите внимание, что вы передаете setTimeout
целое функциональное выражение, поэтому он будет удерживать анонимную функцию и выполнять ее только в конце задержки.
Вы также можете передать setTimeout
ссылку, так как ссылка не выполняется немедленно, но затем вы не можете передавать аргументы:
setTimeout(playNote, delay);
Примечание:
Для повторных событий вы можете использовать setInterval()
, и вы можете установить setInterval()
на переменную и использовать переменную, чтобы остановить интервал с помощью clearInterval()
.
Вы говорите, что используете setTimeout()
в цикле for
. Во многих ситуациях лучше использовать setTimeout()
в рекурсивной функции. Это связано с тем, что в цикле for
переменные, используемые в setTimeout()
, не будут такими переменными, какими они были, когда начался setTimeout()
, но переменные, как они есть после задержки при запуске функции.
Просто используйте рекурсивную функцию, чтобы обойти эту проблему.
// Set original delay
var delay = 500;
// Call the function for the first time, to begin the recursion.
playNote(xxx, yyy);
// The recursive function
function playNote(theId, theTime)
{
// Do whatever has to be done
// ...
// Have the function call itself again after a delay, if necessary
// you can modify the arguments that you use here. As an
// example I add 20 to theTime each time. You can also modify
// the delay. I add 1/2 a second to the delay each time as an example.
// You can use a condition to continue or stop the recursion
delay += 500;
if (condition)
{ setTimeout(function() { playNote(theID, theTime + 20) }, delay); }
}
playNote
добавит запись в цепочку замыкания, длина которой будет неограниченно увеличиваться. Подобно бесконечной рекурсии, это BAD IDEA - вы в конечном итоге исчерпаете память! Я отредактировал ответ, чтобы показать, как избежать этого, сохраняя при этом метод в целом.
– Doin
12 May 2016 в 18:20