分类 前端 下的文章

1.Anime.js

地址:https://animejs.com/

7B4B78D3-F551-46C2-B144-F4EEE29ACD98 2.gif

Anime.js 在 GitHub 上有超过 4.3 万颗星,是最受欢迎的动画库之一。
它是一个轻量级 JavaScript 动画库,具有简单的 API,可用于为 CSS 属性、SVG、DOM 属性和 JavaScript 对象制作动画。使用 Anime.js,我们可以播放、暂停、重启或反转动画。该库还提供了惊人的功能,可通过跟进和重叠动作为多个元素制作动画。该库还包含各种与动画相关的事件,我们可以使用回调和承诺来监听这些事件。

2. Lottie

地址:https://airbnb.io/lottie/

7C8CA4F1-A999-4FB0-8B40-015EB7CF9AF7.gif

Lottie 是一个库,可以解析使用 Bodymovin 插件以 JSON 格式导出的 Adobe After Effects 动画,并在移动和网络应用程序上进行原生渲染。这样,用户就无需手动重新制作由专业设计师在 After Effects 中创建的高级动画。仅网络版在 GitHub 上就有超过 27k 个星。

3. Velocity

地址:http://velocityjs.org/

使用Velocity,你可以创建颜色动画、变换、循环、缓和、SVG动画等。它使用的 API 与 jQuery 库中的 $.animate() 方法相同,如果 jQuery 可用,它还可以与之集成。该库提供渐变、滚动和滑动效果。除了能控制动画的持续时间和延迟外,还能在动画完成后的某个时间反转动画,或在动画进行时完全停止。该库在 GitHub 上有 17k 多颗星,是 Anime.js 的理想替代品。

4. Rough Notation

地址:https://roughnotation.com/

E711C1D5-7AD4-4A66-97A5-CAF8F68DE4C5.gif

Rough Notation 是一个 JavaScript 库,用于在网页上创建彩色注释并制作动画。它使用 RoughJS 创建手绘的外观和感觉。您可以创建多种注释样式,包括下划线、方框、圆圈、高亮、删除线等,还可以控制每种注释样式的持续时间和颜色。

5. Popmotion

地址:https://popmotion.io/

CF3C90A0-7793-4BC4-9053-02718E8A445A.gif

Popmotion 是一个功能强大的库,用于创建引人注目的动画。它为何与众不同?- Popmotion 不假定您打算制作动画的对象属性,而是提供可在任何 JavaScript 环境中使用的简单、可组合的函数。
该库支持数字、颜色和复杂字符串的关键帧、弹簧和惯性动画。该库测试良好,维护积极,在 GitHub 上拥有 19k 多颗星。

6. Vivus

地址:https://maxwellito.github.io/vivus/

1B0F14F6-A2F3-456B-9BA0-8102F8B9F360.gif

Vivus 是一个 JavaScript 库,可让你为 SVGs 制作动画,使其看起来就像正在绘制一样。它速度快、重量轻,完全不依赖任何工具,并提供三种不同的 SVG 动画制作方法:它提供三种不同的 SVG 动画制作方法:延迟、同步和逐一。还可以使用自定义脚本,以自己喜欢的方式绘制 SVG。
Vivus 还允许您自定义持续时间、延迟、定时功能和其他动画设置。查看 Vivus Instant,了解现场实际操作示例。

