前几天在好朋友楼上小黑的介绍下,看到了某个平台的官网,里面有一个人物介绍的模块,里面的动画感觉不错,于是就自己动手写了一个。
当然这里去掉了具体信息,原网站是里面圆圈中是人物的头像,旁边是介绍信息,每个人物就沿着圆弧移动到指定位置
要让小圆在圆弧上动,我们只需要知道圆心在圆弧上的坐标(x,y)就行了
所以当我们知道外圆的半径,小圆的半径,以及角度再利用三角函数就可以计算出 小圆在圆弧上定位的位置 top right
这里是将 移动的小圆封装成一个组件 moveRound,只需要将
大圆半径,小圆半径,转动的角度,剩下的就可以按自己需要添加
<template>
<div>
<h3>围绕圆弧移动动画</h3>
<div class="arc_bo" >
<move-round :minR="25" :bigR="150" :angle="30" ref="mRound1" > </move-round>
<span class="start" @click="toMove" >开始</span>
</div>
</div>
</template>
<script>
import moveRound from './components/moveRound.vue'
export default {
name: 'arcMoveAni',
components: {
moveRound
},
methods: {
toMove() {
this.$refs.mRound1.toMove()
}
}
}
</script>
<style scoped>
.arc_bo{
margin: 0 auto;
width: 6rem;
height: 6rem;
border-radius: 50%;
border: 1px solid #ccc;
position: relative;
margin-top: 2rem;
}
.start{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
color: #f40;
width: 1rem;
height: 1rem;
border-radius: 50%;
border: 1px solid #ccc;
text-align: center;
line-height: 1rem;
}
</style>
moveRound组件,
角度的动态改变计算 top,right的值,其中 raf,caf是 requestAnimationFrame的兼容处理,不明白的可以看往期文章或者百度。
<template>
<div>
<div class="round" :style="setPosition" ></div>
</div>
</template>
<script>
let timer = 0
import { raf,caf } from '../../utils/raf'
export default {
name: 'moveRound',
props: {
angle: { // 需要转动的角度
type: Number,
default: 0
},
bigR: { // 外层大圆半径
type: Number,
default: 0
},
minR: { //移动小圆半径
type: Number,
default: 0
},
backgroundColor: {
type: String,
default: '#7fffd4'
}
},
data() {
return {
top: '',
right: '',
setAngle: 0
}
},
mounted() {
},
computed: {
/**
* sin 对应 y 的值,转换为定位中距离顶部top等于 圆的半径 - y - 小圆半径(让圆心在圆弧上)
* cos 对应 x 的值,转换为定位中距离右边right等于 圆的半径 - x - 小圆半径
* **/
setPosition( { top, right ,setAngle, bigR, minR, backgroundColor} ) {
let size = minR*2 + 'px'
let x = bigR * ( 1 - Math.cos(setAngle * Math.PI/180)) - minR
let y = bigR * ( 1 - Math.sin(setAngle * Math.PI/180)) - minR
right = x + 'px'
top = y + 'px'
return {
top,
right,
width: size,
height: size,
backgroundColor
}
}
},
methods: {
toMove() {
// 调整 累加值,改变速度
this.setAngle += 1
timer = raf(this.toMove)
// 结束动画
if(this.setAngle > this.angle) {
caf(timer)
// 也可以根据需要重复执行
// this.setAngle = 0
}
}
}
}
</script>
<style>
.round{
position: absolute;
will-change: top,right;
border-radius: 50%;
}
</style>
主要的点就是根据角度计算位置,只要思路正确,应该可以少走弯路。
const vendors = ['webkit', 'moz']
let r = window.requestAnimationFrame
let c = window.cancelAnimationFrame
for (let x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
// 统一前缀
r = window[vendors[x] + 'RequestAnimationFrame']
c =
window[vendors[x] + 'CancelAnimationFrame'] ||
window[vendors[x] + 'CancelRequestAnimationFrame']
}
export const raf = (function() {
if (r) {
return r
} else {
let lastTime = 0
return function(callback, element) {
let currTime = new Date().getTime()
let timeToCall = Math.max(0, 16.7 - (currTime - lastTime))
let id = window.setTimeout(function() {
callback(currTime + timeToCall)
}, timeToCall)
lastTime = currTime + timeToCall
return id
}
}
})()
export const caf = (function() {
if (c) {
return c
} else {
return function(id) {
clearTimeout(id)
}
}
})()