视差 Banner 实现二次函数的跟随移动轨迹
#UI设计
学到的知识点
- 使用js 设置偏移量的方式来
requestAnimationFrame,近似实现二次函数的逼近效果, - 设置
translate,不改变DOM结构,降低性能损耗
需要考虑设备的帧率,需要引入时间
视差 Banner 实现二次函数的跟随移动轨迹
🔗 本期用到的代码和工具链接看这里(复制到浏览器打开): CodePen https://codepen.io/editor/linxiang-webcraft/pen/019d53ed-f01c-7938-8c51-bb36a15a08aa
const container = document.querySelector('#parallax-container')
const layers = [
{
element: document.querySelector('.layer-title'),
offsetX: 12,
offsetY: 4,
},
{
element: document.querySelector('.layer-planet-fg'),
offsetX: 24,
offsetY: 8,
},
{
element: document.querySelector('.layer-asteroid'),
offsetX: 48,
offsetY: 16,
},
{
element: document.querySelector('.layer-stars'),
offsetX: -3,
offsetY: -1,
},
{
element: document.querySelector('.layer-planet-bg'),
offsetX: -9,
offsetY: -3,
},
]
let targetX = 0
let targetY = 0
container.addEventListener('pointermove', (e) => {
const rect = container.getBoundingClientRect()
const localX = e.clientX - rect.left
const localY = e.clientY - rect.top
const centerX = localX - rect.width / 2
const centerY = localY - rect.height / 2
targetX = centerX / (rect.width / 2)
targetY = centerY / (rect.height / 2)
startRender()
})
let scheduledFrame = false
function startRender() {
if (scheduledFrame) {
return
}
requestAnimationFrame(render)
scheduledFrame = true
}
let currentX = 0
let currentY = 0
const lerpFactor = 0.1
const EPSILON = 0.001
function render() {
currentX += (targetX - currentX) * lerpFactor
currentY += (targetY - currentY) * lerpFactor
if (
Math.abs(targetX - currentX) < EPSILON &&
Math.abs(targetY - currentY) < EPSILON
) {
currentX = targetX
currentY = targetY
scheduledFrame = false
console.log('animation stopped!')
}
for (const layer of layers) {
const moveX = currentX * layer.offsetX
const moveY = currentY * layer.offsetY
layer.element.style.transform = `translate(${moveX}px, ${moveY}px)`
}
if (scheduledFrame) {
requestAnimationFrame(render)
}
}
container.addEventListener('pointerleave', () => {
targetX = 0
targetY = 0
startRender()
})