7.绿袜动画平台(GSAP

地址:https://greensock.com/

EAC59BAC-69AE-4B0E-A4C3-AB6572ACFA61.gif

GreenSock Animation Platform (GSAP) 是一个库,可让我们创建适用于所有主流浏览器的精彩动画。可以在 React、Vue、WebGL 和 HTML 画布中使用它来制作颜色、字符串、运动路径等动画。它还附带了一个 ScrollTrigger 插件,让您只需少量代码就能创建令人印象深刻的基于滚动的动画。
GSAP已在1100多万个网站中使用,在GitHub上有超过15K个 "星",是一个通用而受欢迎的工具。您可以使用 GreenSock 的 GSDevTools 来轻松调试使用 GSAP 创建的动画。

8. Three.js

地址:https://threejs.org/

Three.js 是一个轻量级库,用于显示复杂的 3D 物体和动画。它利用 WebGL、SVG 和 CSS3D 渲染器来创建引人入胜的三维体验,可在各种浏览器和设备上运行。它是 JavaScript 社区的知名库,在 GitHub 上拥有超过 85k 个星级。

9. ScrollReveal

地址:https://scrollrevealjs.org/

F8520855-05AC-4788-93A2-D2117ED052D1.gif

通过 ScrollReveal 库,您可以轻松地为进入或离开浏览器视口的 DOM 元素制作动画。它提供各种类型的优雅特效,可在多个浏览器中滚动时显示或隐藏元素。ScrollReveal 库也非常易于使用,在 GitHub 上的依赖性为零,拥有超过 2100 个星级用户。

10. Barba.js

地址:https://barba.js.org/

957B1641-7F1C-4C9C-8938-2911C7F3BC9A.gif

让网站出类拔萃的一种创造性方法是,在用户浏览网页时,在网页之间添加生动的过渡效果。这比简单地显示新网页或重新加载浏览器能带来更好的用户体验。
这就是 Barba.js 为何如此有用的原因;该库可让网站像单页面应用程序(SPA)一样运行,从而创建令人愉悦的页面转换。它能减少页面之间的延迟,最大限度地减少浏览器的 HTTP 请求次数。它在 GitHub 上获得了将近 11k颗星。

11. Mo.js

地址:https://barba.js.org/

2DEDCE95-3BEE-4D56-B220-419759DCFB4F.gif

它提供了简单的声明式 API,可轻松创建流畅的动画和特效,在各种屏幕尺寸的设备上都能呈现出完美的效果。您可以移动 HTML 或 SVG DOM 元素,也可以创建一个特殊的 Mo.js 对象,该对象具有一系列独特的功能。它是一个可靠且经过充分测试的库,在 GitHub 上已编写了 1500 多个测试,拥有 1700 多颗星。

12. Typed.js

地址:https://mattboldt.com/demos/typed-js/

4CC9E03C-9503-40D3-8ED1-76423512FF46.gif

它的名字就说明了一切:一个动画打字库。
它能逐个字符键入特定字符串,就像有人在实时键入一样,允许你暂停键入速度,甚至暂停键入特定时间。通过智能退格,它可以键入以与当前字符相同的字符集开始的连续字符串,而不会退格整个前一个字符串--就像我们在上面的演示中看到的那样。
此外,它还支持批量键入,即同时在屏幕上键入一组字符,而不是一个接一个地键入。Typed.js在GitHub上有超过12K颗星,深受Slack和Envato的信任。

转载至网易新闻客户端 @电竞圈每日关注

for 循环


for是最基础的循环,基本上每种编程语言都能见到他的身影,最为常见的使用方法为:

let a=[1,2,3];
for ( let i=0;i<a.length;i++ ) {
   console.log(a[i]);
}
//输出 0 1 2

不少小伙伴可能会看到有的人建议将数组的长度用一个变量缓存起来,以便提高循环效率,例如上述例子改为:

let a=[1,2,3];
let length=a.length;
for ( let i=0;i<length;i++ ) {
   console.log(a[i]);
}
//输出 0 1 2

但这样做其实并不会给你循环带来性能提升(无论循环次数多少),所以除非有其他需求,否则没必要把数组长度单独缓存起来.

对于遍历对象(关联数组),可以如下操作:

let obj={"a":1,"b":2};
let keys=Object.keys(obj)//获取对象的key组成的数组
for ( let i=0;i<keys.length;i++ ) {
  console.log(keys[i],obj[keys[i]]);
}
//输出:
// a 1
// b 2

这里let keys=Object.keys(obj) 与上述的把数组长度缓存起来有所不同,如果放到for循环中的话,Object.keys每次循环都会去计算、生成索引数组,对循环效率产生极大影响.

除使用Object.keys()外,若还有以下方法可选:

  • Object.values(),与Object.keys()类似,但返回的不是索引,而是值
  • Object.getOwnPropertyNames()返回对象自身属性名(包括不可枚举的属性)组成的数组.
  • Object.getOwnPropertySymbols()返回对象自身的Symbol属性组成的数组,不含普通属性
  • Reflect.ownKeys() 返回对象自身所有属性名组成的数组,包括不可枚举的属性和Symbol属性
  • Object.entries() 返回对象自身所有属性键值组成的数组,不含原型.

     let obj={a:1,b:2,c:3}
     console.log(Object.entries(obj))
     输出:
     [ [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] ]
    
方法基本属性原型链不可枚举Symbol
Object.keys()
Object.values()
Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Object.entries()是(k&v)
Reflect.ownKeys()

以上方法都是返回一个数组,然后配合for循环或者其他循环语句进行遍历.

for的优点是非常灵活,可以实现一些特殊循环,其基本结构为for(a;b;c){},其中a、c可以为表达式、语句、函数、值、对象等等都行, 第二个位置需要是一个表达式或者值,如果等于false则停止循环(null、undefined都不等于false哦).其实a、b、c甚至都可以省略(但分号不能省),以下写法在js中是合法的,但因为第二个位置永不等于false,所以会形成一个死循环.

  for(;;;){}

这里主要想阐述for循环非常灵活,但有似乎点跑题了.

let i=0
let flag=true
let f=()=>{
  if(i>10){
    flag=false
  }
  return i++
}
for ([1,2,3];flag;3) {//其中[1,2,3] 和 3 无意义
  console.log(f());
}

另外也可使用while循环进行遍历,但一般不常用于数组或对象上,所以这里就不展开介绍了

for in


for in 是es5加入的,可以用于遍历数组、对象, 需要注意的是,for in会遍历数组所有的可枚举属性,包括原型属性,不包括Symbol.

Object.prototype.title = 'for in';
 let obj={a:1,b:2,c:3}
console.log(obj); //输出 { a: 1, b: 2, c: 3 }
for(let index in obj){
  console.log(index);
}

输出:
a
b
c
title

为避免输出原型属性,可配合hasOwnProperty()方法来进行判断

Object.prototype.title = 'for in';
let obj={a:1,b:2,c:3}
console.log(obj); //输出 { a: 1, b: 2, c: 3 }
for(let index in obj){
  if (obj.hasOwnProperty(index)) {
    console.log(index);
  }
}

输出:
a
b
c

for of 虽然也可以遍历数组,但是一般不推荐,除上面说到的会遍历出原型属性外,还存在两个问题:

  • 遍历数组获取到的key为sting类型,而非number,不注意的话,在使用时可能导致出错.
  • 遍历数组时,存在不按索引顺序遍历的风险

for of


for of 是es6标准,与 for in 相比:
1.遍历出来的是值而非索引.但可以通过遍历arr.keys()的方式获取索引.
2.不会遍历原型属性
3.不支持遍历普通对象,但支持map、set、arguments甚至字符串等存在iterator接口的对象

Array.prototype.title = 'for of';
let arr=[1,2,3] //输出 [1,2,3]
for(let val of arr){
    console.log(val);
}
输出:
1
2
3

Array.forEach


和for of相比,他有一个特点就是可同时遍历出索引和值.
基本用法:

var arr=[1,2,3]
 arr.forEach((val,key)=>{
    console.log(val,key);
    val+=this; //不会改变原数组内容
    //这里的this是forEach的第二个参数1,该参数是可选的,当不填时,默认指向window
},1)
输出:
1 0
2 1
3 2

Array.map


Array.map可以返回遍历的内容,形成新的数组,而Array.forEach没返回值,示例如下:

let arr=[1,2,3]
let newArr=arr.map(function(val,key,_arr){
    //其中参数_arr为arr本身
    return val * this;
},3);
console.log('newArr:',newArr)
console.log('arr:',arr)
输出:
newArr: [ 3, 6, 9 ]
arr: [ 1, 2, 3 ]


Array.filter


Array.filter顾名思义,对数组进行过滤,返回满足条件的元素组成的数组

//取数组中的奇数
let arr = [1,2,3,4,5,6,7,8,9];
let odds = arr.filter(item => item % 2)
console.log(odds);
输出:
[ 1, 3, 5, 7, 9 ]

和foreach、map、filter的相似点:

  • 都不能中途停止遍历.除非程序报错。
  • 不能循环时通过增加数组元素来改变循环次数
  • 但可以减少数组元素来改变循环次数,如使用pop()、shift()
  • 修改回调传入的值不会改变原数组

Array.reduce


Array.reduce是一个累加器,用于累加整个数组的值,当然,你也可以用于拼接数组中的所有字符串,这取决于你回调函数中的处理逻辑.其中第二个参数为初始值,可省略.

let arr = [1,2,3];
let total = arr.reduce((total,item)=> {
   return total + item;
});
console.log(total);
输出:
6

总结:

  • for效率非常高,而且灵活,但代码可能没其他方法简洁
  • 要遍历对象,除for in 外,一般都是先获取对象的属性成为数组,然后再实现遍历
  • for in 不建议用于数组,除非你清楚他的特性

类型系统

众所周知 JS 是一门 弱类型语言,不到执行时都不能确定变量的类型。编码时可以随心所欲反正不报错,一不小心就写出八哥( undefined 警告!)。

1. 静态类型检查

静态类型检查让 TS 在编辑器中披上 强类型语言 的“马甲”,使得开发者在 编码时 就可以 避免大多数类型错误的情况发生,而开发者要做的就 只是声明变量时多写一个符号和一个单词。

当然你也可以在声明变量时 不指定类型 或者使用 any 类型 来达到 JS 的动态类型效果,让 TypeScript 变成 AnyScript ,任性~

let name: string = '陈皮皮';
name = 9527; // 报错

let age: any = 18;
age = 'eighteen'; // 不报错

真正做到 早发现,早解决,早下班

2. 原始类型

TS 在支持 与 JS 基本相同的原始类型 之外,还额外提供了 枚举(Enum)和元组(Tuple) 的支持。

// 枚举
enum Direction {
    Up = 1,
    Down,
    Left,
    Right
}
let direction: Direction = Direction.Up;

// 元组
let x: [string, number];
x = ['hello', 10]; // 不报错
x = [10, 'hello']; // 报错

3. 智能提示

类型系统 配合 声明文件(关于声明文件我们后面再聊)给我们带来了编辑器中 完善的自动补全智能提示,大大增加了开发效率,也再不会因为拼错变量名或函数名而导致运行时的错误。

我知道 JS 加插件也能实现一定程度的智能提示但是语言自带它不香吗 : )

