snowFlakeXue

Work hard for what you desire.


  • 首页

  • 关于

  • 分类

  • 归档

  • 搜索

异步处理

发表于 2020-03-01 | 更新于 2020-03-02 | 分类于 javascript学习

同步和异步

​ 同步和异步是一种消息通知机制

​ 同步: A调用B,B处理获得结果,才返回给A。A在这个过程中,一直等待B的处理结果,没有拿到结果之前,需要A(调用者)一直等待和确认调用结果是否返回,拿到结果,然后继续往下执行。

​ 做一件事,没有拿到结果之前,就一直在这等着,一直等到有结果了,再去做下边的事

​ 异步: A调用B,无需等待B的结果,B通过状态,通知等来通知A或回调函数来处理。

​ 做一件事,不用等待事情的结果,然后就去忙别的了,有了结果,再通过状态来告诉我,或者通过回调函数来处理。

ES6 Promise对象

ES6的Promise对象是一个构造函数,用来生成Promise实例。
所谓Promise对象,就是代表了未来某个将要发生的事件(通常是一个异步操作)。
它的好处在于,有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数

哎呀呀呀呀呀呀,乍一看有点难懂,现在通过一个小应用,来讲解一下这个promise咋用把~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// promise的使用
// promise 下有俩个参数 分别是 resolve 和 reject
let p = new Promise((resolve,reject)=>{
// 请求一张图片
let img = new Image();
img.src = 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1564676679229&di=189f903018a2854e74fbac3834f55d4e&imgtype=0&src=http%3A%2F%2Fpic.rmb.bdstatic.com%2Ff54083119edfb83c4cfe9ce2eeebc076.jpeg';

img.onload=function(){
resolve('成功了')//必须传参
}

img.onerror=function(){
reject('失败了')//也可reject(),可以不传参
}
})
// pending 等待状态
// resolve 成功状态
// reject 失败状态 console.log('21:',p);//[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined

//then 是在promise返回结果之后才执行
// then里面可以传递2个函数
// 第一个函数 成功时执行的函数
// 第二个函数 失败时执行的函数
p.then((info)=>{
console.log('图片'+info)
},(msg)=>{//可以()=>{}不传参
console.log('图片'+msg)
})

then的返回值,会返回一个新的 Promise 对象, 但是状态会有几种情况:

  • then 的回调函数中没有返回值,then就会返回一个状态为: resolved 的 promise 对象
  • then 的回调函数返回值是 非 promise 的值, then就会返回一个状态为: resolved 的 promise 对象,另外会把返回值,传递给 下一个 then
  • then 的回调函数返回值是 promise 对象,then 就直接返回这个 promise 对象,具体的状态可以由我们自己定义,具体传递的值,也由我们自己定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let p = new Promise((resolve,reject)=>{
resolve('123')
})

p.then((info)=>{
console.log(info)
// return 123; //后面then会返回成功了123(对应上面的第二条,有return值时)
return new Promise((resolve,reject)=>{
reject();//后面then会返回失败了(对应上面的第三条)
})
}).then((msg)=>{
console.log('成功了',msg)
},()=>{
console.log('失败了')
})

async 函数 和 await

async和await是成对存在的,这么做就是用同步解决异步问题,我想让请求三执行完了请求二执行,请求二执行完了请求一执行,有这么一个次序关系

all和race方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 所有的promise都成功的情况下 才会执行的函数

let p1= new Promise((resolve,reject)=>{
setTimeout(() => {
resolve()
}, 500);
})

let p2= new Promise((resolve,reject)=>{
setTimeout(() => {
reject()
}, 300);
})

let p3= new Promise((resolve,reject)=>{
setTimeout(() => {
resolve()
}, 2000);
})
// Promise.all 只有所有状态都是resolve才会成功
let allP = Promise.all([p1,p2,p3]);

console.log(allP)

allP.then(()=>{
console.log('成功了')
},()=>{
console.log('失败了')
})
// Promise.race 这一个数组中的promise 谁跑的最快 就是谁的结果!
let raceP = Promise.race([p1,p2,p3]);

console.log(raceP)//p2最快,所以是失败了

raceP.then(()=>{
console.log('成功了')
},()=>{
console.log('失败了')
})

ES6

发表于 2020-02-25 | 更新于 2020-02-29 | 分类于 javascript学习

let和const

var:

1.  var可以重复声明
   2.  作用域:全局作用域和函数作用域
   3.  会进行预解析

let:

1.  同一作用域下不可以重复声明
2.  作用域:全局作用域和块作用域{}
3.  不会进行预解析

const:

1. 只能声明一次,且必须直接赋值
   2. 作用域:块级作用域
   3. 不会被预解析
   4. 不能重新赋值

解构赋值

对象的解构赋值

