5.3 作用域、闭包和this

let 声明的变量只存在于其所在的代码块中

由于 JS 是基于词法(静态)作用域的语言,词法作用域的含义是在函数定义时就确定了作用域,而不是函数执行时再确定

calculate 函数,所带的闭包,scope =10;

第六章

Microdata 进行SEO优化:

7.3 提高Web动画的性能实战

7.8.1 使用CSS3动画

   

velocity源码解读

阅读(1,878) 评论(0) JS2017-01-01

写在前面

一个号称incredibly fast的动画库,好奇很久了,最近差不多读完了源码

一.结构

动画库基本结构:

  • timer:周期执行的定时器,比如递归requestAnimationFrame/setTimeout

  • tween:补间数据,包括duration, progress, easing, events

  • tick():定时器每次执行的动作,更新补间数据,应用到元素上

有了这些东西,动画就能跑起来了,只是原始一点野蛮一点而已:

var timer = window.requestAnimationFrame || setTimeout;
var tween = {
startTime: 0,
el: document.body,
property: 'marginLeft',
start: 0,
end: 200,
unit: 'px',
duration: 1000,
easing: function(p) {return p;},
begin: function() {console.log('begin')},
progress: function() {console.log('progress')},
complete: function() {console.log('complete')}
};
var tick = function() {
if (!tween.startTime) {
tween.startTime = Date.now();
tween.begin && tween.begin.call(tween.el);
}
var p = Math.min((Date.now() - tween.startTime) / tween.duration, 1);
var delta = tween.end - tween.start;
if (p < 1) {
tween.el.style[tween.property] = tween.start + delta * tween.easing(p) + tween.unit;
tween.progress && tween.progress.call(tween.el);
timer(tick);
}
else {
tween.el.style[tween.property] = tween.end + tween.unit;
tween.complete && tween.complete.call(tween.el);
}
}
// use
tick();

效果是body在1秒内向右匀速移动200px,看起来傻傻的,我们可能想要一些增强效果:

  • 多个元素按顺序动/同时动

  • 稍复杂的easinglinear太无趣了)

  • 循环(有限次/无限次)、暂停、停止

为了支持这些,还需要一些扩展结构:

  • 动画队列:控制动画序列

  • easing包:缓动效果、物理效果、step效果等等

  • 控制命令:reversepause/resumestop等等

当然,基础结构也不够健壮,至少应该有:

  • CSS工具包:负责校验/存取CSS属性,包括属性前缀检测、单位转换、硬件加速、子属性整合

  • 数据缓存:用来存放动画队列、已知的属性前缀、不频繁变化的DOM属性值

到这里,一个动画库的结构基本完整了,我们可能还想要一些高级功能:

  • 快进

  • 重播

  • 跳过

这些强大的特性能给我们带来惊喜,事实上Velocity支持快进(mock),而读源码就是为了添上重播和跳过功能

二.设计理念

1.缓存所有能缓存的东西

通过缓存数据,来尽可能地减少DOM查询,一点一点提升性能

源码从来不解释为什么缓存,只偶尔提到为什么不做缓存:

/* Note: Unlike other properties in Velocity, the browser's scroll position is never cached since it so frequently changes
(due to the user's natural interaction with the page). */
// 当前scroll位置,起点
//! scroll不缓存,每次都从node取(el.scrollLeft/Top),因为频繁变化
scrollPositionCurrent = opts.container["scroll" + scrollDirection]; /* GET */

除了缓存,另一个提升性能的技巧是整合操作,只在最后写一次DOM,例如transformCache

2.把动画逻辑收敛进来

除了必需的动画事件,Velocity提供了非常人性化的display/visibility设计:none/visibility值在动画结束时应用,非none/visibility值在动画开始时就用

类似的还有属性值可以是function,根据元素在集合中的位置来生成初始值,例如:

$("div").velocity({
translateX: function(i, total) {
// i is equal to the current element's index in the total set of divs.
// Successively increase the translateX value of each element.
return (i * 20);
}
}, 2000);

这样做是为了把动画逻辑收敛在Velocity中,动画相关逻辑应该交给动画库控制,保证业务代码干净

三.技巧

1.正则环视的用法

不匹配内容,但是强制检查,比如场景:

// 去掉rgb的小数部分,保留a的小数部分(通过肯定正则环视来搞定的)
'rgba(1.5, 1.4, 1.1, 0.3)'.replace(/\.(\d)+(?=,)/g, "")
"rgba(1, 1, 1, 0.3)"