修饰符和静态关键字

泪目,是从 C# 那里几乎原汁原味搬过来的一套修饰符和关键字,主要如以下几个:

1. 访问修饰符(public、private 和 protected)

用来 限定类成员的可访问范围。

没有 internal 和 protect internal

没有访问修饰符的封装莫得灵魂!

class Me {
    public name = '陈皮皮'; // 大家都知道我叫陈皮皮
    private secret = '*******'; // 我的秘密只有我知道
    protected password = '********'; // 我的支付宝密码会告诉我的后人的
}

let me = new Me();
let a = me.name; // 拿到了我的名字
let b = me.secret; // 报错,私有的属性
let c = me.password; // 报错,受保护的属性

class Child extends Me {
    constructor() {
        super();
        this.name = '陈XX';
        this.secret // 报错,无法访问
        this.password = '888888'; // 可以访问
    }
}

2. 静态关键字(static)

用于 定义全局唯一的静态变量和静态函数。

在 Creator 的 JS 脚本中是使用 cc.Class 的 statics 属性来定义静态成员的,使用体验一言难尽…

另外在 ES6 中 JS 已经支持静态函数,在 ES7 中也加入了对静态属性的支持。

class Whatever {
    public static origin: string = 'Whatever';
    public static printOrigin() {
        console.log(this.origin);
        console.log(Whatever.origin);
    };
}