1
2
3
4
5
6
let obj = {
a:1,
b:2
}
let {a,b} = obj;//这里用c,d就不行,必须和对象的属性名一致
console.log(a,b);//1 2

数组的解构赋值

1
2
3
let arr = ["a","b"];
let [c,d] = arr;//名字可不一样,位置对应了就行
console.log(a,b);//a b

怎么快速交换两个值(用到解构赋值)

1
2
3
4
let a=1;
let b=2;
[a,b]=[b,a];
console.log(a,b);//2 1

字符串的解构赋值(没啥用)

1
2
3
let str = "abc";
let [c,d] = str;
console.log(a,b);//a b

展开运算符(…)

扩展:

1
2
let arr1 = [1,2,3,4];
let arr2 = ["a",...arr1,"b,"c];//当使用这种方式插入就会很方便

剩余参数

1
2
3
let arr1 = [1,2,3,4];
let [a,b,...c] = arr1;
console.log(c);//[3,4]

以上用法在对象中依然适用,就不再赘述

解决浅复制问题

如果let arr2=arr1

这样直接赋值的话会造成在我修改arr2时,arr1也变了

但如果我用扩展运算符就可以完美避开这个问题

1
2
3
4
let arr1=[1,2,3,4];
let arr2=[...arr1];
arr2[0]=3;
console.log(arr1[0]);//1

Set

数组去重

1
2
3
4
5
6
7
8
9
10
let arr = [1,2,3,2,1,4,5];
let s = new Set(arr);
console.log(s);//{1,2,3,4,5} 注意这不是数组
console.log(s.size);//5 size属性:个数
s.clear();//清空所有值
s.delete(4);//传入的是要删除的具体值,而不是数组下标 返回true或false是否删除成功【
s.add(6); //添加也包含去重功能,若添加已有元素则添加不成功,返回set本身
s.has(5);//检验是否包含,返回true和false
//将s转为数组
arr = [...s];

Map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let arr = [
["a",1],
["b",2],
["c",3]
];//写成一维数组是不得行的,必须写成这样式的俩值
let m = new Map(arr);
console.log(m);//{"a"=>1,"b"=>2,"c=>3"} Map方法将其改变为键值形式
console.log(m.size);//3 size属性:个数
m.clear();//清空所有值
m.delete("a")//传入的是要删除的key值,而不是数组下标 返回true或false是否删除成功 会将key value都删了
m.get("b");//返回key对应的value
m.set("d",4).set("a",2);//添加也可修改 注意不是add 可迭代
m.has(5);//检验是否包含,返回true和false
//将s转为数组
arr = [...m];

箭头函数

箭头函数:

形参=>返回值

1
2
let fn=num=>num*2;
console.log(fn(2));//4

(形参,形参)=>返回值

1
2
let fn=(num1,num2)=>num1+num2;
console.log(fn(1,2));//3

()=>返回值

1
2
let fn=()=>"返回值";
console.log(fn());//"返回值"

()=>{

执行语句

return 返回值(可选)

}

1
2
3
4
let fn=()=>{
console.log("a");
};
fn();//"a"

(形参)=>{

执行语句

return 返回值(可选)

}

箭头函数不能用不定参(arguments)

但可以用扩展运算符解决(又叫rest参数)

1
2
3
4
let fn = (a,b,...arg)=>{
console.log(arg);
}
fn(1,2,3,4);

箭头函数本身没有this,当调用箭头函数的this时,指向其声明时作用域的this

参数默认值问题

1
2
3
4
let fn = (a=2,b=10)=>{
console.log(a*b);
}
fn();//尽管忘记传参数了,也会得到结果20,不会返回undefined

Array.from()

将类数组转换为数组

先康康啥是类数组,就是由下标,有值但他不是数组

1
2
3
4
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
1
2
3
4
5
let lis=document.querySelectorAll("li");
lis=Array.from(lis);
//当然也可以用展开运算符将类数组转换成数组啦
lis=[...lis];
//接下来lis就可以愉快的使用数组的方法啦,比如forEach啥的

Array.from还有两个可选参数,一个是类似于map方法,另一个就是改变this指向(我觉得没啥用,就不记了)

1
2
3
4
5
let lis=document.querySelectorAll("li");
lis=Array.from(lis,(item,index)=>{
console.log(item,index);
return index;
});

Array.of()

将传入的参数组成一个新数组

1
console.log(Array.of(1,2,3,4,"a"));//[1,2,3,4,"a"]

Array.isArray()

检测传入的是否是数组

arr.find()

返回数组中第一个满足判断条件的值,若没有就返回undefined

参数是一个回调函数

1
2
3
4
5
6
7
8
9
let arr = [1,2,3,4];
let val = arr.find(item=>{//index,arr可选
if(item>3){
return true;
}
});
//简写
let val = arr.find(item=>item>3);
console.log(val);

arr.findIndex()

