DOM基础测试33
Opened this issue · 25 comments
zhangxinxu commented
本期题目如下:
大家提交回答的时候,注意缩进距离,起始位置从左边缘开始;另外,github自带代码高亮,所以请使用下面示意的格式。
```js // 你的JS代码写在这里 ```
另外,务必提供在线demo,方便验证与评分。jsbin.com jsfiddle.net codepen.io或者国内类似站点都可以,也可以使用github page。
没有可访问demo积分-1分哟。
-----其他-----
因为本周在北京参加前端技术会议,周六才回上海,所以本期小测答疑直播改为6月23日周日上午10:00,预计半小时左右。直播地址:https://live.bilibili.com/21193211
首位答题者会额外2积分。
感谢您的参与!
sghweb commented
忘记加在线demo了,补一下
demo
// 第一题
let divele = document.createElement('div')
divele.style.width = 300 + 'px'
divele.style.height = 150 + 'px'
document.body.appendChild(divele)
// 第二题
divele.style.backgroundImage = 'linear-gradient(to bottom right, red, blue)';
// 第三题 想用requestAnimationFrame 没想出怎么控制时间
let Timer = null
let colorArr = [0, 0, 255]
let changeColor = function() {
if (colorArr[2] == 255 && colorArr[1] < 255) {
colorArr[1] += 15
}
if (colorArr[1] == 255 && colorArr[2] > 0) {
colorArr[2] -= 15
}
if (colorArr[2] == 0 && colorArr[1] > 0) {
colorArr[1] -= 15
}
if (colorArr[2] == 0 && colorArr[1] == 0 && colorArr[0] < 255) {
colorArr[0] += 15
}
if (colorArr[0] == 255) {
clearInterval(Timer)
}
divele.style.backgroundImage = `linear-gradient(to bottom right, rgb(${colorArr[2]},${colorArr[1]},${colorArr[0]}), rgb(${colorArr[0]},${colorArr[1]},${colorArr[2]}))`
}
Timer = setInterval(() => {
changeColor()
}, 1000 / 68)
wingmeng commented
感觉自己第3题实现的不够优雅……
/*** 第 1 题 ***/
var box = document.createElement('div');
box.style.width = '150px';
box.style.height = '300px';
document.body.appendChild(box);
/*** 第 2 题 ***/
// 方法1:使用位置关键词
box.style.background = 'linear-gradient(to right bottom, red, blue)';
// 方法2:使用角度(纯属装B)
// 由于是长方形,所以需要用三角函数算出颜色临界线夹角(矩形右上与左下角对角线)
// var angle = Math.atan(150 / 300) * 180 / Math.PI + 90;
// box.style.background = 'linear-gradient(' + angle + 'deg, red, blue)';
/*** 第 3 题 ***/
// 思路:利用 HSL 颜色空间,H 为色相角度,所以两种颜色的渐变动画就是对 H 的递增或递减,
// 判断颜色1到颜色2的 H 跨度是否大于180度,如大于则取 360 减去 H 跨度,再取负
// 根据跨度值算出每帧渲染步长,动画过渡渲染采用 requestAnimationFrame
bgColorAnimate('hsl(0, 100%, 50%)', 'hsl(240, 100%, 50%)', 1);
function bgColorAnimate(color1, color2, duration) {
var getHSLArr = function(hslStr) {
var result = hslStr.match(/^hsl\((-*\d+),\s*(\d+%),\s*(\d+%)+/i);
return [result[1], result[2], result[3]];
};
var getHSLStr = function(hslArr) {
return 'hsl(' + hslArr.join(',') + ')';
};
var c1 = getHSLArr(color1);
var c2 = getHSLArr(color2);
var hue1 = c1[0];
var hue2 = c2[0];
var hueSpan = Math.abs(hue1 - hue2);
if (hueSpan > 180) {
if (hue1 > hue2) {
hue1 = -(360 - hue1);
} else {
hue2 = -(360 - hue2);
}
}
var fps = 60; // 帧率
var steps = Math.abs(Math.min(hue1, hue2)) / fps * duration; // 步长
c1[0] = hue1;
c2[0] = hue2;
var render = function(timestamp, dt) {
if (dt > duration / hueSpan) {
if (c1[0] == hue2) {
return;
}
hue2 > 0 ? c1[0] += steps : c1[0] -= steps;
hue1 > 0 ? c2[0] -= steps : c2[0] += steps;
box.style.background = 'linear-gradient(to right bottom, ' + getHSLStr(c1) + ',' + getHSLStr(c2) + ')';
dt = 0;
}
requestAnimationFrame(function(_timestamp) {
render(_timestamp, dt + _timestamp - timestamp)
});
};
requestAnimationFrame(function(timestamp) {
render(timestamp, 0);
});
}
NeilChen4698 commented
Demo
https://codepen.io/crazyboy/pen/Oebpze
(function () {
var div = document.createElement('div');
div.style.height = '300px';
div.style.width = '150px';
div.style.background = 'linear-gradient(to bottom right, red , blue)';
document.body.appendChild(div);
var counter = function(val) {
// 255 可以被 3 整除, 得到85帧
var step = 3;
var asc = true;
return {
next: function() {
if (asc && val === 255) {
asc = false;
} else if (!asc && val === 0) {
asc = true;
}
if (asc) {
val += step;
} else {
val -= step;
}
return val;
}
};
}
var descendCounter = counter(255);
var riseCounter = counter(0);
//想在一秒内得到85帧, 约得11毫秒
setInterval(function() {
div.style.background = 'linear-gradient(to bottom right,rgb(' + descendCounter.next() + ',0,' + riseCounter.next() + '),rgb(' + riseCounter.next() + ',0,' + descendCounter.next() + '))';
}, 11);
})();
Despair-lj commented
// 1
const div = document.createElement('div')
div.style.width = '150px'
div.style.height = '300px'
document.body.appendChild(div)
// 2
div.style.background = 'linear-gradient(to bottom right, red, blue)'
// 3 方法一
const animateFn = () => {
div.style.background = 'linear-gradient(to bottom right, red, blue)'
let start = null
function step(timestamp) {
if (!start) start = timestamp
const progress = timestamp - start
const color = Math.min((progress * 255) / 1000, 255).toFixed(0)
const red = 'rgb(' + (255-color) + ',0,' + color + ')'
const blue = 'rgb(' + color + ',0,' + (255-color) + ')'
div.style.background = 'linear-gradient(to bottom right, ' + red +', '+ blue + ')'
if (progress < 1000) {
window.requestAnimationFrame(step)
}
}
window.requestAnimationFrame(step)
}
animateFn()
// 方法二
const div1 = document.createElement('div')
const inner = document.createElement('div')
div1.classList.add('outer')
inner.classList.add('inner')
document.body.appendChild(div1)
const animateFn1 = () => {
inner.style.background = 'linear-gradient(to bottom right, red, blue, red)'
div1.appendChild(inner)
let start = null
function step(timestamp) {
if (!start) start = timestamp
const progress = timestamp - start
const distance = Math.min((progress * 15) / 100, 150)
inner.style.left = -1 * distance + 'px'
inner.style.top = -1 * distance * 2 + 'px'
if (progress < 1000) {
window.requestAnimationFrame(step)
} else {
div1.removeChild(inner)
div1.style.background = 'linear-gradient(to bottom right, blue, red)'
}
}
window.requestAnimationFrame(step)
}
animateFn1()
livetune commented
//1
var elm = document.createElement('div')
elm.style.width = '300px'
elm.style.height = '150px'
document.body.append(elm)
function getTanDeg(tan) {
var result = Math.atan(tan) / (Math.PI / 180)
result = Math.round(result)
return result
}
var result = getTanDeg(0.5)
var i = 180 - result
//2
elm.style.background = 'linear-gradient(' + i + 'deg,red,blue)'
//3
function roll() {
if (i === 360 - 27) {
i = 180 - 27
}
elm.style.background = 'linear-gradient(' + i + 'deg,red,blue)'
// 一秒60帧 一帧加 3 deg
i += 3
requestAnimationFrame(roll)
}
roll()
Seasonley commented
Demo
话说查了一下IE12才支持模板字符串
hsl的渐变有点反常识
补充:参考了几种CSS渐变背景图片transtion动画方法 « 张鑫旭-鑫空间-鑫生活,尝试了houdini
var aniDiv=document.createElement('div')
aniDiv.style.height="300px"
aniDiv.style.width="150px"
aniDiv.style.background="linear-gradient(to right bottom,red,blue)"
document.body.appendChild(aniDiv)
function getBkg(max,min){
return 'linear-gradient(to right bottom,'+max+','+min+')'
}
function aniGoRGB(){
var start=Date.now();
function step(){
var min=0.255*(Date.now()-start)
var max=255-min
if(min<255){
aniDiv.style.background=getBkg(
'rgb('+max+',0,'+min+')',
'rgb('+min+',0,'+max+')'
)
window.requestAnimationFrame(step)
}else{
max=0,min=255
aniDiv.style.background=getBkg(
'rgb('+max+',0,'+min+')',
'rgb('+min+',0,'+max+')'
)
}
}
window.requestAnimationFrame(step)
}
function aniGoHex(){
var start=Date.now();
function step(){
var min=parseInt(0xff/1e3*(Date.now()-start))
var max=0xff-min
if(max>0){
aniDiv.style.background=getBkg(
'#'+(((max<<16)+min).toString(16)),
'#'+(((min<<16)+max).toString(16))
)
window.requestAnimationFrame(step)
}else{
aniDiv.style.background=getBkg(
'#0000ff',
'#ff0000'
)
}
}
window.requestAnimationFrame(step)
}
function aniGoHSL(){
var start=Date.now();
function step(){
var delta=parseInt((360-240)/1e3*(Date.now()-start))
var max=240+delta
var min=360-delta
if(max<360){
aniDiv.style.background=getBkg(
'hsl('+min+', 100%, 50%)',
'hsl('+max+', 100%, 50%)'
)
window.requestAnimationFrame(step)
}else{
aniDiv.style.background=getBkg(
'hsl(240, 100%, 50%)',
'hsl(0, 100%, 50%)'
)
}
}
window.requestAnimationFrame(step)
}
function aniGoBkgPos(){
aniDiv.style.transition="background-position 1s";
aniDiv.style.background='linear-gradient(to right bottom, red, blue, red) 100% 100%/200% 200%';
setTimeout(function(){
aniDiv.style.background='linear-gradient(to right bottom, blue, red)';
aniDiv.transition="";
},1000)
}
function aniGoHoudini(){
if(!(CSS&&CSS.registerProperty)){aniGoRGB();return;}
aniDiv.style.background='linear-gradient(to right bottom, var(--start-stop), var(--end-stop))';
aniDiv.style.transition="--start-stop 1s, --end-stop 1s";
aniDiv.className="houdini";
setTimeout(function(){
aniDiv.style.background='linear-gradient(to right bottom, blue, red)';
aniDiv.style.transition="";
aniDiv.className="";
},1000)
}
if (CSS&&CSS.registerProperty) {
CSS.registerProperty({
name: '--start-stop',
syntax: '<color>',
inherits: false,
initialValue: 'transparent'
});
CSS.registerProperty({
name: '--end-stop',
syntax: '<color>',
inherits: false,
initialValue: 'transparent'
});
}
guqianfeng commented
/**
* 1.添加div元素
*/
let oDiv = document.createElement("div");
oDiv.style.width = "300px";
oDiv.style.height = "150px";
document.body.appendChild(oDiv);
/**
* 2.添加渐变
*/
oDiv.style.backgroundImage = "linear-gradient(to right bottom, red, blue)";
/**
* 3.渐变动画
* 红色 255,0,0 蓝色 0 0 255
* 红色变蓝色 r减小 b增加
* 蓝色变红色 r增加 b减小
*/
let red_r = 255, red_b = 0, blue_r = 0, blue_b = 255,timer;
function changeColor(){
red_r--;
red_b++;
blue_r++;
blue_b--;
oDiv.style.backgroundImage = `linear-gradient(to right bottom, rgb(${red_r},0,${red_b}), rgb(${blue_r},0,${blue_b}))`;
if(red_r === 0){
cancelAnimationFrame(timer);
}
timer = requestAnimationFrame(changeColor);
}
changeColor();
silverWolf818 commented
//第一题,第二题
var box = document.createElement('div');
box.style.width = '300px';
box.style.height = '150px';
box.style.background = 'linear-gradient(to bottom right, red , blue)';
document.body.append(box);
//第三题
//[requestAnimationFrame](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame)
//根据官方文档requestAnimationFrame回调函数执行次数通常是每秒60次,通过内置函数时间戳设置1s
//红蓝对应RGB红色(255,0,0)蓝色(0,0,255)
var start = null;
function ani(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start;
var color = parseInt(Math.min(progress / 1000 * 255, 255));
var red = "rgb("+(255-color)+",0,"+color+")";
console.log(red);
var blue = "rgb("+color+",0,"+(255-color)+")";
box.style.background = "linear-gradient(to bottom right, "+red+", "+blue+")";
if (progress <= 1000) {
window.requestAnimationFrame(ani);
}
}
window.requestAnimationFrame(ani);
liyongleihf2006 commented
应该就是红色管道转化为蓝色管道,蓝色管道转化为红色管道的问题吧
可惜下面的实现不支持ie,因为ie不支持filter:url滤镜
我考虑了一下,又添加了一种别的实现方式,可惜依然不支持ie
jsbin
svg{
position:absolute;
visibility: hidden;
}
.filter {
filter: url('#filter')
}
<svg>
<filter id="filter">
<feColorMatrix id="matrix" type="matrix" values="1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0" />
</filter>
</svg>
<button id="btn">开始变换</button>
<button id="btn2">另外一种变换</button>
//第一题
const div = document.createElement('div');
Object.assign(div.style, {
height: '300px',
width: '150px'
});
document.body.appendChild(div);
//第二题
Object.assign(div.style, {
backgroundImage: 'linear-gradient(to right bottom, red, blue)'
});
//第三题
div.classList.add("filter");
const matrix = document.querySelector('#matrix');
var animationDuration = 1000;
document.querySelector("#btn").addEventListener('click', transform);
function transform() {
const startTime = Date.now();
step();
function step() {
window.requestAnimationFrame(function () {
const currentTime = Date.now();
let i = (currentTime - startTime) / animationDuration;
if (i > 1) {
i = 1
};
matrix.setAttribute('values',
`${1 - i} 0 ${i} 0 0
0 1 0 0 0
${i} 0 ${1-i} 0 0
0 0 0 1 0`
);
if (i < 1) {
step();
}
});
}
}
//另外一种实现方式
//第一题
const div2 = document.createElement('div');
Object.assign(div2.style, {
height: '300px',
width: '150px'
});
document.body.appendChild(div2);
//第二题
Object.assign(div2.style, {
background: 'linear-gradient(to right bottom, red, blue)'
});
//第三题
var animationDuration = 1000;
Object.assign(div2.style, {
'background-blend-mode': 'difference'
});
document.querySelector("#btn2").addEventListener('click', transform2);
function transform2() {
const startTime = Date.now();
step();
function step() {
window.requestAnimationFrame(function () {
const currentTime = Date.now();
let i = (currentTime - startTime) / animationDuration;
if (i > 1) {
i = 1
};
let c = i * 255;
Object.assign(div2.style, {
background: `linear-gradient(to right bottom,red,blue),rgb(${c},0,${c})`
});
if (i < 1) {
step();
}
});
}
}
asyncguo commented
(() => {
let oDiv = document.createElement('div')
oDiv.style.width = '150px'
oDiv.style.height = '300px'
oDiv.style.background = 'linear-gradient(to right bottom, red, blue)'
document.body.appendChild(oDiv)
let num = 0
function aniGradient () {
if (num == 100) {
window.cancelAnimationFrame(aniGradient)
return
}
num++
// 由红蓝渐变转为蓝红,那么直接在原本的红色之前接收一个蓝色(默认隐藏掉,逐渐渐变再显示出来)
oDiv.style.background = `linear-gradient(to right bottom, blue -${100 - num}%, red ${num}%, blue ${100 + num}%)`
window.requestAnimationFrame(aniGradient)
}
window.requestAnimationFrame(aniGradient)
})()
xiongchenf commented
(function() {
// 1
const div = document.createElement('div');
div.style.width = "150px";
div.style.height = "300px";
div.style.border = "1px solid #333";
document.body.appendChild(div);
// 2
div.style.background = "linear-gradient(to bottom right, red, blue)";
let last = +new Date();
const roll = () => {
let now = +new Date(),
dist = now - last,
percent = dist / 1000,
red = 255 - 255 * percent,
blue = 255 * percent;
if (dist >= 1000) {
last = now;
}
// 3
div.style.background = "linear-gradient(to bottom right, rgb("+ red +",0, "+ blue +"), rgb("+ blue +",0, "+ red +")";
window.requestAnimationFrame(roll);
}
roll();
})();
smileyby commented
//=> 计算渐变角度
let width = 150;
let height = 300;
let incline = Math.sqrt(Math.pow(width,2)+Math.pow(height,2));
let angle = (180 - Math.asin(height / incline) / Math.PI * 180);
//=> 创建div
let box = document.createElement('div');
box.style.width = width + 'px';
box.style.height = height + 'px';
box.style.background = 'linear-gradient('+ angle +'deg, red, blue)';
document.body.append(box);
//=> 添加渐变动画,btn是我添加的动画开始按钮
let time = 0,
timer = null,
step = (180/1000)*17,
initAgent = angle,
flag = true;
btn.addEventListener('click',function(){
if (!flag) return;
flag = false;
initAgent += step;
box.style.background = 'linear-gradient('+ initAgent +'deg, red, blue)';
timer = setInterval(function(){
if (time > 1000) {
flag = true;
clearInterval(timer);
}
initAgent += step;
time += 17;
box.style.background = 'linear-gradient('+ initAgent +'deg, red, blue)';
}, 17);
});
fzero17 commented
var target = document.createElement("div");
target.setAttribute("style", "width:300px;height:150px");
document.body.appendChild(target);
target.style.background = "linear-gradient(to bottom right, red, blue)";
tzmy commented
var div = document.createElement('div');
div.style.cssText='height:300px;width:150px;background:black;';
document.body.appendChild(div);
div.style.cssText+='background:linear-gradient(to right bottom, red, blue);'
lifelikejuly commented
第一题
var div = document.createElement("DIV")
div.style.cssText = "width:150px;height:300px;";
document.body.appendChild(div)
第二题
var div = document.createElement("DIV")
div.style.cssText = "width:150px;height:300px;";
div.style.background = 'linear-gradient(to bottom right, red,50%, blue)';
document.body.appendChild(div)
第三题
var div = document.createElement("DIV")
div.style.cssText = "width:150px;height:300px;";
document.body.appendChild(div)
var value = 100;
var tag = true
setInterval(function() {
div.style.background = 'linear-gradient(to bottom right, red,' + value + '%, blue)';
if (value == 100) {
tag = true
} else if (value == 0) {
tag = false;
}
if (tag) {
value -= 10
} else {
value += 10
}
}, 100)
XboxYan commented
借助CSS动画来实时取值颜色
demo
<div id="color" class="color"></div><!--颜色参考-->
.color{
color: red;
background-color: blue;
animation: color 1s linear forwards;/**控制动画时长和类型**/
}
@keyframes color {
to{
color: blue;
background-color: red;
}
}
var div = document.createElement('div');
var color = document.getElementById('color');
div.style.width = '150px';
div.style.height = '300px';
document.body.appendChild(div);
div.style.background = 'linear-gradient(to right bottom, red, blue)';
var animationState = true;
color.addEventListener("animationstart",function(){
animationState = true;
})
color.addEventListener("animationend",function(){
animationState = false;
})
var draw = function () {
if(animationState){
var style = window.getComputedStyle(color);
div.style.background = 'linear-gradient(to right bottom, '+style.color+', '+style.backgroundColor+')';
}
requestAnimationFrame(draw);
};
draw();
Via1877 commented
//第一题
var div = document.createElement('div');
div.style.width=150+"px";
div.style.height= 300+'px';
document.body.appendChild(div);
//第二题
div.style.background= 'linear-gradient(to bottom right, red, blue, red)';
div.style.backgroundSize=' 150% 200%';
//第三题
function changeColor(){
div.style.backgroundSize=' 220% 200%';
div.style.backgroundPositionX="100%";
div.style.backgroundPositionY="100%";
div.style.transition='all 1s';
}
var btn = document.createElement('button');
btn.innerText="改变颜色";
document.body.appendChild(btn);
btn.addEventListener('click',changeColor);
frankyeyq commented
<button id="reset">reset</button>
function go() {
let divEle = document.createElement('div');
divEle.style.cssText = 'width: 150px;height: 300px;'
document.body.appendChild(divEle)
divEle.style.background = 'linear-gradient(to bottom right, red , blue)'
let to255 = 0
let to0 = 255
let reqId = requestAnimationFrame(render)
function render() {
if (to255 <= 255 && to0 >= 0) {
to255 += 4.25
to0 -= 4.25
divEle.style.background = 'linear-gradient(to bottom right, rgb('+ to255 +',0,' + to0 + ') , rgb(' + to0 + ',0,'+ to255 +'))';
requestAnimationFrame(render)
} else {
cancelAnimationFrame(reqId)
}
}
}
go()
document.getElementById('reset').addEventListener('click', function() {
document.querySelector('div').remove()
go()
})
z-xl-t commented
Demo
<html>
<body>
</body>
</html>
// 第一题
var bNode = document.querySelector("body");
var divNode = document.createElement("div")
divNode.setAttribute(
'style',
'width:150px;' + 'height:300px;'+ "background: blue"
);
bNode.appendChild(divNode);
// 第二题
divNode.style.background = "linear-gradient(to bottom right,red, blue)";
juzhiqiang commented
`
// 使用createElement方法创建一个宽高150*300px的div元素插入到body
function createDiv() {
let elem = document.createElement('div');
elem.setAttribute('style', 'width:150px;height:300px;');
document.body.appendChild(elem);
}
// 设置style实现左上角到右下角的red到blue渐变
function setGradient() {
let oDiv = document.getElementsByTagName('div');
oDiv[0].style = oDiv[0].getAttribute('style') + "background:linear-gradient(120deg, red 0%, blue 100%)"
}
// 渐变动画
function annimateGraduebt() {
let oDiv = document.getElementsByTagName('div');
let n = 0;
setInterval(function() {
if (n === 100) {
oDiv[0].style = oDiv[0].getAttribute('style') +
"background:linear-gradient(120deg,blue 0%,red 0%, blue 100%)"
n = 0;
} else {
oDiv[0].style = oDiv[0].getAttribute('style') +
"background:linear-gradient(120deg,blue 0%,red " + (n++) + "%, blue " + (100 + n) + "%)"
}
}, 20)
}
// 1
createDiv();
// 2
setGradient()
// 3
annimateGraduebt();
`
jsweber commented
//第一题
let div = document.createElement('div')
div.style.cssText = 'width:300px;height:150px;color:#fff;'
div.innerText = 'hover to change'
document.body.appendChild(div)
//第二题
div.style.backgroundImage = 'linear-gradient(to bottom right, red, blue)'
//第三题
div.addEventListener('mouseenter', () => {
div.style.backgroundImage = 'linear-gradient(to bottom right, red, blue)'
addLinearColor(div)
})
function addLinearColor(div){
let start=Date.now()
function step(){
let toColorR = 0.255 * (Date.now()-start)
let toColorB = 255 - toColorR
let fromColorR = toColorB
let fromColorB = toColorR
if(toColorR<255){
div.style.backgroundImage = `linear-gradient(to bottom right, rgb(${fromColorR},0,${fromColorB}), rgb(${toColorR}, 0, ${toColorB}))`
window.requestAnimationFrame(step)
}else{
div.style.backgroundImage = `linear-gradient(to bottom right, rgb(0,0, 255), rgb(255, 0, 0))`
}
}
window.requestAnimationFrame(step)
}
CandyQiu commented
//习题: https://github.com/zhangxinxu/quiz/issues/30
// 1
let div = document.createElement("div");
div.style.height = "150px";
div.style.width = "300px";
document.body.appendChild(div);
// 2
div.style.background = "linear-gradient(to left top, blue, red)";
// 或者
div.style.background = "linear-gradient(165deg,red,blue)";
// 3
//每秒重复60次,所以循环60
function clicks(){
let progress= 0;
window.requestAnimationFrame(linerGradientChange);
function linerGradientChange(timestamp){
progress += 1;
let color = parseInt(Math.min(progress / 60 * 255, 255));
let blue = "rgb("+color+",0,"+(255-color)+")";
let red = "rgb("+(255-color)+",0,"+color+")";
div.style.background = "linear-gradient(165deg,"+red+","+blue+")";
if (progress <= 60) {
window.requestAnimationFrame(linerGradientChange);
}
}
}
// 兼容性参考 :https://www.zhangxinxu.com/wordpress/2013/09/css3-animation-requestanimationframe-tween-%E5%8A%A8%E7%94%BB%E7%AE%97%E6%B3%95/
zhangxinxu commented
- 通常我们使用JS给DOM元素设置style样式的时候,不通过改变style属性值,因为容器覆盖以前的样式,然后.style.xxx这样的方式不会有性能问题,即使有很多行,因为浏览器它会自动合并成一次解析。
- to bottom right,这样无论宽高比例是多少都没有问题。没有to就是从右下方开始。
- CSS渐变本质上是backgroundImage,是无法transition或者animation的,但可以使用JS。seasonley的方法就是大多数人实现的合集,非常感谢。但是非常遗憾,虽然花了很多功夫,但是对于复杂色值,其颜色变化可能并不是最舒服的那种,可能就像早期的Safari色值变化,而且如果有Alpha透明度变化,就很困难了。
- XboxYan的方法比较接近:我们可以借助animation或者transition本身的颜色变化来赋值,实现更简单,更准确,更接近原生的backgroundImage色值变化效果。我写的小demo:https://output.jsbin.com/hojesabawe
- 颜色转换的技巧。任意颜色转换为RGB(A)色值,给DOM元素赋值,然后使用getComputedStyle()获取。举个例子,请把色值skyblue转换成RGB色值,div.style.color = 'skyblue'; getComputedStyle(div).color -> RGB色值,所有浏览器都是这样的,包括IE。
zhangxinxu commented
sorry,忘记录播了。
wingmeng commented
感谢张老师的精彩分享 @zhangxinxu ,同时对 @XboxYan 清奇的思路表示佩服,受大神的启发,封装了个通用方法来作为第 3 题的补充:
/**
* 颜色过渡效果构造器
* @descr: color1 渐变过渡到 color2,color2 渐变过渡到 color1
* @param {string} color1 - 颜色1,可以是:颜色关键字/HSL(A)/RGB(A)/HEX
* @param {string} color2 - 颜色2,同上
* @param {time} number - 完成过渡效果所需的时间,单位:秒
* @param {string} [timingFn] - 过渡效果的动画函数关键词,缺省为 linear
*/
function TransColor(color1, color2, time, timingFn) {
timingFn = typeof timingFn === 'undefined' ? 'linear' : timingFn;
this.elm = document.createElement('i');
this.color1 = this.getRGB(color1);
this.color2 = this.getRGB(color2);
this.transferring = false;
this.done = false;
this.elm.style.position = 'absolute';
this.elm.style.top = '-99em';
this.elm.style.border = '1px solid';
this.reset();
this.elm.style.transition = ['border-color', time + 's', timingFn].join(' ');
document.body.appendChild(this.elm);
}
TransColor.prototype = {
constructor: TransColor,
getRGB: function(color) {
var result;
var elm = document.createElement('i');
elm.style.position = 'absolute';
elm.style.color = color;
document.body.appendChild(elm);
result = getComputedStyle(elm).color;
document.body.removeChild(elm);
return result;
},
reset: function() {
this.elm.style.borderColor = [this.color1, this.color2].join(' ');
},
getFrame: function() {
if (!this.transferring) {
this.transferring = true;
this.elm.offsetHeight; // 触发重绘
this.elm.style.borderColor = [this.color2, this.color1].join(' ');
}
var computedColor = getComputedStyle(this.elm).borderColor
.match(/rgba*\(\d+(,\s*\d*\.*\d+){2,3}\)/gi);
this.done = computedColor[0] === this.color2;
if (this.done) {
this.transferring = false;
this.reset();
}
return {
color1: computedColor[0],
color2: computedColor[1],
done: this.done
}
}
};
使用:(以第 3 题为例)
var transColor = new TransColor('red', 'blue', 1); // 初始化一个实例
var render = function() {
// getFrame 方法返回 color1 到 color2 和 color2 到 color1 渐变的中间颜色
var animate = transColor.getFrame();
// 这里是要渲染的元素
box.style.background = 'linear-gradient(to right bottom, ' +
animate.color1 + ', ' +
animate.color2 + ')';
if (animate.done) { // done 为 true 时表示过渡效果结束
return;
}
requestAnimationFrame(render);
};
render();