console.log(Whatever.origin); // Whatever
Whatever.printOrigin(); // Whatever

3. 抽象关键字(abstract)

用来定义 抽象类或抽象函数,面向对象编程很重要的一环。

没对象的可以面向工资编程…

abstract class Animal {
    abstract eat(): void; // 不同动物进食的方式不一样
}

let animal = new Animal(); // 报错,法实例化抽象类无

class Dog implements Animal {
    eat() {
        console.log('我吃,汪!');
    }
}

let dog = new Dog();
dog.eat(); // 我吃,汪!

class Cat implements Animal {
    // 报错了,没有实现进食的功能
}

4. 只读关键字(readonly)

用来定义只读的字段,使得字段 只能在创建的时候赋值一次。

class Human {
    name: string;
    readonly id: number;
    constructor(name: string, id: number) {
        this.name = name;
        this.id = id;
    }
}

let human = new Human('陈皮皮', 666666);
human.name = '陈不皮'; // 名字可以改
human.id = 999999; // 报错,身份证号码一旦确定不能更改

接口(Interface)

C# 和 Java 的朋友们让我看到你们的双手好吗
接口用于一系列成员的声明,但不包含实现,接口支持合并(重复声明),也可以继承于另一接口。

下面展示几个常见的用法:

1. 扩展原始类型

