核心思路是將已有的圖片通過背景圖片定位設置在不同的元素上,給元素添加動畫,使之看起來有飄動的感覺。如果米有現有圖片,則使用截圖工具生成圖片。
參考博文:https://my.oschina.net/codingDog/blog/1839097
一、有現成圖片
線上demo:https://my.weblf.cn/alone_page/css_ani/flag2.html
代碼:
<!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_box{
/* transform: rotate(90deg);
margin-top: 200px; */
/* transform: scale(1); */
}
#flag {
position: absolute;
left: 50%;
top: 50%;
animation: flag-reverse ease-in-out infinite;
}
#flag>li {
height: 100%;
float: left;
background-image: url('../statics/images/flag2.png');
background-size: auto 100%;
animation: flag ease-in-out infinite;
}
</style>
</head>
<body>
<div class="flag_box">
<ul id="flag"></ul>
</div>
<script>
(function () {
// 這裏是js代碼
var flagEle = document.getElementById('flag')
var image = new Image()
image.src = '../statics/images/flag2.png'
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'
console.log('圖片加載完成')
splitImg(100, 5, 1.5, 3)
}
/**
* 分割圖片
* @param sliceCount 切片數量
* @param amplitude 振幅
* @param period 固定週期個數
* @param duration 一個週期的時長
*/
function splitImg(sliceCount, amplitude, period, duration) {
console.log('切割圖片開始')
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 + 1; 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>
二、自動生成圖片後飄動
線上demo:https://my.weblf.cn/vuecli3_wp4_alone_demo/html2canvas_flag.html
此demo使用vue編寫,調用html2canvas生成圖片:
<template>
<div id="pageDiv" :style="{'padding-top':isWeiXin || isApps?'0':'3rem'}">
<!-- 頁面頭部-->
<header-com :poptitle="'html2canvas截圖'" :type="'doc_title'" v-if="!isWeiXin && !isApps"></header-com>
<!-- 頁面的主要內容 -->
<section class="content">
<div class="box_main" ref="imageToFile">
<div id="flag1">歡迎光臨 一路順風</div>
</div>
<button type="button" class="shot-btn" @click="screenShot">截圖</button>
<!-- 截圖結果 -->
<p>截圖結果</p>
<img id="new_img" :src="img" v-if="img"/>
<!-- 旗幟飄動 -->
<div class="flag_box">
<ul id="flag"></ul>
</div>
</section>
</div>
</template>
<script>
import HeaderCom from "@/components/header"; //頁面頭部
import {changeUrl} from "@/utils/changeUrl"
import html2canvas from 'html2canvas'
export default {
data() {
return {
isWeiXin: TS_WEB.isWeiXin,
isApps: TS_WEB.isApp,
config: {
value: '',
logo: require('@/statics/images/system/sjbj.jpg')
},
img: ""
};
},
components: {
HeaderCom,
html2canvas
},
methods: {
changeUrl,
//生成圖片
screenShot() {
html2canvas(this.$refs.imageToFile, {
width: 80,
height: 200,
scale: 1,
}).then((canvas) => {// 第一個參數是需要生成截圖的元素,第二個是自己需要配置的參數,寬高等
this.img = canvas.toDataURL('image/png');
setTimeout(()=>{
this.img_ini()
},1000)
})
},
/**
* 分割圖片
* @param sliceCount 切片數量
* @param amplitude 振幅
* @param period 固定週期個數
* @param duration 一個週期的時長
*/
splitImg(sliceCount, amplitude, period, duration,image,flagEle) {
console.log('切割圖片開始')
var imgWidth = image.width
document.getElementById('flag').style.width=imgWidth+'px'
var imgHeight = image.height
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+1; i++) {
console.log(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 style="background-image:url('${this.img}')"></li>`)
document.documentElement.appendChild(styleEle)
},
//獲取新圖片
img_ini(){
var flagEle = document.getElementById('flag')
var image = new Image()
image.src = this.img
let that=this
image.onload = function () {
console.log('圖片加載完成')
that.splitImg(80, 5, 1.5, 3,image,flagEle)
}
}
},
mounted(){
},
created() {
document.title='html2canvas截圖'
}
};
</script>
<style>
#flag {
height: 100%;
position: absolute;
animation: flag-reverse ease-in-out infinite;
}
#flag>li {
height: 100%;
float: left;
background-size: auto 100%;
animation: flag ease-in-out infinite;
}
</style>
<style lang="less" scoped>
// 盒子模型
#pageDiv {
width: 100%;
height: 100%;
padding-top: 0;
padding-bottom: 0;
overflow: hidden;
position: relative;
box-sizing: border-box;
.content{
height: 100%;
width: 100%;
overflow: scroll;
overflow-x: hidden;
.box_main{
width: 80px;
height: 200px;
#flag1{
width: 80px;
height: 200px;
background: red;
writing-mode: vertical-lr;
font-size: 16px;
line-height: 80px;
padding-top: 20px;
box-sizing: border-box;
color: white;
}
}
#new_img{
display: block;
width: 80px;
height: 250px;
}
ul,li {
list-style: none;
}
.flag_box{
position: absolute;
right: 50px;
top: 4rem;
height: 200px;
width: 80px;
}
}
}
</style>