除了这个返回的是索引值,剩下的和find方法一样

arr.flat(depth)

扁平化多维数组 depth指要提取嵌套数组的结构深度,默认值是1

当然,当你不知道数组有多少层的时候,可以直接传Infinity

返回“拉开的”数组

1
2
3
4
5
6
let arr = [
[1,2],
[1,[3,6,
[4,5]]]
]
console.log(arr.flat(Infinity));//[1,2,3,6,4,5]

arr.flatMap()

在扁平化的同时想要进行一些操作,比如删除某一项时,可以使用此方法,参数是回调函数 but 这个函数只能处理一层,如果层数太多,需要递归

1
2
3
4
5
6
7
8
9
10
11
12
13
let arr = [
["小明",18],
["小刘",19]
]
let newArr = arr.flatMap(item=>{
//使用过滤器方法去掉年龄那一项
item=item.filter((item,index)=>{
//使索引值为0,来做到删除年龄
return index==0;
})
return item;//注意这里一定要写返回值
})
console.log(newArr);//["小明","小刘"]

arr.fill()

填充作用,一般用于操作二进制

1
2
3
let arr = [0,1,2,3,4];
console.log(arr.fill("a",1,4));//[0,"a","a","a",4]
//三个参数,(替换值,起始位置[可选],终止位置(不包含,可选)),且终止值默认值为arr.length 不能使数组变长

arr.includes()

判断数组中是否包含一个指定的值

1
2
let arr = [1,2,3,4,5];
console.log(arr.includes(1,2));//false 两个参数(查找值,从第几位开始查找(可选))

字符串也有includes方法,用法和参数与数组的完全一致

str.startsWith() str.endsWith()

1
2
3
let str = "肥肥肥最厉害";
console.log(str.startsWith("肥肥",2));//false,第二个参数(可选)代表从第几位开始作为头,本例中应该是肥最
console.log(str.endsWith("肥肥肥",3));//true,第二个参数(可选)代表第几位的前一位为尾

str.repeat()

将字符串重复多少次,不能太大数,比如几亿次啊,浏览器会撑不住

1
2
let str = "a";
console.log(str.repeat(3));//"aaa"

模板字符串

插值表达式 ${} (取代字符串拼接中的+””+) , 里面的值只要是表达式即可,可以是函数调用啊,三目运算啊,都可以;首尾用 即可,取代了单双引,且其中可以任意换行而不报错

1
2
3
4
5
6
7
8
9
let name = ()=>{
var a = "小明";//当然实际运用中可能是一些非常复杂的操作
return a;
}
let age = 18;
let str = `
今年${name()}终于${age>15?age:"保密"}了!
`;
console.log(str);//今年小明终于18了

对象的简洁表示法

1
2
3
4
5
6
7
8
9
let a = 0;
let b = 1;
let obj = {
a,//a等于a,打印出来就是a:0,等同于a:a
b,
c(){//当对象中某一属性值是方法时,可以这么简化,取代之前那种还要写function的
console.log("a");
}
}

属性名表达式

1
2
3
4
5
6
7
let name = "小明";
let obj = {
[name]:111//给属性赋上变量名
}
console.log(obj);//"小明":111
//按老办法写
obj[name]=111;

Object.assign()

合并对象,两个参数(源对象,目标对象)

1
2
3
4
5
6
7
8
9
let obj = {
a:1,
b:2
}
let obj1 = {
c:3,
d:4
}
obj1 = Object.assign({},obj,obj1);

当然,我认为使用扩展运算符更方便一些,不需要考虑位置顺序

Object.is()

传两个参数,判断是否完全相等,和===类似,但是又有不同之处,具体如下

1
2
3
4
5
Object.is(NaN,NaN);//true
NaN===NaN;//false
+0===-0;//true
Object.is(+0,-0);//false
Object.is(1,"1");//false 强类型

babel

1
2
3
4
5
<head>
<script src="babel.min.js"></script>
</head>
<script type="text/babel">
</script>

上面只是平时简单的测试,用babel,可以将ES6转化为可兼容的,当然也不是所有ES6新增的他都能转化,使用的还需要小心一点,之前要测试哦;至于应用到项目里的高阶使用方法,以后再说····

动画

发表于 2020-01-15 | 更新于 2020-02-22 | 分类于 javascript学习

transition

元素的样式发生改变,给元素添加一个过渡动画

参数:

- transition-delay 延迟时间,动画延迟多长时间执行(s|ms) 默认值0s 可选

- transition-duration 动画时长,动画用多长时间完成(s|ms) 默认值 0s 必要

- transition-property 要动画的样式 (即css属性,如width等)默认值 all,若分别对不同属性设置不同动画,中间用逗号隔开

eg:transition: 1s width, 1s 2s height;

- transition-timing-function 动画形式

linear 匀速

ease 缓冲(默认值)