// 扩展 String 类型
interface String {

    /**
     * 翻译
     */
    translate(): string;

}

// 实现翻译函数
String.prototype.translate = function () {
    return this; // 不具体写了,直接返回原字符串吧
};

// 使用
let nickname = '陈皮皮'.translate();

2. 定义类型

interface Human {
    name: string; // 普通属性,必须有但是可以改
    readonly id: number; // 只读属性,一旦确定就不能更改
    hair?: number; // 可选属性,挺秃然的
}

let ChenPiPi: Human = {
    name: '陈皮皮',
    id: 123456789,
    hair: 9999999999999
}

3. 类实现接口

interface Vehicle {
    wheel: number;
    engine?: string;
    run(): void;
}

class Car implements Vehicle {
    wheel: 4;
    engine: '帝皇引擎';
    run() {
        console.log('小汽车跑得快!')
    }
}

class Bike implements Vehicle {
    wheel: 2;
    run() {
        console.log('小黄车冲冲冲!')
    }
}

类型别名(Type)

这是一个比较常用的特性,作用如其名。
类型别名 用来 给类型起一个新的名字。

类型别名和接口很相似,类型别名可以作用于原始类型,联合类型,元组以及其它任何你需要手写的类型,接口支持合并而类型别名不可以。

类型别名同样也 支持扩展,并且可以和接口互相扩展。

// 给原始类型起个小名
type UserName = string;
let userName: UserName = '陈皮';

// 还可以是函数
type GetString = () => string;
let getString: GetString = () => {
    return 'i am string';
}
let result = getString();

// 创建一个新的类型
type Name = {
    realname: string;
    nickname: string;
}
let name: Name = {
    realname: '吴彦祖',
    nickname: '陈皮皮'
}
// 再来一个新的类型
type Age = {
    age: number;
}
// 用上面两个类型扩展出新的类型
type User = Name & Age;
let user: User = {
    realname: '吴彦祖',
    nickname: '陈皮皮',
    age: 18,
}

联合类型(Union Types)

