css3+js旗帜飘动
效果一:(css+dom实现)

代码:
<!doctype html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>飘动的旗帜~</title>
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
width: 100%;
background-color: lightgrey;
}
body {
text-align: center;
position: relative;
}
ul,
li {
list-style: none;
}
#flag {
position: absolute;
left: 50%;
top: 50%;
transform: translate3d(-50%, -50%, 0);
animation: flag-reverse ease-in-out infinite;
}
/* 这里是核心css样式 */
#flag>li {
height: 100%;
float: left;
background-image: url("https://oscimg.oschina.net/oscnet/4073613a5ab7bb799829aa83a67e9f46b7d.jpg");
background-size: auto 100%;
animation: flag ease-in-out infinite;
}
</style>
</head>
<body>
<ul id="flag"></ul>
<script>
(function () {
// 这里是js代码
var flagEle = document.getElementById('flag')
var image = new Image()
image.src = 'https://oscimg.oschina.net/oscnet/4073613a5ab7bb799829aa83a67e9f46b7d.jpg'
var IMG_MAX_WIDTH = 600
var IMG_MAX_HEIGHT = 600
var imgHeight
var imgWidth
image.onload = function () {
imgWidth = image.width
imgHeight = image.height
var ratio = image.width / image.height
if (imgWidth > IMG_MAX_WIDTH) {
imgWidth = IMG_MAX_WIDTH
imgHeight = imgWidth / ratio
}
if (imgHeight > IMG_MAX_HEIGHT) {
imgHeight = IMG_MAX_HEIGHT
imgWidth = imgHeight * ratio
}
flagEle.style.width = imgWidth + 'px'
flagEle.style.height = imgHeight + 'px'
flagEle.style.marginLeft = -imgWidth / 2 + 'px'
flagEle.style.marginTop = -imgHeight / 2 + 'px'
splitImg(100, 20, 1.5, 2)
function splitImg(sliceCount, amplitude, period, duration) {
var styleEle = document.createElement('style')
// styleEle.innerHTML = 'body{background: red}'
var styleHtmlAry = []
var sliceCountPerPeriod = Math.floor(sliceCount / period)
var sliceWidth = imgWidth / sliceCount
var formula = sliceCountPerPeriod + 'n+'
var interval = duration * period / sliceCount
// 添加动画延时
for (var i = 0; i < sliceCount; i++) {
if (i < sliceCountPerPeriod) {
styleHtmlAry.push('#flag > li:nth-child(' + formula + i + ') { ')
styleHtmlAry.push('animation-delay: -' + (interval * (sliceCountPerPeriod - i)) +
's;')
styleHtmlAry.push('}')
}
styleHtmlAry.push('#flag > li:nth-child(' + i + ') { background-position: -' + (i *
sliceWidth) + 'px 0; }') // 设置切片背景
}
// 添加关键帧动画
styleHtmlAry.push('@keyframes flag {')
styleHtmlAry.push('0% { transform: translate3d(0, ' + amplitude + 'px, 0); }')
styleHtmlAry.push('50% { transform: translate3d(0, -' + amplitude + 'px, 0); }')
styleHtmlAry.push('100% { transform: translate3d(0, ' + amplitude + 'px, 0); }')
styleHtmlAry.push('}')
// 添加反向关键帧动画
styleHtmlAry.push('@keyframes flag-reverse {')
styleHtmlAry.push('0% { transform: translate3d(0, ' + (-amplitude) + 'px, 0); }')
styleHtmlAry.push('50% { transform: translate3d(0, ' + amplitude + 'px, 0); }')
styleHtmlAry.push('100% { transform: translate3d(0, ' + (-amplitude) + 'px, 0); }')
styleHtmlAry.push('}')
// 容器应用flag-reverse动画
styleHtmlAry.push('#flag {')
styleHtmlAry.push('animation-duration: ' + duration + 's;') // 添加周期时长
styleHtmlAry.push('animation-delay: -' + (interval * sliceCountPerPeriod) + 's;')
styleHtmlAry.push('}')
// 切片样式
styleHtmlAry.push('#flag > li {')
styleHtmlAry.push('animation-duration: ' + duration + 's;') // 添加周期时长
styleHtmlAry.push('width: ' + (imgWidth / sliceCount) + 'px;') // 设置切片宽度
styleHtmlAry.push('}')
styleEle.innerHTML = styleHtmlAry.join('')
// 创建切片元素
flagEle.innerHTML = new Array(sliceCount + 1).join('<li></li>')
document.documentElement.appendChild(styleEle)
}
}
})();
</script>
</body>
</html>
效果二:(比较有质感,canvas实现)

