我需要创建一些自定义滚动动画-并希望开始探索制作一个简单块的动画。
使用json-我想提供块的骨架(类名,高度,宽度,背景),然后提供与滚动值相关的每个开始/结束帧的动作。
我该如何修改代码-使用数据json处理该块的前进/后退动画
所以在这个例子中。
-如果卷轴超过400,则摧毁方块。
所以动画要在向前的方向上保持住,但是我想在相反的方向上反转动画-因此时间轴可以向前,向后移动-取决于滚动速度-因此是慢动作或加速情感可以抓住
这是第一步-添加具有多个对象的更复杂的动画,更长的复杂动画。
我已尝试捕获翻译细节,以使原汁原味的x或y翻译不会被覆盖-但我认为这是一个错误。...
请复查 Get translate3d values of a div?
// jsfiddle
https://jsfiddle.net/g10qe5m6/6/
var data = [{
"structure": {
"name": "square",
"height": 30,
"width": 30,
"x": 10,
"y": 10,
"background": 'url("https://i.pinimg.com/originals/74/f3/5d/74f35d5885e8eb858e6af6b5a7844379.jpg")'
},
"frames": [{
"create": [{
"s": 0
}, {
"e": 0
}]
}, {
"moveRight": [{
"s": 1
}, {
"e": 400
}]
}, {
"destroy": [{
"s": 400
}, {
"e": 400
}]
}]
}]
//console.log(data)
function getCurrentValues(el) {
var results = $(el).css('transform').match(/matrix(?:(3d)\(\d+(?:, \d+)*(?:, (\d+))(?:, (\d+))(?:, (\d+)), \d+\)|\(\d+(?:, \d+)*(?:, (\d+))(?:, (\d+))\))/)
if(!results) return [0, 0, 0];
if(results[1] == '3d') return results.slice(2,5);
results.push(0);
return results.slice(5, 8);
};
var animations = {
createObj: function(obj) {
//create object
var block = $('<div></div>');
$(block).addClass(obj.name);
$(block).addClass("animatedblock");
$(block).css("height", obj.height);
$(block).css("width", obj.width);
$(block).css("transform", 'translate(' + obj.x + 'px, ' + obj.y + 'px)');
$(block).css("background", obj.background);
$(block).css("background-size", "cover");
$('.container').append($(block));
},
deleteObj: function(el) {
//destroy object
el.remove()
},
moveRight: function(el, pixels) {
//el.css('')
//move right
console.log("x", getCurrentValues(el)[0])
console.log("y", getCurrentValues(el)[1])
el.css('transform', 'translate(' + pixels + 'px, ' + getCurrentValues(el)[1] + 'px');
//el.css('transform', 'translate(' + pixels + 'px, ' + getCurrentValues(el).y + 'px');
},
moveLeft: function(el, pixels) {
//move left
//el.css('transform', 'translate(' + -pixels + 'px, ' + getCurrentValues(el).y + 'px');
console.log("x", getCurrentValues(el)[0])
console.log("y", getCurrentValues(el)[1])
el.css('transform', 'translate(' + -pixels + 'px, ' + getCurrentValues(el)[1] + 'px');
},
moveDown: function(el, pixels) {
//move down
//el.css('transform', 'translate(' + getValues(el).x + 'px, ' + pixels + 'px)');
el.css('transform', 'translate(' + getCurrentValues(el)[0] + 'px, ' + pixels + 'px');
},
moveUp: function(el, pixels) {
//move up
// el.css('transform', 'translate(' + getValues(el).x + 'px, ' + -pixels + 'px)');
el.css('transform', 'translate(' + getCurrentValues(el)[0] + 'px, ' + -pixels + 'px');
}
}
//app.deleteObj($('.square'));
//data.skeleton
/*
var instructor = {
action: function(data, position) {
console.log("position", position)
$.each(data, function(i, item) {
//alert(item.PageName);
console.log("item", item.frames)
});
}
}
*/
var frames = data[0].frames;
var instructor = {
action: function(scroll, direction) {
var sequence = [{
"create": 0,
"moveRight": 100,
"moveDown": 200,
"destroy": 400
}]
//if down - forward animation
//if up - reverse animation
///use the data to detect what the block can do at what start and end frame
if (scroll == 0) {
//create block
//animations.createObj(data[0].structure);
}
if (scroll > 100 && scroll < 400) {
//move right
animations.moveRight($('.square'), scroll);
}
if (scroll > 400 && scroll < 800) {
//move right
animations.moveDown($('.square'), scroll);
}
if (scroll > 800) {
//animations.deleteObj($('.square'));
}
//move left
//animations.moveLeft($('.square'), scroll);
}
}
animations.createObj(data[0].structure);
var position = $(window).scrollTop();
$(window).scroll(function() {
var scroll = $(window).scrollTop();
console.log("scroll", scroll);
if (scroll > position) {
console.log('scrollDown');
instructor.action(scroll, "down");
} else {
console.log('scrollUp');
instructor.action(scroll, "up");
}
position = scroll;
});
答案 0 :(得分:4)
尽管问题过于广泛,无法在一个答案中解决,但我会尽力给您 一个主意。将代码分解为小模块,以处理滚动事件和动画操作。 subscription方法用于以Observable模式绑定事件侦听器。其余的 该代码不言自明。如有任何疑问,请在下面评论。
let data = [{
"structure": {
"name": "square",
"height": 30,
"width": 30,
"x": 0,
"y": 0,
"background": 'url("https://i.pinimg.com/originals/74/f3/5d/74f35d5885e8eb858e6af6b5a7844379.jpg")'
},
"frames": [{
"animation": "move",
"start": 0,
"stop": 300,
"startPositionX": 0,
"startPositionY": 0,
"endPositionX": 90,
"endPositionY": 0,
}, {
"animation": "move",
"start": 301,
"stop": 600,
"startPositionX": 90,
"startPositionY": 0,
"endPositionX": 90,
"endPositionY": 80,
}, {
"animation": "move",
"start": 601,
"stop": 900,
"startPositionX": 90,
"startPositionY": 80,
"endPositionX": 0,
"endPositionY": 0,
}, {
"animation": "show",
"start": 601,
"stop": 9999,
"positionX": 0,
"positionY": 0,
}],
},
{
"structure": {
"name": "pear",
"height": 30,
"width": 30,
"x": 90,
"y": 80,
"background": 'url("https://i.pinimg.com/originals/74/f3/5d/74f35d5885e8eb858e6af6b5a7844379.jpg")'
},
"frames": [{
"animation": "move",
"start": 0,
"stop": 300,
"startPositionX": 90,
"startPositionY": 80,
"endPositionX": 0,
"endPositionY": 80,
}, {
"animation": "move",
"start": 301,
"stop": 600,
"startPositionX": 0,
"startPositionY": 80,
"endPositionX": 0,
"endPositionY": 0,
}, {
"animation": "move",
"start": 601,
"stop": 900,
"startPositionX": 0,
"startPositionY": 0,
"endPositionX": 90,
"endPositionY": 80,
}, {
"animation": "show",
"start": 601,
"stop": 9999,
"positionX": 90,
"positionY": 80,
}],
}
]
let animations = {
setup: function($container) {
this.$container = $container;
this.viewportWidth = $container.width();
this.viewportHeight = $container.height();
},
createBlock: function(blockSpec) {
let $block = $('<div>');
$block.addClass(blockSpec.name);
$block.addClass("animatedblock");
$block.css("height", blockSpec.height);
$block.css("width", blockSpec.width);
$block.css("background", blockSpec.background);
$block.css("background-size", "cover");
this.$container.append($block);
this.setPosition($block, blockSpec.x, blockSpec.y)
return $block;
},
setPosition($block, x, y) {
$block.css({
left: x / 100 * this.viewportWidth,
top: y / 100 * this.viewportHeight,
});
},
moveBlock($block, frame, scrollProgress) {
let blockPositionX = frame.startPositionX + scrollProgress * (frame.endPositionX - frame.startPositionX);
let blockPositionY = frame.startPositionY + scrollProgress * (frame.endPositionY - frame.startPositionY);
this.setPosition($block, blockPositionX, blockPositionY);
},
showBlock: function($block, frame) {
$block.show()
this.setPosition($block, frame.positionX, frame.positionY);
},
hideBlock: function($block) {
$block.hide()
},
}
class ScrollObserver {
constructor() {
let $window = $(window);
this.STOP_DISPATCH = 'STOP_DISPATCH';
this.subscribers = [];
$window.scroll(event => this.dispatch($window.scrollTop()));
}
subscribe(subscriberFn) {
this.subscribers.push(subscriberFn);
}
dispatch(scrollPosition) {
for (let subscriberFn of this.subscribers) {
if (subscriberFn(scrollPosition) == this.STOP_DISPATCH) break;
}
}
}
jQuery(function($) {
animations.setup($('.container'));
$(window).resize(event => animations.setup($('.container')));
for (let obj of data) {
let scrollObserver = new ScrollObserver();
let blockSpec = obj.structure;
let $block = animations.createBlock(blockSpec);
for (let frame of obj.frames) {
scrollObserver.subscribe(scrollPosition => {
if (scrollPosition >= frame.start && scrollPosition <= frame.stop) {
let scrollProgress = (scrollPosition - frame.start) / (frame.stop - frame.start);
switch (frame.animation) {
case 'move':
animations.moveBlock($block, frame, scrollProgress);
break;
case 'show':
animations.showBlock($block, frame);
}
return scrollObserver.STOP_DISPATCH;
}
});
}
}
});
body {
height: 1500px;
}
.container {
background: grey;
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100vw;
box-sizing: content-box;
}
.animatedblock {
position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container"></div>