ease-in 加速

ease-out 减速

ease-in-out 先加速再减速

贝塞尔曲线运动 cubic-bezier()*

transition 在使用时需要注意一个小问题,我们首先来看看下面这个代码

transition

我们给box加了一个两秒的动画,让他的宽从100变为500,但实际上,他只是在点击按钮式显现并变化但没有动画效果,原因是元素在页面上渲染完之前,transition 是不起效果的,也就是当我点击按钮时,浏览器让box显示出来是需要渲染时间的,虽然很短,但仍长于解析速度,也就是我可能几微秒的时间内就已经解析到动画那一步了,但我还没渲染完,而我们又无法监视浏览器什么时候渲染完,因此可以设置一个稍微长一点时间的计时器来解决这个问题,时间最好不要少于20ms

这下,问题就迎刃而解啦

transitionend

一个监测动画结束的事件

照理来说,应该可以像鼠标移入啊,我用item.ontransitionend就可以触发事件,但好像不行,应该用下面这种形式

其中,注意后面的WebKitTransitionEnd,这是为了兼容一些低版本的,这些大小写很烦,要仔细点。

监听事件

事件监听基本用法 :item.addEventListener(‘事件名(不加on)’,fn);

取消事件监听:item.removeEventListener(‘事件名(不加on)’,fn); 如果要取消不能使用匿名函数*

不用匿名函数什么意思,就是防止后来取消的时候找不到,也就是不能写成

1
2
3
4
5
6
7
8
item.addEventListener('click',function(){

})
function(){
item.removeEventListener('click',function(){

})
}

addEventListener是很常用的一种手段,相比较于用on事件,这种方式更好,因为他不会覆盖,你可以同时为一个元素添加多个点击事件且都会生效,如果用on事件就会被覆盖只有一个生效

那给个正确的例子吧

1
2
3
4
5
6
box.addEventListener("click",fn);
function fn(){
var w = parseInt(getComputedStyle(box)["width"]);
this.style.width = w + 100 + "px";
box.removeEventListener("click",fn);
}

上面这个例子就是如果写了取消,那一次点击后,下一次不会再生效;要是不写取消,宽度就会随着你的点击次数逐渐增加100px

animation

与transition相比,可以精确动画,需要动画帧keyframes

先来看看keyframes的写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<style>
/* 动画帧 */
//move为动画帧名,在后面调用animation时要注明使用哪个动画帧
@keyframes move {
/* 0%{
width: 100px;
height: 100px;
}
动画帧不定义的时候,默认就使用计算后样式(即元素本来的样式)
*/
//某些情况下需要将0%写成与计算后样式不一样的,如下
/* 0% {
width: 0;
height: 0;
} */
25% {
width: 100px;
height: 300px;
}
50% {
width: 300px;
height: 300px;
}
75% {
width: 300px;
height: 100px;
}
/* 100% {
width: 100px;
height: 100px;
}
100% 不定义 默认会回到计算后样式,剩下的与0%哪里一样
*/
100% {
width: 0;
height: 0;
}
}
/*
默认动画执行完毕之后,会回到计算后样式
*/
#box {
width: 100px;
height: 100px;
background: red;
animation: move 2s;
}
</style>

animation的属性

- animation-name 动画帧名称 必需

- animation-duration 动画持续时间 必需

- animation-timing-function 动画形式(参考 transition)

- animation-delay 动画开始前的延迟时间

- animation-iteration-count 动画执行次数 number(具体的数字) | infinite(无限次)

- animation-direction alternate(1,3,5奇数次正常,2,4,6偶数次倒序执行倒序执行) normal顺序执行

-animation-fill-mode:

​ backwards 动画开始前,元素的样式保留在动画帧 0

​ forwards 动画结束后,元素的样式保留在动画帧 100

​ both: backwards + forwards(开始前在0,结束后在100,即不回到计算后样式)

-animation-play-state: paused 暂停, running 播放

低版本兼容需要写成-webkit-animation···

把很多属性写进animation时可没有顺序,但一定是动画持续时间在动画延迟时间前

animation相关事件

1
2
3
4
5
6
7
8
9
10
box.addEventListener("animationstart",function(){
console.log("动画开始");
});
box.addEventListener("animationend",function(){
console.log("动画结束");
});
// animationiteration 动画多次执行时,使用,监听动画又开始
box.addEventListener("animationiteration",function(){
console.log("动画又开始");
});

transform

变换:旋转,斜切,缩放,位移

旋转:rotate() 单位deg

斜切:*skew(x,y)

​ skewX() +:左上角,右下角 -:右上角,左下角 与y轴夹角

​ skewY() +:左上角,右下角 -:右上角,左下角 与x轴夹角

​ 单位:deg

缩放:(倍数)

​ scale(x ,y) 一起缩放

​ scaleX()

​ scaleY()

