感谢 akinuri,我设法将他的答案改编为在 requestanimationframe 上运行的动态函数。再次感谢 akinuri,很好的代码。ps: currentColor 和 targetColor 请求一个带有 rgb 值的字符串('rgb(0,0,0)')
function startColorFade(fps, duration, element, currentColor, targetColor) {
var stop = false;
var fpsInterval = 1000 / fps;
var now;
var then = Date.now();
var elapsed;
var startTime = then;
var currentColorArray = getElementBG(currentColor);
var targetColorArray = getElementBG(targetColor);
var distance = calculateDistance(currentColorArray, targetColorArray);
var increment = calculateIncrement(distance, fps, duration);
animateColor(duration, element, currentColorArray, targetColorArray, increment, stop, fpsInterval, now, then, elapsed, startTime);
}
function animateColor( duration, element, currentColorArray, targetColorArray, increment, stop, fpsInterval, now, then, elapsed, startTime ) {
var step = function() {
if (stop) {
return;
}
// request another frame
requestAnimationFrame(function() //arguments can passed on the callback by an anonymous funtion
{
animateColor(duration, element, currentColorArray, targetColorArray, increment, stop, fpsInterval, now, then, elapsed, startTime);
colorTransition(element, currentColorArray, targetColorArray, increment);
});
// calc elapsed time since last loop
now = Date.now();
elapsed = now - then;
// if enough time has elapsed, draw the next frame
if (elapsed > fpsInterval) {
// Get ready for next frame by setting then=now, but...
// Also, adjust for fpsInterval not being multiple of 16.67
then = now - (elapsed % fpsInterval);
// draw stuff here
var sinceStart = now - startTime;
}
if (sinceStart / 1000 * 100 >= duration * 100)
{
stop = true;
}
}
step();
}
function colorTransition(element, currentColorArray, targetColorArray, increment) {
// checking R
if (currentColorArray[0] > targetColorArray[0]) {
currentColorArray[0] -= increment[0];
if (currentColorArray[0] <= targetColorArray[0]) {
increment[0] = 0;
}
} else {
currentColorArray[0] += increment[0];
if (currentColorArray[0] >= targetColorArray[0]) {
increment[0] = 0;
}
}
// checking G
if (currentColorArray[1] > targetColorArray[1]) {
currentColorArray[1] -= increment[1];
if (currentColorArray[1] <= targetColorArray[1]) {
increment[1] = 0;
}
} else {
currentColorArray[1] += increment[1];
if (currentColorArray[1] >= targetColorArray[1]) {
increment[1] = 0;
}
}
// checking B
if (currentColorArray[2] > targetColorArray[2]) {
currentColorArray[2] -= increment[2];
if (currentColorArray[2] <= targetColorArray[2]) {
increment[2] = 0;
}
} else {
currentColorArray[2] += increment[2];
if (currentColorArray[2] >= targetColorArray[2]) {
increment[2] = 0;
}
}
// apply the new modified color
element.style.backgroundColor = rgb2hex(currentColorArray);
}
function getElementBG(elmBGColor) {
var bg = elmBGColor; // i.e: RGB(255, 0, 0)
bg = bg.match(/\((.*)\)/)[1];
bg = bg.split(",");
for (var i = 0; i < bg.length; i++) {
bg[i] = parseInt(bg[i], 10);
}
if (bg.length > 3) { bg.pop(); }
return bg; // return array
}
function calculateDistance(colorArray1, colorArray2) {
var distance = [];
for (var i = 0; i < colorArray1.length; i++) {
distance.push(Math.abs(colorArray1[i] - colorArray2[i]));
}
return distance;
}
function calculateIncrement(distanceArray, fps, duration) {
var increment = [];
for (var i = 0; i < distanceArray.length; i++) {
increment.push(Math.abs(Math.floor(distanceArray[i] / (fps * duration))));
if (increment[i] == 0) {
increment[i]++;
}
}
return increment;
}
function rgb2hex(colorArray) {
var hex = [];
for (var i = 0; i < colorArray.length; i++) {
hex.push(colorArray[i].toString(16));
if (hex[i].length < 2) { hex[i] = "0" + hex[i]; }
}
return "#" + hex.join("");
}
//random rgb values in array, very nice
function generateRGB(min, max) {
var min = min || 0;
var max = max || 255;
var color = [];
for (var i = 0; i < 3; i++) {
var num = Math.floor(Math.random() * max);
while (num < min) {
num = Math.floor(Math.random() * max);
}
color.push(num);
}
return color;
}