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>
posted @ 2020-01-09 16:31  吴小明-  阅读(1366)  评论(0编辑  收藏  举报