位移:translate(x,y)

​ translateX()

​ translateY()

​ 单位:px

变换原点:

​ 默认 旋转,缩放,斜切 都是围绕着元素的中心点进行变换

​ transform-origin 变换基点 (旋转,缩放,斜切 围绕着那个点进行)

​ 默认值: center center

​ 0,0点 在元素的左上角

注意,当写多个函数变换时,后写的先计算样式

图

如上面栗子,第一个是先算好缩放到一半再移200,第二个是先移200,再缩,因此第一个比第二个多走100

图

js获取transform

或许你想这样子获取

getComputedStyle(item)["transform"]

but你得到的将是这么个玩应儿

matrix(0.707107, 0.707107, -0.707107, 0.707107, 0, 0)

没错,上面所讲的旋转啊,位移啊,其实都是css为了方便我们使用才弄得,事实上,我们做的都是对就九个数操作,emmmm就是矩阵,等3D的时候就是16位啦哈哈哈哈哈哈哈哈,不过我们只用操作12位就可以了

换句话说,你获取不到transform的哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈

emmmmmm不过你可以通过js对这9个数进行你想要的旋转缩放位移!了解就好,一般用不上哈,线性代数还可以再等等。

那先来看看简单的,就位移吧

首先默认情况下matrix是这样的

1
2
3
4
5
6
7
// matrix(1, 0, 0, 1, 0, 0);
var a = 1;
var b = 0;
var c = 0;
var d = 1;
var e = 0;
var f = 0;

那你要是问我为啥是这样的,我也不知道,记住就好了哈哈哈哈哈,不行就百度一下子

因而我们就用a~f代替一下子这9个数,到时候字符串拼接好用

那就来看看位移的实现吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// x 位移
function translateX(x){
e += x; //对e操作
box.style.transform = 'matrix('+a+', '+b+', '+c+', '+d+', '+e+', '+f+')';
}
// y 位移
function translateY(y){
f += y;//对f操作
box.style.transform = 'matrix('+a+', '+b+', '+c+', '+d+', '+e+', '+f+')';
}
box.onclick = function(){
translateX(10);//调用
translateY(10);//调用
};

是不是很简单哈哈哈哈哈,那再来看看缩放吧,也差不多的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// x 缩放(a,c,e)
function scaleX(x){
a *= x;
c *= x;
e *= x;
box.style.transform = 'matrix('+a+', '+b+', '+c+', '+d+', '+e+', '+f+')';
}
// y 缩放(b,d,f)
function scaleY(y){
b *= y;
d *= y;
f *= y;
box.style.transform = 'matrix('+a+', '+b+', '+c+', '+d+', '+e+', '+f+')';
}
box.onclick = function(){
scaleX(1.2);
scaleY(1.2)
};

emmmm在说旋转之前先来看看一些基础叭

1
2
3
4
Math.tan(rad) 正切函数
//你像这个rad就是烦人之处,他不接受角度,因而我们需要把角度转换成弧度一下子
Math.PI π圆周率
角度转弧度: deg/180*Math.PI

下面来看正题-旋转的实现

1
2
3
4
5
6
7
8
function rotate(deg){
a=Math.cos(deg/180*Math.PI);
b=Math.sin(deg/180*Math.PI);
c=-Math.sin(deg/180*Math.PI);
d=Math.cos(deg/180*Math.PI);
box.style.transform = 'matrix('+a+', '+b+', '+c+', '+d+', '+e+', '+f+')';
}
rotate(30);

再来看看斜切~

1
2
3
4
5
6
7
8
9
10
// x轴倾斜
function skewX(xDeg){
c = Math.tan(xDeg/180*Math.PI);
box.style.transform = 'matrix('+a+', '+b+', '+c+', '+d+', '+e+', '+f+')';
}
// y轴倾斜
function skewY(yDeg){
b = Math.tan(yDeg/180*Math.PI);
box.style.transform = 'matrix('+a+', '+b+', '+c+', '+d+', '+e+', '+f+')';
}

transform 3D

实现3D,必须加上这两个东西

transform-style: preserve-3d; 设置到父元素,使其子元素保留其3D位置

perspective 景深,一般设置到父样式的父元素,设置成想加3D效果的元素的一两倍即可

还有一个需要你灵活设置,那就是transform-origin,就是你看的角度,emmm我觉得应该是位置好一点,相对于2D,3D这里需要多设置一个z轴距离,设置在父元素上

像这样transform-origin: center center -100px;

还有一个属性

​ backface-visibility: hidden; 当元素不面向屏幕时是否可见。 设置在3D变化的元素上即可

以上所总结的是设置在父元素上还是哪上如果忘了,可以去看看3D导航这个demo

下面再来讲讲3D实现方法

transform3D 变换

​ 1. 旋转

​ rorateX() 围绕着 X 轴的旋转 (上下翻转)