代码:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>旗帜飘飘</title>
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
}
body {
position: relative;
background: lightgrey;
}
#flagCanvas {
position: absolute;
top: 50%;
left: 50%;
transform-origin: center;
transform: translate3d(-50%, -50%, 0);
}
</style>
</head>
<body>
<canvas id="flagCanvas"></canvas>
<script>
var canvas = document.getElementById('flagCanvas')
var ctx = canvas.getContext('2d')
var IMG_MAX_WIDTH = 600
var IMG_MAX_HEIGHT = 600
var imgWidth, imgHeight
var image = new Image()
image.src = 'https://oscimg.oschina.net/oscnet/4073613a5ab7bb799829aa83a67e9f46b7d.jpg'
var amplitude = 30 // 振幅
var period = 2 // 周期数
var frequency = 1 // 频率
var wavelength // 波长
var v // 波速
var cftX // x系数
var cftA // 振幅系数
image.onload = function (ev) {
imgWidth = Math.floor(image.width)
imgHeight = Math.floor(image.height)
var canvas = document.getElementById('flagCanvas')
var scale = 1
if (imgWidth > IMG_MAX_WIDTH) {
scale = IMG_MAX_WIDTH / imgWidth
}
if (imgHeight > IMG_MAX_HEIGHT) {
scale = scale * IMG_MAX_HEIGHT / imgHeight
}
canvasWidth = imgWidth
canvasHeight = imgHeight + amplitude * 2
canvas.width = canvasWidth
canvas.height = canvasHeight
canvas.style.transform = 'translate3d(-50%,-50%,0) scale(' + scale + ')'
wavelength = imgWidth / period
cftX = 2 * Math.PI / wavelength
cftA = amplitude / imgWidth
v = wavelength * frequency
tick()
}
var fps = 70 // 每秒帧数
var interval = 1000 / fps // 连续帧之间间隔(理论)
var stop = false // 停止动画
var timeNow = Date.now() // 当前时间
var timeLast = timeNow // 上一帧时间
var delta = 0 // 连续帧之间间隔(实际)
var y = 0
var lastY = 0
var distance = 0
var tick = function () {
if (stop) return false
timeNow = Date.now()
delta = timeNow - timeLast
if (delta > interval) {
timeLast = timeNow
distance += (delta / 1000 * v)
ctx.clearRect(0, 0, canvasWidth, canvasHeight)
for (var x = 0; x < imgWidth; x++) {
// var y = cftA * x * Math.sin(cftX * (x - distance)) + amplitude
// ctx.drawImage(image, x, 0, 1, imgHeight, x, y, 1, imgHeight)
y = cftA * x * Math.sin(cftX * (x - distance)) + amplitude
ctx.drawImage(image, x, 0, 1, imgHeight, x, y, 1, imgHeight)
ctx.fillStyle = 'rgba(255,255,255,' + (x === 0 ? 0 : (y - lastY) * 0.5) + ')'
ctx.fillRect(x, y, 1, imgHeight)
lastY = y
}
}
requestAnimationFrame(tick)
}
</script>
</body>
</html>

浙公网安备 33010602011771号