使用 联合类型 允许你在 声明变量或接收参数时兼容多种类型。

个人最喜欢的特性之一,点赞!
1. 表示一个值可以是几种类型之一

let bye: string | number;
bye = 886; // 不报错
bye = 'bye'; // 不报错
bye = false; // 报错**

2. 让函数接受不同类型的参数,并在函数内部做不同处理

function padLeft(value: string, padding: string | number) {
    if (typeof padding === 'string') {
        return padding + value;
    } else {
        return Array(padding + 1).join('') + value;
    }
}
padLeft('Hello world', 4); // 返回 '    Hello world'
padLeft('Hello', 'I said: '); // 返回 'I said: Hello'

泛型(Generics)

C# 和 Java 的朋友们再次让我看到你们的双手好吗
使用 泛型 可以让一个 类/函数支持多种类型的数据,使用时可以传入需要的类型。

又是一个非常实用的特性,利用泛型可以 大大增加代码的可重用性,减少重复的工作,点赞!

以下是两个常用的用法:

1. 泛型函数

// 这是一个清洗物品的函数
function wash<T>(item: T): T {
    // 假装有清洗的逻辑...
    return item;
}

class Dish { } // 这是盘子
let dish = new Dish(); // 来个盘子
// 盘子洗完还是盘子
// 用尖括号提前告诉它这是盘子
dish = wash<Dish>(dish);

class Car { } // 这是汽车
let car = new Car(); // 买辆汽车
// 汽车洗完还是汽车
// 没告诉它这是汽车但是它认出来了
car = wash(car);
2. 泛型类

// 盒子
class Box<T>{
    item: T = null;
    put(value: T) {
        this.item = value;
    }
    get() {
        return this.item;
    }
}

let stringBox = new Box<String>(); // 买一个用来装 String 的盒子
stringBox.put('你好!'); // 存一个 '你好!'
// stringBox.put(666); // 报错,只能存 String 类型的东西
let string = stringBox.get(); // 拿出来的是 String 类型

装饰器(Decorator)

这是一个相对比较高级的特性,以 @expression 的形式对类、函数、访问符、属性或参数进行额外的声明。

利用装饰器可以做很多骚操作,感兴趣的话可以深入研究下。
对类做预处理

export function color(color: string) {
    return function (target: Function) {
        target.prototype.color = color;
    }
}

@color('white')
class Cloth {
    color: string;
}
let cloth = new Cloth();
console.log(cloth.color); // white

@color('red')
class Car {
    color: string;
}
let car = new Car();
console.log(car.color); // red
Creator 中的 TS 组件中的 ccclass 和 property 就是两个装饰器

const { ccclass, property } = cc._decorator;

@ccclass
export default class CPP extends cc.Component {

    @property(cc.Node)
    private abc: cc.Node = null;

}

命名空间(namespace)

命名空间用来定义标识符的可用范围,主要用于解决重名的问题,对于项目模块化有很大的帮助。

Cocos Creator 中的 cc 就是一个内置的命名空间
1. 对相同名字的类和函数进行区分

// pp 命名空间
namespace pp {
    export class Action {
        public static speak() {
            cc.log('我是皮皮!');
        }
    }
}

// dd 命名空间
namespace dd {
    export class Action {
        public static speak() {
            cc.log('我是弟弟!');
        }
    }
}

// 使用
pp.Action.speak(); // 我是皮皮!
dd.Action.speak(); // 我是弟弟!

2. 对接口进行分类

namespace Lobby {
    export interface Request {
        event: string,
        other: object
        // ...
    }
}

namespace Game {
    export interface Request {
        event: string,
        status: string
        // ...
    }
}

// 用于 Lobby 的请求函数
function requestLobby(request: Lobby.Request) {
    // ...
}

// 用于 Game 的请求函数
function requestGame(request: Game.Request) {
    // ...
}


转自:https://forum.cocos.org/t/typescript/93014
@陈皮皮