​ rorateY() 围绕着 Y 轴的旋转

​ rorateZ() 围绕着 Z 轴的旋转

​ 2. 位移

​ translateZ z轴位移

Tween动画算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
var Tween = {
linear: function (t, b, c, d){ //匀速
return c*t/d + b;
},
easeIn: function(t, b, c, d){ //加速曲线
return c*(t/=d)*t + b;
},
easeOut: function(t, b, c, d){ //减速曲线
return -c *(t/=d)*(t-2) + b;
},
easeBoth: function(t, b, c, d){ //加速减速曲线
if ((t/=d/2) < 1) {
return c/2*t*t + b;
}
return -c/2 * ((--t)*(t-2) - 1) + b;
},
easeInStrong: function(t, b, c, d){ //加加速曲线
return c*(t/=d)*t*t*t + b;
},
easeOutStrong: function(t, b, c, d){ //减减速曲线
return -c * ((t=t/d-1)*t*t*t - 1) + b;
},
easeBothStrong: function(t, b, c, d){ //加加速减减速曲线
if ((t/=d/2) < 1) {
return c/2*t*t*t*t + b;
}
return -c/2 * ((t-=2)*t*t*t - 2) + b;
},
elasticIn: function(t, b, c, d, a, p){ //正弦衰减曲线(弹动渐入)
if (t === 0) {
return b;
}
if ( (t /= d) == 1 ) {
return b+c;
}
if (!p) {
p=d*0.3;
}
if (!a || a < Math.abs(c)) {
a = c;
var s = p/4;
} else {
var s = p/(2*Math.PI) * Math.asin (c/a);
}
return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
},
elasticOut: function(t, b, c, d, a, p){ //*正弦增强曲线(弹动渐出)
if (t === 0) {
return b;
}
if ( (t /= d) == 1 ) {
return b+c;
}
if (!p) {
p=d*0.3;
}
if (!a || a < Math.abs(c)) {
a = c;
var s = p / 4;
} else {
var s = p/(2*Math.PI) * Math.asin (c/a);
}
return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
},
elasticBoth: function(t, b, c, d, a, p){
if (t === 0) {
return b;
}
if ( (t /= d/2) == 2 ) {
return b+c;
}
if (!p) {
p = d*(0.3*1.5);
}
if ( !a || a < Math.abs(c) ) {
a = c;
var s = p/4;
}
else {
var s = p/(2*Math.PI) * Math.asin (c/a);
}
if (t < 1) {
return - 0.5*(a*Math.pow(2,10*(t-=1)) *
Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
}
return a*Math.pow(2,-10*(t-=1)) *
Math.sin( (t*d-s)*(2*Math.PI)/p )*0.5 + c + b;
},
backIn: function(t, b, c, d, s){ //回退加速(回退渐入)
if (typeof s == 'undefined') {
s = 1.70158;
}
return c*(t/=d)*t*((s+1)*t - s) + b;
},
backOut: function(t, b, c, d, s){
if (typeof s == 'undefined') {
s = 1.70158; //回缩的距离
}
return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
},
backBoth: function(t, b, c, d, s){
if (typeof s == 'undefined') {
s = 1.70158;
}
if ((t /= d/2 ) < 1) {
return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
}
return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
},
bounceIn: function(t, b, c, d){ //弹球减振(弹球渐出)
return c - Tween['bounceOut'](d-t, 0, c, d) + b;
},
bounceOut: function(t, b, c, d){//*
if ((t/=d) < (1/2.75)) {
return c*(7.5625*t*t) + b;
} else if (t < (2/2.75)) {
return c*(7.5625*(t-=(1.5/2.75))*t + 0.75) + b;
} else if (t < (2.5/2.75)) {
return c*(7.5625*(t-=(2.25/2.75))*t + 0.9375) + b;
}
return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b;
},
bounceBoth: function(t, b, c, d){
if (t < d/2) {
return Tween['bounceIn'](t*2, 0, c, d) * 0.5 + b;
}
return Tween['bounceOut'](t*2-d, 0, c, d) * 0.5 + c*0.5 + b;
}
};
/*
Tween四个必要参数:
- t: current time(当前时间 - 当前运动次数)
- b: beginning value(初始值)
- c: change in value(变化量)
- d: duration(持续时间 - 运动总次数)
*/
(function(){
var run = document.querySelector("#run");
var stop = document.querySelector("#stop");
var box = document.querySelector("#box");
var x = 0;
var speed = 5;
var timer = 0;
var t = 0; //动画执行到第几次 (动画已经消耗的时间)
var b = 100; // 动画开始前的初始值
var c = 500; // 动画初始值 和 目标点之间的差值
var d = 60; // 动画执行总次数, 动画执行时间
run.onclick = function(){
cancelAnimationFrame(timer);
timer = requestAnimationFrame(move);
function move(){
t++;
var val = Tween["elasticOut"](t,b,c,d);// val 动画执行到第 t 次时,动画应该走到哪个位置
// console.log(val,t);
//box.style.transform = 'translateX('+val+'px)';
box.style.width = val + 'px';
console.log(t);
if(t < d){
timer = requestAnimationFrame(move);
}
}
};
stop.onclick = function(){
cancelAnimationFrame(timer);
};

})();

动画框架的使用

所用框架戳这里

首先我们来看看我们能操作哪些属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
"width",
"height",
"left",
"top",
"right",
"bottom",
"marginBottom",
"marginleft",
"marginRight",
"marginTop",
"paddingLeft",
"paddingRight",
"paddingTop",
"paddingBottom"
"opacity"

"rotate",
"rotateX",
"rotateY",
"rotateZ",
"translateX",
"translateY",
"translateZ",
"scale",
"scaleX",
"scaleY",
"skewX",
"skewY"

注意这里都是数值样式,如果是非数值样式,比如颜色,可以获取但不能用作动画操作

那我们就先来看看咋获取吧

1
2
3
css(box,"height");//获取
css(box,"height",200);//修改
css(box,"background","blue");//修改

但是有一个特别重要的东西就是有关transform的值,也就是上面给出的可操作的部分的下半部分,是只能先设置再获取的

1
2
css(box,"scale",.5);
css(box,"scale");

如果没有上面代码块的第一行,那么久无法获取

下面进入正题,看看框架的具体使用参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// transform 相关的样式,在动画前,一定记得先设置初始值
css(box,"rotate",0);
mTween({
el: box,
attr: {//改变后的样式值
width: 300,
height: 300,
rotate: 360
},
//duration: 100 //默认值 400
duration: {
multiple: .5, /* 根据要动画的样式中,最大的差值计算一个时间 multiple 差值的倍数 */
min: 400, //完成动画的最少时间 毫秒
max: 1000 //完成动画的最大时间 毫秒
},
fx : "backOut" // 动画形式: 参考 Tween
cb: function(){
console.log("动画执行完成");
},
moveing: function(){//注意moveing的写法
console.log("动画执行过程中");
}
//停止动画 mTween.stop(box);
});

定时器

发表于 2020-01-14 | 分类于 javascript学习

设置定时器

setTimeout(function,时间):多长时间后干嘛

setInterval(function,时间):每隔多长时间干嘛

这两个的返回值是定时器编号

清空定时器:

clearTimeout(定时器编号)

clearInterval(定时器编号)

定时器管理:

如果多个定时器同时进行,会乱套,所有有下面两种解决方式

在打开新定时器时把旧定时器关掉:clearInterval(timer)

判断定时器是否执行,如果执行先不打开

1
2
3
4
5
6
7
8
9
if(timer){
return;
}

·····
timer=item.setInterval(()=>{
····
timer=0;
},1000)

demo1

demo2

杂七杂八

发表于 2020-01-14 | 分类于 javascript学习

1.首先给一个例子

图片

​ 是不是很神奇,咋都是5呢,这大概是因为这个var吧,那我们换成let试试

图片

​ 哦吼,看样子是局部全局问题呀,解析的时候先解析全局的,那用var的话,var是全局的,已经解析到5了,你手速不可能跟上解析速度吧,那输出就都是5,而用let就完全不用操心了。

​ 下面的demo里用的都是let,但解决方法是var的 ,那我该怎么解决这个问题,定位到我指定元素呢,用this就ok,在事件函数中,this代表的是触发当前事件的元素。也就是说,在demo中,如果用let,就用nav[i];如果用var,就用this

demo)

