$('html,body').animate({ scrollTop: $('#anchorOfMyTargetSection').offset().top },'slow');
在Dart,我可以制作卷轴,但我不知道如何为它制作动画:
int targetSection = querySelector('#anchorOfMyTargetSection').offsetTop; window.scrollTo( 0,targetSection );
更具体地说,我正在做一个单页,其中包含指向自我页面中各节的链接.
以下是链接:
<nav> <ul class="nav-list"> <li><a href="http://example.com/#title">Home</a></li> <li><a href="http://example.com/#about">About us</a></li> <li><a href="http://example.com/#products">Products</a></li> <li><a href="http://example.com/#services">Services</a></li> <li><a href="http://example.com/#contact">Contact</a></li> </ul> </nav>
这是完整的jQuery代码:
// Generated by LiveScript 1.2.0 var smoothScrolling; smoothScrolling = function(selector,offset){ return $(selector).click(function(click){ var link,anchor; click.preventDefault(); link = $(this).attr('href'); anchor = link.substring(link.indexOf('#')); return $('html,body').animate({ scrollTop: $(anchor).offset().top + offset },'slow'); }); }; smoothScrolling('.nav-list a',-45);
这里是Dart代码(当然没有动画部分):
import 'dart:html'; void main() { smoothScrollingOffset = -45; querySelectorAll('.nav-list a').onClick.listen(smoothScrolling); } int smoothScrollingOffset = 0; void smoothScrolling(MouseEvent click) { click.preventDefault(); String link = click.target.toString(); String anchor = link.substring( link.indexOf('#') ); int targetPosition = querySelector('$anchor').offsetTop; window.scrollTo( 0,targetPosition + smoothScrollingOffset ); }
请记住,我不是Dart的新手,也不是一般的编程新手.如果您看到Dart代码中可以改进的东西,请告诉它.
解决方法
这些是链接
<nav> <ul class="nav-list"> <li><a href="http://example.com/#title">Home</a></li> <li><a href="http://example.com/#about">About us</a></li> <li><a href="http://example.com/#products">Products</a></li> <li><a href="http://example.com/#services">Services</a></li> <li><a href="http://example.com/#contact">Contact</a></li> </ul> </nav>
在您的Dart代码中导入dart:html库以访问DOM.
import 'dart:html';
这是函数,这就是它的作用:
>单击链接时,将对其进行分析并提取锚点
>它使用锚点来了解哪个元素/部分比您要查找的要多
>然后获取元素/部分位置
>滚动到元素/部分
.
void smoothScrolling(String selector,{int offset: 0,int duration: 500}) { // The detection of the clicks and the selectors of the links are specified at the bottom of the function // Let's suppose you click a link to visit 'http://example.com/#contact' // When you click the link void trigger(MouseEvent click) { // Prevent to visit the resources,like normally does click.preventDefault(); // Get the resource link of the clicked element. In this case: 'http://example.com/#contact' String link = click.target.toString(); // Extract the anchor. In this case from 'http://example.com/#contact' will extract '#contact' String anchor = link.substring( link.indexOf('#') ); // With the extracted anchor,search the corresponding element and get his position. // In this case gets the position of the element with 'contact' in the 'id' attribute int targetPosition = querySelector('$anchor').offsetTop; // Before to translate to the element,// you can specify if you want to translate some distance before or after the element targetPosition += offset; // Let's move in direction to the section // We know than in Dart there are 60 frames per second,that means a frame duration is // 1000 milliseconds divided in 60 frames = per frame is 16.66 milliseconds long. // But 16.66 milliseconds multiplied by 60 = 999.99 milliseconds. That is ALMOST a second. // And that means than there will be 59.99 frames in 999.99 milliseconds // But we cannot handle frame fractions,we should round frames to integers // So 59.99 frames will be rounded to 60 frames // Calculate the total number of frames int totalFrames = ( duration / (1000 / 60) ).round(); // The first animation frame will be the number 1,the number 0 will be the start point int currentFrame = 0; // In this case the start point will be the current position int currentPosition = window.scrollY; // The end point will be the target position,we should know how many distance there is between the start and end point. // The positive and negative numbers represents the same distance,that means than 'y' and '-y' are the same. // Example: 10 and -10 are the same distance. // Calculate the distance between the start and end point. int distanceBetween = targetPosition - currentPosition; // Then calculate how many distance should move per frame num distancePerFrame = distanceBetween / totalFrames; // The animation function is triggered by first time more later in the code // And when is triggered void animation(num frame) { // First we look the number of the frame we are going to run. // When all the frames are complete the animation function will not be executed again if ( totalFrames >= currentFrame ) { // In every frame we are going to move some distance with direction to the target. // The direction (in this case will be only up or down) depends of the 'distanceBetween' number. // Let's explore this part with an example: You are 10 pixels from your target,your target is at the point 20,// Remember,to calculate the distance between you and the target we do 'targetPosition - currentPosition'. // If you are 10 pixels on from the target (at the point 10) the result will be: 20 - 10 = 10. // If you are 10 pixels down from the target (at the point 30) the result will be: 20 - 30 = -10. // You see how the number is the same but with different polarity?. And 10 and - 10 represent the same distance // The direction depends of the number 0,if you move closer to the 0 you will go down,if you move away the 0 you will move up. // Let's move 5 pixels: // 10 + 5 = 15. You will move down,because you will be more away of the 0,your target is at the number 20. // -10 + 5 = -5. You will move up,because you will be more closer to the 0,your target is at the number 0. // Let's move to the point where we should be in this frame window.scrollTo( 0,currentPosition ); // Calculate the point where we should be in the next frame currentPosition += distancePerFrame; // We get ready to execute the next frame currentFrame++; // When the time of this frame (16.66 milliseconds) is complete immediately starts the next frame. window.animationFrame.then(animation); } } // Here is triggered the animation by first time window.animationFrame.then(animation); } // Here are the links' selectors and the detection of the clicks querySelectorAll(selector).onClick.listen(trigger); }
要使用该功能,我们应指定链接的选择器,以及可选的滚动偏移和/或持续时间.
void main() { // To use the function we should specify the links' selectors,// and optionally an offset and/or the duration of the scrolling,smoothScrolling('.nav-list a',offset: -45,duration: 2500); }
动画
我将解释要点,所有细节都在代码中注释.
标记的另一件事是我长期使用Blender,一个开源的3D动画软件,感谢Blender我进入了编程世界.所以我知道我在谈论动画.
1. Dart文档
这是第一个难点.如果您在Dart docs中搜索动画来处理动画,你会发现animationFrame,这似乎没问题.
但首先,什么是框架?也许你已经听过每秒24帧的东西.这意味着,在这种情况下,帧是1秒除以24 =每帧是0.0416秒长=每41.66毫秒一帧.
然后让我们处理帧作为时间块,这个时间块通常作为整数处理.我们通常会这样说:这个屏幕是每秒24帧,但是这个屏幕不是每秒24.6帧.
但是文档中存在问题.
The Future completes to a timestamp that represents a floating point
value of the number of milliseconds that have elapsed since the page
started to load (which is also the timestamp at this call to
animationFrame).
好的,这意味着我可以知道页面中的用户已经有多少时间,但是没有任何关于我每秒可以知道多少次的参考,这就是我在谈论帧时所期望的:一秒钟有多少帧?
2.飞镖中的帧
经过一些实验,我发现比Dart每秒有60帧
1000 milliseconds divided in 60 frames = per frame is 16.66
milliseconds long. But 16.66 milliseconds multiplied by 60 = 999.99
milliseconds. That is ALMOST a second. And that means than there will
be 59.99 frames in 999.99 milliseconds But we cannot handle frame
fractions,we should round frames to integers. So 59.99 frames will be
rounded to 60 frames
记住一帧长16.66毫秒.
3.达特动画
// Set the duration of your animation in milliseconds int duration = 1000; // Calculate the total number of frames int totalFrames = ( duration / (1000 / 60) ).round(); // The first animation frame will be the number 1,the number 0 will be the start point int currentFrame = 0; // The animation function is triggered by first time more later in the code // And when is triggered void animation(num frame) { // First we look the number of the frame we are going to run. // When all the frames are complete the animation function will not be executed again if ( totalFrames >= currentFrame ) { // =========================================== // Here what we are going to do in every frame // =========================================== // We get ready to execute the next frame currentFrame++; // When the time of this frame (16.66 milliseconds) is complete immediately starts the next frame. window.animationFrame.then(animation); } } // Here is triggered the animation by first time window.animationFrame.then(animation);
注意:
1.我发现了编写smoothScrolling函数的错误,但不要担心,只会影响Dart虚拟机,编译的JavaScript按预期工作.我试图找到究竟是什么导致错误,所以可以报告它.
我发现的是在动画函数make中使用数字distancePerFrame而不是函数不循环.
2.从技术上讲,这不是’平滑滚动’,是’线性滚动’.