2.异步throw

//!!! 技巧,异步throw,不会影响逻辑流程
setTimeout(function() {
throw error;
}, 1);

例如:

/* We throw callbacks in a setTimeout so that thrown errors don't halt the execution of Velocity itself. */
try {
opts.complete.call(elements, elements);
} catch (error) {
setTimeout(function() {
throw error;
}, 1);
}

3.循环动画的实现

利用reverse巧妙实现循环,有限次循环:

// 需要reverse的次数
//! 第一次是正向的,后续的2n-1次都是reverse,例如:正-反-反反-反反反
//! 只是调换起点终点,所以可以这么干
var reverseCallsCount = (opts.loop * 2) - 1;

无限循环:

// 通过reverse + loop: true来实现无限循环(第一次单程结束时调换起点终点)
Velocity(element, "reverse", {loop: true, delay: opts.delay});

4.jQuery队列的’inprogress’哨兵

自动dequeue时,如果发现队首元素为inprogress的话,不dequeue。而每次dequeue时,都会往队列里unshift('inprogress')

这样保证了第一次自动dequeue,后续的必须手动dequeue。用标识变量也行,但得挂在queue数组上,用数组首元可能是为了避免往数组上添属性

P.S.自动dequeue在源码processElement()尾部,比较隐蔽

四.黑科技及注意事项

Velocity的文档常年不更新,且只介绍基本用法,这里介绍一些从源码中发现的好东西

黑科技

1.查看补间插值

如果动画属性名为tween,表示测试补间插值。progress回调的第5个参数为补间插值,其它时候为null。例如:

$el.velocity({
tween: 500
}, {
easing: 'easeIn',
delay: 300,
duration: 600,
progress: function() {
console.log(arguments[4]);
}
});`

可以输出每个tick0变化到500的具体值,有些场景下,这些补间值很有用

2.停止所有动画

有没有办法直接停掉tick loop?有的。

$.Velocity.State.isTicking = false

tick loop的开关,直接停掉rAF递归,next tick生效

但这个是破坏性的,不可恢复,因为停之前没有处理ctx(当前值,当前时间等等)

而且,这样直接停掉tick loop,在性能上不是最优的,因为缺少收尾处理:移除动画元素身上多余的3D变换(主要指硬件加速hack),减少复合层数

3.操作缓存数据

一般不需要手动修改缓存值,但在解决一些闪烁的问题时很有用:

// 设置velocity缓存值
Velocity.Utilities.data(node, "velocity").transformCache = {
'scaleX': '0.8',
'scaleY': '0.8'
};

同样,在重置动画时单纯抹掉style没有用,下次动画仍然取缓存值,必须要清除属性值缓存:

// 清除velocity缓存值
$.Velocity.Utilities.removeData(node);

注意事项

1.调试性能时注意硬件加速

mobileHA选项会被修正,Chrome调试必须开模拟移动设备才能看到真实的层数:

// 硬件加速
// 传入mobileHA=true不算,设备支持才行(移动设备,且不是安卓2.3)
opts.mobileHA = (opts.mobileHA && Velocity.State.isMobile && !Velocity.State.isGingerbread);

2.无限360度旋转

每个属性可以有不同的easing,例如:

$el.velocity({
translateX: [100, 'easeInOut', 0]
}, 1000);

但无限360度旋转的动画不能这样传入easing,否则每转一圈会有停顿,例如:

// 第一圈正常,之后每圈结束有停顿
$el.velocity({
rotateZ: [360, 'linear', 0]
}, {
duration: 1000,
loop: true
});

从现象上看是有停顿,其实原因来自reverse的内部实现:

/* Easing is the only option that embeds into the individual tween data (since it can be defined on a per-property basis).
Accordingly, every property's easing value must be updated when an options object is passed in with a reverse call.
The side effect of this extensibility is that all per-property easing values are forcefully reset to the new value. */
// 如果传入了非空opt,每个属性的easing统一用opt的easing
//! 因为easing可以是属性级的
//! 如果传入的opt有easing,就用该值统一覆盖掉上一个call中各个属性的
if (!Type.isEmptyObject(options)) {
lastTweensContainer[lastTween].easing = opts.easing;
}

算是实现上的bug,因为非空opt不代表opt.easing非空,所以停顿的原因是:

第一圈正常:linear
第二圈:reverse中把linear改成swing(默认easing)了
第n圈:都是reverse,所以都是swing

swing效果是两头慢,中间快,这样就出现了诡异的停顿。当然,紧急修复方案是把easing写在opt里,例如:

// 第一圈正常,之后每圈结束有停顿
$el.velocity({
// 这里的easing要与下面的一致,或者干脆去掉
rotateZ: [360, 'linear', 0]
}, {
easing: 'linear',
duration: 1000,
loop: true
});

3.background-position无限循环动画有问题

通过源码很容易发现逻辑漏洞:

//!!! 这里有bug,如果startValue不是0,这里会给强制0
// 例如backgroundPositionX: ['100%', -100],这里会露出前100像素,强制从0到100%
if (/^backgroundPosition/.test(propertyName) && parseFloat(tweenContainer.endValue) === 100 && tweenContainer.unitType === "%") {
tweenContainer.endValue = 0;
tweenContainer.startValue = 100;
}

应该是像rotate一样,交换起点终点,这里强制为0就有问题了,例如:

$el.css({
background: 'url(ruler.jpeg) no-repeat top left',
backgroundSize: 'auto 100%',
backgroundPosition: '-100px 0'
})
.velocity({
backgroundPositionX: ['100%', -100]
}, {
duration: 2000,
loop: true
});

background-position相关动画中需要注意这一点,或者手动修复它

五.源码分析

Git地址:https://github.com/ayqy/velocity-1.4.1

P.S.源码4600行,读完手动注释版本5400行,足够详细

 

由于viewport单位得到众多浏览器的兼容,lib-flexible这个过渡方案已经可以放弃使用,不管是现在的版本还是以前的版本,都存有一定的问题。建议大家开始使用viewport来替代此方案。vw的兼容方案可以参阅《如何在Vue项目中使用vw实现移动端适配》一文。

Compass is no longer actively maintained. Compass is a Stylesheet Authoring Environment that makes your website design simpler to implement and easier to maintain. http://compass-style.org
 
 
Sass makes CSS fun! https://sass-lang.com
 

PostCSS plugin to parse CSS and add vendor prefixes to CSS rules using values from Can I Use. It is recommended by Google and used in Twitter and Alibaba.

 

Sass是一种"CSS预处理器",可以让CSS的开发变得简单和可维护。但是,只有搭配Compass,它才能显出真正的威力。

本文介绍Compass的用法。毫不夸张地说,学会了Compass,你的CSS开发效率会上一个台阶。

一、Compass是什么?

简单说,Compass是Sass的工具库(toolkit)。

Sass本身只是一个编译器,Compass在它的基础上,封装了一系列有用的模块和模板,补充Sass的功能。它们之间的关系,有点像Javascript和jQuery、Ruby和Rails、python和Django的关系。

二、安装

Compass是用Ruby语言开发的,所以安装它之前,必须安装Ruby。

Compass 提供了大量的混合宏 Mixins 用来处理类似添加浏览器前缀这样的工作

一种更优雅的处理浏览器前缀的方式是使用 CSS 的后处理程序,比如 PostCSS 最流行的 Autoprefixer 插件

第8章 前端工程化实战

CSS将从入口脚本文件中抽离出来,作为一个单独的入口样式文件,并在入口页面文件里直接引用

DefinePlugin插件用来定义一些全局变量,这些变量可以在模块当中直接使用,比如通常定义一个变量来标识当前是开发环境还是生产环境;

缓存控制:

模块引用:

相对路径、绝对路径和模块路径

当前路径 --> --> 如果文件不存在,继续往上层目录查找,直至磁盘根目录

后缀名自动补全

异步模块加载

Source Map 提供了源文件代码到目标文件代码的对应关系






《移动WEB前端高级开发实践@www.java1234.com.pdf》——2的更多相关文章

  1. 《从零开始做一个MEAN全栈项目》(1)

    欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习. 在本系列的开篇,我打算讲一下全栈项目开发的优势,以及MEAN项目各个模块的概览. 为什么选择全栈开发? ...

  2. 《从零开始做一个MEAN全栈项目》(2)

    欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习.   上一节简单介绍了什么是MEAN全栈项目,这一节将简要介绍三个内容:(1)一个通用的MEAN项目的技 ...

  3. 《从零开始做一个MEAN全栈项目》(3)

    欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习. 上一篇文章给大家讲了一下本项目的开发计划,这一章将会开始着手搭建一个MEAN项目.千里之行,始于足下, ...

  4. 《从零开始做一个MEAN全栈项目》(4)

    欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习. 在上一篇中,我们讲了如何去构建第一个Express项目,总结起来就是使用两个核心工具,express和 ...

  5. 一个关于vue+mysql+express的全栈项目(一)

    最近学了mysql数据库,寻思着能不能构思一个小的全栈项目,思来想去,于是就有了下面的项目: 先上几张效果图吧       目前暂时前端只有这几个页面,后端开发方面,有登录,注册,完善用户信息,获取用 ...

  6. Vue、Nuxt服务端渲染,NodeJS全栈项目,面试小白的博客系统~~

    Holle,大家好,我是李白!! 一时兴起的开源项目,到这儿就告一段落了. 这是一个入门全栈之路的小项目,从设计.前端.后端.服务端,一路狂飙的学习,发量正在欣喜若狂~~ 接触过WordPress,H ...

  7. Vue、Node全栈项目~面向小白的博客系统~

    个人博客系统 前言 ❝ 代码质量问题轻点喷(去年才学的前端),有啥建议欢迎联系我,联系方式见最下方,感谢! 页面有啥bug也可以反馈给我,感谢! 这是一套包含前后端代码的个人博客系统,欢迎各位提出建议 ...

  8. SpringBoot 整合 Elastic Stack 最新版本(7.14.1)分布式日志解决方案,开源微服务全栈项目【有来商城】的日志落地实践

    一. 前言 日志对于一个程序的重要程度不用过多的言语修饰,本篇将以实战的方式讲述开源微服务全栈项目 有来商城 是如何整合当下主流日志解决方案 ELK +Filebeat . 话不多说,先看实现的效果图 ...

  9. 全栈项目|小书架|服务器端-NodeJS+Koa2实现首页图书列表接口

    通过上篇文章 全栈项目|小书架|微信小程序-首页水平轮播实现 我们实现了前端(小程序)效果图的展示,这篇文章来介绍服务器端的实现. 首页书籍信息 先来回顾一下首页书籍都有哪些信息: 从下面的图片可以看 ...

  10. 全栈项目|小书架|服务器开发-NodeJS 使用 JWT 实现登录认证

    通过这篇 全栈项目|小书架|服务器开发-JWT 详解 文章我们对JWT有了深入的了解,那么接下来介绍JWT如何在项目中使用. 安装 $ npm install jsonwebtoken 生成 Toke ...

随机推荐

  1. Task 的一些个人见解

    Task确实比较好用且优雅 我感觉.NET要成为艺术家... public class TheTask { /// <summary> /// 直接调用是同步方法 /// </sum ...

  2. 各种常用js函数实现

    1.bind function bind(fn, context) {    var args = Array.prototype.slice.call(arguments, 2);    retur ...

  3. 在C#中将对象序列化成Json格式

    在C#中将对象转换为Json格式的字符串. //匿名对象 var dataObj = new { Number = 1, Name = "Json" }; //将返回的时间格式解析 ...

  4. AQS系列(四)- ReentrantReadWriteLock读写锁的释放锁

    前言 继续JUC包中ReentrantReadWriteLock的学习,今天学习释放锁. 一.写锁释放锁 入口方法 public void unlock() { sync.release(1); } ...

  5. net core 3.1 跨域 Cors 找不到 “Access-Control-Allow-Origin”

    首先在ConfigureServices添加 public void ConfigureServices(IServiceCollection services) { services.AddCors ...

  6. Android高斯模糊实现方案

    1.使用Glide Glide.with(this) .load(service.getImageUri()) .dontAnimate() .error(R.drawable.error_img) ...

  7. 使用Git出现以下错误"Git@github.com: Permission denied (publickey). Could not read from remote repository."解决方案

    转载于:https://blog.csdn.net/dotphoenix/article/details/100130424 git@github.com: Permission denied (pu ...

  8. Linux 版本控制工具之rabbitvcs

    原文地址:http://www.robotshell.com/2017/11/04/Linux-%E7%89%88%E6%9C%AC%E6%8E%A7%E5%88%B6%E5%B7%A5%E5%85% ...

  9. Codeforces Round #608 (Div. 2) 题解

    目录 Codeforces Round #608 (Div. 2) 题解 前言 A. Suits 题意 做法 程序 B. Blocks 题意 做法 程序 C. Shawarma Tent 题意 做法 ...

  10. .Net Core WebApi 模型验证无效时报400

    问题 模型验证无效时,没有进入到接口里,而是直接报400 Bad Request,非常不友好. 环境 SDK:.Net Core 2.2.401 开发工具:VS2017 step 1 创建接口 /// ...