2.有的时候我们想让一些块元素没有间隙地并排放着,但总是事与愿违,就像下面这样

图片

但是不慌,解决办法还是有的

首先是笨办法,就是把div写一串,还是不留缝隙那种

<div class="app"></div><div class="app"></div><div class="app"></div><div class="app"></div><div class="app"></div>

还有一个办法就是把父元素的font-size设成0,但是如果子元素对font-size有要求,因为他会继承父元素的0,所以要单独给子元素再设置font-size

采用任一方法,我们来看看效果

图片

吼吼吼,大功告成!(虽然这不是js的事)

3.开关问题:

1
2
3
4
5
6
if(){

}
else{

}

这种形式是不是非常常见,但是作为判断条件的有时可能并不能起作用,比方说src这个属性就不能放在括号里,不能作为条件,这个时候就可以用开关了,实际上就是我们自己定义的一个条件,通过这个条件来控制我们自己的条件

1
2
3
4
5
6
7
8
9
let isTrue=true;
if(true){
···
isTrue=false;
}
else{
···
isTrue=false;
}

4.classList的应用

  • item.classList.add(“class名字”)

    添加class

  • item.classList.remove(“class名字”)

    删除某一class

  • item.classList.contains(“class名字”)

    判断是否含有某class,有则返回true,没有则返回false

  • item.classList.toggle(“class名字”)

    切换,若有这个就删掉,没有这个就加上

5.自定义属性

给元素加一个标准中没有定义的属性就是自定义属性,如

item[i].index=i;

6.JSON是字符串,不是对象

7.任何数%n,结果为0~n-1,如n%5,结果为0,1,2,3,4

8.数据类型划分

按typeof划分:number,string,boolean,function,undefined,symbol,object

按ECMAscript划分:简单类型:number,string,boolean,null,undefined,symbol

​ 复杂类型:object

​ 常见对象类型:Array,object,Element,Elements,Function

因此console.log(typeof(null))的结果是object而不是null

9.NaN不等于任何值,也不等于自身

获取元素

发表于 2020-01-14 | 分类于 javascript学习

JS有三大功能块:行为交互,数据交互,逻辑处理

获取单个元素

  1. getElementById
  2. querySelector

需要注意的是,以下所有获取元素的方法中的document都可替换为parent

获取完元素的用处:

  1. 修改css样式

    首先回顾一下css引入的三种方法

    行间样式:

    1
    <div style="width:100px;height:100px;background-color:red;"></div>

    非行间样式:

    • <style><style>

    • <link href="" rel="stylesheet" type="text/css" />

      无论是哪一种样式,都用一种方式即可修改对应的样式

      image-20200114142847633

      image-20200114143020127

      其中,需要注意两种获取元素的方法的括号里应该写什么,getElementById是写名就行了,不需要 . #

      queryselector如果匹配到了多个元素,只会采用第0个

​ 再来看看一些有意思的

​ 如果我想清空样式怎么做最方便呢(只适用于行间样式)

​ item.style.cssText=” “;

​ 如果只修改某个样式,比方说我原来的样式是宽高各100px,我现在

​ item.style.cssText=”width:300px”

​ 我得样式就会变成宽300,高0,也就是说会覆盖,这个时候,就可以用js超级好用的字符串拼接了

​ item.style.cssText+=”width:300px”

​ 这个时候后面的宽覆盖前面的宽,样式就变成宽300,高100

  1. 获取表单用户输入的内容

    item.value

  2. 获取普通元素(非标单的内容)

    item.innerHtml

    注意当要加的是标签时,要用字符串拼接,否则会覆盖掉原来的标签

    item.innerHtml+=”<><>”

  3. 获取元素的class

    item.className

    这种情况可以用于脱离内联样式,通过写多个class及if语句来改变样式

获取多个元素(类数组)

  • document.getElementsByClassName(“类名”)
  • document.getElementsByTag(“标签名”)
  • document.querySelectorAll(“css selector”)

    上述三种方法获取到的一组元素不能直接操作,都只能通过数组下标访问,即使只有一个能匹配也得用数组下标,因此一般也都用循环

image-20200114150232454

image-20200114150311437

还有!切记是Elements!不是Element!

demo链接

I/O软件层次结构

发表于 2019-11-28 | 分类于 操作系统

注意每一层都是用下一层提供的服务,向上层提供服务

用户层软件

中断处理程序

汇总:

其中只有设备驱动程序和中断处理程序需要和硬件打交道

I/O核心子系统

其中假脱机技术实际上不属于核心子系统,但我们就拿在一起讲

因为要实现的功能与硬件无关,所以就无须设备驱动程序和中断处理程序

I/O调度

就跟磁盘调度差不多,找个合适的调度算法就行

设备保护

假脱机技术

脱机:脱离主机的控制进行输入输出

假脱机技术:用软件方式模拟脱机技术

其中输入井就对应着上面第一个磁带的作用,输出井是第二个;输入进程相当于上图中第一个外围控制机,输出进程相当于第二个;

共享打印机原理分析

设备的分配与回收

I/O控制方式

发表于 2019-11-28 | 分类于 操作系统

程序直接控制方式

中断驱动方式

有了这种方式,CPU和I/O才能并行

DMA方式

如上图所示,我们可以看出,I/O与内存之间就不需要CPU这个媒介了

通道控制方式

总结:

I/O控制器

发表于 2019-11-27 | 更新于 2019-11-28 | 分类于 操作系统

I/O控制器的组成

内存映像I/O vs 寄存器独立编址

I/O设备的概念和分类

发表于 2019-11-27 | 更新于 2019-11-28 | 分类于 操作系统

什么是I/O设备

I/O设备的分类

12…12
Liu Xue

Liu Xue

119 日志
11 分类
RSS
GitHub E-Mail
© 2020 Liu Xue
由 Hexo 强力驱动 v3.8.0
|
主题 – NexT.Pisces v7.1.1
本站总访问量 次 | 有人看过我的博客啦