总结一波, 先这样吧,慢慢再补充,有问题…
react篇传送门
当访问一个对象的属性时,如果在对象的内部不存在,就会通过__proto__一直向上去找,直到null。
PS:
基本数据类型也有__proto__属性,但基本类型的值本质是个密封对象,不能增加、修改、删除属性。
含义:在一个函数内,创建一个内部函数,内部函数存在对外部函数变量的引用就会导致闭包。(也可以换句话说:能访问外部函数作用域中的变量的函数)作用是,使函数可以在定义的作用域外的地方被调用。
function foo() {
var a = 1
function bar() {
a++
console.log(a)
}
return bar
}
const myFoo = foo()
myFoo()
好处:
坏处:容易导致内存泄漏
手写promise
typeof
:返回7种数据类型:number,string,boolean,undefined,symbel,object,functioninstanceof
:用来判断对象和数组 ([ ] instanceof Array)Array.isArray([ ])
判断数组的方法Array.isPrototypeOf([ ])
判断数组constructor
: 指向构造函数,原型链上的方法,所以不能用来判断null和undefinedObject.prototype.toString.call()
- - 相对来说最准确的方式综合:
function gettype(obj) {
var type = typeof obj;
if (type !== 'object') {
return type;
}
//如果不是object类型的数据,直接用typeof就能判断出来
//如果是object类型数据,准确判断类型必须使用Object.prototype.toString.call(obj)的方式才能判断
return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1');
}
var m = new Map(); // 空Map
m.set('Adam', 67); // 添加新的key-value /或修改
m.has('Adam'); // 是否存在key 'Adam': true
m.delete('Adam'); // 删除key 'Adam'
m.get('Adam'); // undefined
var s1 = new Set(); // 空Set
var s = new Set([1, 2, 3, 3, '3']);
s; // Set {1, 2, 3, "3"}
s.add(4);
s; // Set {1, 2, 3, "3", 4}
s.delete(3);
s; // Set {1, 2, "3", 4}
//数组去重 百试不爽
var arr=[...new Set([1,2,1,2,3])]
// [1, 2, 3]
Math.random() : 返回介于 0(包含) ~ 1(不包含) 之间的一个随机数。该函数不是加密安全的随机数生成器。
window.crypto.getRandomValues(typedArray) : 返回非0的正整数,可以获取符合密码学安全性要求的随机值。
typedArray是一个基于整数的 TypedArray,其可以是 Int8Array、Uint8Array、Int16Array、 Uint16Array、 Int32Array 或 Uint32Array。
//生成随机随机数
var arr = new Uint16Array(8);
var crypto = window.crypto || window.webkitCrypto
|| window.mozCrypto || window.oCrypto || window.msCrypto;
window.crypto.getRandomValues(arr);
// 生成UUID
window.crypto.randomUUID();
详情参考:
1.JS 安全随机数 window.crypto及其兼容性
2.深入JS getRandomValues和Math.random方法
瞻仰一下大佬博客:张鑫旭的个人主页
总的来说:
Math.random() 随机数并不是实时生成的,而是直接生成一组随机数(64个),并放在缓存中。当这一组随机数取完之后再重新生成一批,放在缓存中。并且是可以被模拟、计算出来的。
getRandomValues() 方法的底层实现是没有缓存的,并且是实时生成的,因此,性能上是要比 Math.random() 差的
贪心算法以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。
//你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。
//你拥有的饼干数量和尺寸都足以让所有孩子满足。
//所以你应该输出2.
输入: g = [1,2], s = [1,2,3]
输出: 2
var findContentChildren = function(g, s) {
g.sort(asc);
s.sort(asc);
let gp = 0,
sp = 0;
while (sp < s.length && gp < g.length) {
// 发现满足条件的饼干,喂饱一个孩子
if (s[sp] >= g[gp]) {
gp++;
}
// 继续找下一块饼干
sp++;
}
return gp;
function asc(a, b) {
return a - b;
}
};
console.log(findContentChildren([1,2,2,4,6,7,8,8,8,9,9], [1,3,4,4,5,8,9]))//6
具体参考:
- JS贪心算法,含图解
- 五大常用算法——贪心算法详解及经典例子
for...of
语句在可迭代对象包括: Array,Map,Set,String,TypedArray,arguments 对象等等.弥补了弥补了forEach
和for-in
循环的短板forEach()
和map()
forEach()会修改原来的数组,不会返回执行结果。map()方法会得到一个新的数组并返回。
map的执行速度会更快。
filter()
创建一个新数组, 返回符合条件的元素。
reduce()
官方:对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
简单来讲,他的主要作用,就是可以取到上次遍历的返回值。进而做累加等操作
some()
判断数组中是不是,至少有1个元素,通过了被提供的函数。
every()
指数组内的所有元素是否都能通过某个指定函数
Array.from()
:
用于将类似数组的对象和可遍历对象转为真正的数组
Array.of()
:
用于将一组值,转换为数组。
用来弥补数组构造函数Array()
的不足,基本上可以用来替代Array()
或new Array()
copyWithin()
:
将指定位置的成员复制到其他位置,然后返回当前数组,会修改当前数组。
find()
和 findIndex()
find:找出 第一个 符合条件的数组成员
findIndex: 返回 第一个 符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1
fill()
使用给定值,填充一个数组。用于空数组的初始化非常方便。
entries()
,keys()
和 values()
用于遍历数组。它们都返回一个遍历器对象。
keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历
includes()
表示某个数组是否包含给定的值,方法返回一个布尔值。
flat()
,flatMap()
flat:用于将嵌套的数组“拉平”,变成一维的数组。返回一个新数组
flatMap:对原数组的每个成员执行一个函数,然后对返回值组成的数组执行flat()方法,返回一个新数组。
at()
接受一个整数作为参数,返回对应位置的成员,主要是为了解决运算符[]
不支持负索引。
使用方法列举太臃肿,都放在另一篇了;
实例移步:
ES6数组新方法
旧的数组方法:
js数组方法
基本类型:
引用类型:
访问一个引用类型,需要先从栈中获取该对象的指针,然后再通过指针访问堆内存对应的数据。
浅拷贝只拷贝这个对象的指针,原来的对象和拷贝的对象指向的是堆内存中的同一个东西,彼此之间的操作会互相影响。
深拷贝则会在堆内存中重新分配内存,拥有不同的地址,但值是一样的。
详情:
关于深浅拷贝的那些事
String.prototype.trimStart()
/ String.prototype.trimEnd()
头\尾的空格文本去掉Object.fromEntries()
键值对还原成对象结构Array.prototype.flat()
/ Array.prototype.flatMap()
数组展平try...catch
catch的参数改为可选JSON.stringify()
加强格式转化JSON.parse()
添加了对行分隔符(\u2028) 和段落分隔符(\u2029)的支持先查找缓存,有缓存直接返回资源给浏览器进程,网络请求结束
没有缓存文件或者缓存过期,则会 真正进入网络请求流程:
(1)定时器都是异步操作
(2)事件绑定都是异步操作
(3)promise
(4)回调函数可以理解为异步
(5)async await
(6)$nextTick
@click.stop : 阻止事件冒泡
@click.prevent : 阻止事件默认行为
名称 | 大小 | 网络请求 | 生命周期 |
---|---|---|---|
cookie | 4kb左右 | 每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题 | 默认是关闭浏览器后失效, 但是也可以设置过期时间 |
localstorage | 5M | 仅在浏览器中保存,不参与和服务器的通信 | 除非手动被清除,否则永久保存,可以跨页面通信 |
SessionStorage | 5M | 仅在浏览器中保存,不参与和服务器的通信 | 仅在当前会话(窗口)下有效,关闭窗口或浏览器后被清除。并且重新加载或恢复页面仍会保持原来的页面会话;不可以跨页面通信 |
首先需要明白webpack proxy跨域只能用作与开发阶段,临时解决本地请求服务器产生的跨域问题。并不适合线上环境。配置在webpack的devServer属性中。webpack中的devsever配置后,打包阶段在本地临时生成了一个node服务器,浏览器请求服务器相当于请求本地服务。
es6继承
class People{
constructor(name='wang',age='27'){
this.name = name;
this.age = age;
}
eat(){
console.log(`${this.name} ${this.age} eat food`)
}
}
//继承父类
class Woman extends People{
constructor(name = 'ren',age = '27'){
//继承父类属性
super(name, age);
}
eat(){
//继承父类方法
super.eat()
}
}
let wonmanObj=new Woman('xiaoxiami');
wonmanObj.eat();
原型链继承(父类的实例作为子类的原型)
function Woman(){
}
Woman.prototype= new People();
Woman.prototype.name = 'haixia';
let womanObj = new Woman();
优点:简单易于实现,父类的新增的实例与属性子类都能访问
缺点:1.如果要新增加原型属性和方法需要在new 父类构造函数的后面;2.无法实现多继承;3.创建子类实例时,不能向父类构造函数中传参数
构造函数继承(复制父类的实例属性给子类)
function Woman(name){
//继承了People
People.call(this); //People.call(this,'wangxiaoxia');
this.name = name || 'renbo'
}
let womanObj = new Woman();
优点:1.解决了子类构造函数向父类构造函数中传递参数;2.可以实现多继承(call或者apply多个父类)
缺点:1.方法都在构造函数中定义,无法复用;2.不能继承原型属性/方法,只能继承父类的实例属性和方法
原型继承
function Wonman(name){
let instance = new People();
instance.name = name || 'wangxiaoxia';
return instance;
}
let wonmanObj = new Wonman();
优点:1.不限制调用方式、2. 简单,易实现
缺点:不能多次继承
组合继承
寄生继承
寄生组合继承
element.addEventListener(event, function, useCapture)
第三个参数:true - 捕获阶段执行fn; false- 默认。事件句柄在冒泡阶段执行event.stopPropagation( )
、 event.target==event.currentTarget
event.preventDefault( )
return false
不仅阻止了事件往上冒泡,而且阻止了事件本身(默认事件)PS:箭头函数中没有this绑定,必须通过查找作用域链来决定其值。 如果箭头函数被非箭头函数包含,则this绑定的是最近一层非箭头函数的this,否则this的值则被设置为全局对象
async
属性的执行是在脚本下载完之后,在 window 的 load 事件发生之前。如果这个时候文档还没有解析完全意味着它们可以阻止 DOM 构建。defer
属性的执行是在文档完全解析完成后进行的,在 window 的 DOMContentLoaded 事件之前。defer 属性就可以保证它们执行是按照它们出现在 HTML 中的顺序来的,并且不会阻止主线程的渲染。To:前端常见知识点三之HTML
transform:translate(-50%,-50%);
懒得写了
有点多,看链接吧:grid布局
主要属性:
.container {
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;
//简化 重复
grid-template-columns: repeat(3, 33.33%);
grid-template-rows: repeat(3, 33.33%);
//重复某种模式
grid-template-columns: repeat(2, 100px 20px 80px);
//自动填充 (按照父级的宽度)
grid-template-columns: repeat(auto-fill, 100px);
// 只有当容器足够宽,可以在一行容纳所有单元格,并且单元格宽度不固定的时候。fit和fill会有差异
// fit是自适应 fill是自动填充
// fr ==> 指剩余空间、比例 (同flex)
// minmax() 长度范围
grid-template-columns: repeat(auto-fill, minmax(214px, 1fr));
grid-template-columns: repeat(auto-fit, minmax(214px, 1fr));
// 指定网格线名称
grid-template-columns: [c1] 100px [c2] 100px [c3] auto [c4];
grid-template-rows: [r1] 100px [r2] 100px [r3] auto [r4];
// 间隔
grid-gap: ;
// 排列顺序
grid-auto-flow: column;
grid-auto-flow: row;
// 不留空隙优先顺序
grid-auto-flow: column dense;
grid-auto-flow: row dense;
//单元格内的对齐方式
justify-items: start | end | center | stretch(拉伸);
align-items: start | end | center | stretch;
place-items: ;
// 整个grid盒子对齐方式
justify-content: start | end | center | stretch | space-around | space-between | space-evenly;
align-content: start | end | center | stretch | space-around | space-between | space-evenly;
place-content:
//指定网格线(索引、名字)
grid-column-start:左边框所在的垂直网格线
grid-column-end:右边框所在的垂直网格线
grid-row-start:上边框所在的水平网格线
grid-row-end:下边框所在的水平网格线
grid-column: 1 / 3;
grid-row: 1 / 2;
// 区域
grid-template-areas: 'a b c'
'd e f'
'g h i';
.item-1 {
grid-area: e;
}
// 只作用于单个项目
justify-self: start | end | center | stretch;
align-self: start | end | center | stretch;
place-self: ;
}
overflow:hidden;
text-overfollw:ellipesis;
white-spce:nowrap
// += 超出两行隐藏:
display:-webkit-box; //将对象作为弹性伸缩盒子模型显示
-webkit-box-orient:vertical; //设置盒子子元素排列方式
-webkit-line-clamp:2; //显示的行数
tr:nth-child(2n+1)
表示HTML表格中的奇数行。
tr:nth-child(odd)
表示HTML表格中的奇数行。
tr:nth-child(2n)
表示HTML表格中的偶数行。
tr:nth-child(even)
表示HTML表格中的偶数行
li:first-child
列表中的第一个li
:first-line
选择文本的第一行
:first-letter
选择这一行的第一字
:link
未访问的超链接
:checked
选中的复选框
:lang()
通过指定的lang值显示样式
详细的,看这里吧:Less语言特性
块级格式化上下文,这是一个独立的渲染区域,规定了内部如何布局、并且这个区域的子元素不会影响到外面的元素。多用于清楚浮动,解决高度塌陷、父子margin重叠等问题(不会吧不会吧,现在还有人用浮动。而且用了还不清除浮动 ?骂骂咧咧10086次)
//清除浮动
.clearfix:after{
content:""; /*内容为空*/
height:0; /*高度为0*/
line-height:0; /*行高为0*/
display:block; /*块级元素*/
visibility:hidden; /*隐藏*/
clear:both; /*清除浮动*/
}
.clearfix{
zoom:1; /*兼容IE678*/
}
触发BFC:
高度塌陷: 父元素不写高度时,子元素写了浮动后,父元素会发生高度塌陷
style(1000) => ID(100) => Class/伪类/属性选择器(10) => 标签(1) => ‘*’、‘>’、‘+’ (0)
父级overflow:hidden
margin-bottom:-300px;
padding-bottom:+300px;
设为 Flex 布局以后,子元素的float、clear和vertical-align属性将失效。
height: 1px;
transform: scale(0.5);
div {
width: 0;
height: 0;
border-width: 10px;
border-style: solid;
border-color: transparent #0099CC transparent transparent;
transform: rotate(90deg); /*顺时针旋转90°*/
}
touchstart
:按下; touchend
: 抬起; touchmove
: 移动 <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
(1)处理 HTML 标记并构建 DOM 树。
(2)处理 CSS 标记并构建 CSS规则树,根据执行顺序解析js文件。
(3)将 DOM 与 CSSOM 合并成一个渲染树。
(4)根据渲染树来布局,以计算每个节点的几何信息。
(5)将各个节点绘制到屏幕上。
To:前端常见知识点三之浏览器
当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流
。
会导致回流的操作:
查询某些属性或调用某些方法:
clientWidth、clientHeight、clientTop、clientLeft
offsetWidth、offsetHeight、offsetTop、offsetLeft
scrollWidth、scrollHeight、scrollTop、scrollLeft
scrollIntoView()、scrollIntoViewIfNeeded()
getComputedStyle()
getBoundingClientRect()
scrollTo()
当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘
。
将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。
+
原理就是微任务
问题:
当vue的data里边声明或者已经赋值过的对象或者数组(数组里边的值是对象)时,向对象中添加新的属性,或更新此属性的值,是不会更新视图的。
简言之:下面单个修改属性this.items[0] = {…}是不会更新视图的,除非直接更新this.items = [{…}]
data() {
return {
items: [
{ message: "one", id: "1" },
{ message: "two", id: "2" },
{ message: "three", id: "3" },
],
};
},
mounted() {
//此时对象的值更改了,但是视图没有更新
this.items[0] = { message: "测试", id: "1" };
// 您还可以使用 vm.$set实例方法,这也是全局 Vue.set方法的别名
this.$set(this.items, 0, { message: "测试", id: "4" }); //$set可以触发更新视图
// 调用方法:this.$set或Vue.set( target, key, value )
// target:要更改的数据源(可以是对象或者数组)
// key:要更改的具体数据
// value :重新赋的值
// this.$set或Vue.set 这两个是同一个东西,唯一的区别就是一个是通过原型访问,一个是通过vue实例
},
原因:
由于 JavaScript 的限制,Vue 不能检测数组和对象 property 的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的。
自己说原因:
object.defineProperty
劫持数据存在的问题:1.不能监听数组索引和长度的变更;2.无法监听 属性的添加和删除;3. 必须遍历对象的每个属性。更详细的解释请看官方文档:深入响应式原理
还不明白,看下面这个Vue数据双向绑定
2.0
:
Vue实现数据双向绑定主要利用的就是: 数据劫持和发布订阅模式。
data()
中对象所有的属性,并使用 Object.defineProperty
把这些属性
全部转为 getter/setter
。watcher
)实例。在属性
被修改时会触发时setter
,setter`会通知观察者,从而使它关联的组件重新渲染。总的来说就是: 用数据劫持(Object.defineProperty
)实现监听数据变化,用发布订阅的模式,实现一个数据变化通知多个视图更新。
简单的setter和getter:
let leo = {}, age = 18;
Object.defineProperty(leo, 'age', {
get(){
// to do something
console.log('监听到请求数据');
return age;
},
set(newAge){
// to do something
console.log('监听到修改数据');
age = newAge > age ? age : newAge
}
})
leo.age = 20; // 监听到修改数据
console.log(leo.age); // 监听到请求数据 // 18
leo.age = 10; // 监听到修改数据
console.log(leo.age); // 监听到请求数据 // 10
探索 Vue.js 响应式原理、Vue数据双向绑定原理和实现 - - 这俩可以瞄一眼
3.0
:
使用Proxy代替defineProperty
Vue3使用代理模式(Proxy)实现数据劫持,Object.defineProperty只能监听属性,而Proxy能监听整个对象,通过调用new Proxy()
,可以创建一个代理用来替代另一个对象被称为目标,这个代理对目标对象进行了虚拟,因此该代理与该目标对象表面上可以被当作同一个对象来对待。代理允许拦截在目标对象上的底层操作,而这原本是Js引擎的内部能力,拦截行为使用了一个能够响应特定操作的函数,即通过Proxy去对一个对象进行代理之后,我们将得到一个和被代理对象几乎完全一样的对象,并且可以从底层实现对这个对象进行完全的监控。Proxy对象是ES6引入的新特性,Vue3放弃使用了Object.defineProperty,而选择了使用更快的原生Proxy,即是在兼容性方面更偏向于现代浏览器。
说了这么多proxy的优势在于:1.Proxy可以直接监听对象而非属性、2.Proxy可以直接监听数组的变化。解决了之前所说的defineProperty存在的问题。
proxy:
var target = {a: 1};
var proxy = new Proxy(target, {
set: function(target, key, value, receiver){
console.log("watch");
return Reflect.set(target, key, value, receiver);
},
get: function(target, key, receiver){
return target[key];
}
});
proxy.a = 11; // watch
console.log(target); // { a: 11 }
=> beforeCreate
setup()
开始监控Data对象数据变化、开始初始化事件
=> created
setup()
实例已经创建完成,完成了data 数据的初始化,el没有,可以初始化data数据
beforeMount
=> onBeforeMount
开始执行挂载钩子,编译模板,把data里面的数据和template生成html,完成了el和data 初始化,生成了虚拟dom,并转换为真实Dom,但还没有更新到页面上。
mounted => onMounted
挂载完成,template渲染到了html,一般可以做一些ajax操作
beforeUpdate
=> onBeforeUpdate
实时监控数据变化
updated
=> onUpdated
随时更新DOM
beforeDestroy
=> onBeforeUnmount
destroyed
=> onUnmounted
errorCaptured => onErrorCaptured
renderTracked => onRenderTracked
renderTriggered => onRenderTriggered
activated => onActivated
deactivated => onDeactivated
(err: Error, instance: Component, info: string) => ?boolean
(e: DebuggerEvent) => void
跟踪虚拟 DOM 重新渲染时调用 。renderTracked({ key, target, type })(e: DebuggerEvent) => void
当虚拟 DOM 重新渲染被触发时调用。和 renderTracked 类似,接收 debugger event 作为参数。此事件告诉你是什么操作触发了重新渲染,以及该操作的目标对象和键。diff算法的基础是Virtual DOM,Virtual DOM是一棵以JavaScript对象作为基础的树,每一个节点称为VNode,用对象属性来描述节点,实际上它是一层对真实DOM的抽象,最终可以通过渲染操作使这棵树映射到真实环境上,简单来说Virtual DOM就是一个Js对象,用以描述整个文档。
Vue2框架通过深度递归遍历新旧两个虚拟DOM树,并比较每个节点上的每个属性,来确定实际DOM的哪些部分需要更新,由于现代JavaScript引擎执行的高级优化,这种有点暴力的算法通常非常快速,但是DOM的更新仍然涉及许多不必要的CPU工作。
在这里引用尤大的描述,为了实现这一点,编译器和运行时需要协同工作:编译器分析模板并生成带有优化提示的代码,而运行时尽可能获取提示并采用快速路径,vue3.0这里有三个主要的优化:
有两种方式:组合式API、选项式API
3.0更推荐组合式API,2.0是选项式API
数据驱动和组件化
(1)@keyup.delete、
(2).lazy 将model的更新方式从input改变为change
(3).number 将用户输入的值转换为数字类型
(4).trim 自动过滤用户输入的首尾空白字符
(5)@click.once : 事件只触发一次
每次更新时不会直接更新到真实的DOM上,而是通过diff方法比较每次的差异,然后将更新的内容暂存在本地的一个虚拟DOM上,等待更新完成后,再一次性将虚拟DOM映射到真实DOM上
key的作用主要是为了高效的更新虚拟DOM。
当data选项是一个函数的时候,这样各个实例中的data有了自己的作用域,互不干扰。
// bus.js
import Vue from 'vue';
export default new Vue();
(1)路由传值:
this.$router.push({
name: 'routePage' ,
query/ params : {
routeParams: params
})
用params传值,页面刷新时,参数会消失,用query则不会,但参数会显示在地址栏中。
(2)vuex
<component is="one"></component>
components:{
one: {template:'我是线路一'},
two: {template: '我是线路二'},
thr: {template: '我是线路三'}
}
(1)name版
出现的过程: name-enter(初始态) => name-enter-active(中间态) => name-enter-to(终止态)
消失的过程: name-leave => name-leave-active => name-leave-to
<transition name="slide-fade">
<p v-if="show"> hello world </p>
</transition>
/* 可以设置不同的进入和离开动画 */
/* 设置持续时间和动画函数 */
.slide-fade-enter-active {
transition: all .3s ease;
}
.slide-fade-leave-active {
transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to
transform: translateX(10px);
opacity: 0;
}
(2)钩子实现过渡动画
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
@enter-cancelled="enterCancelled"
@before-leave="beforeLeave"
@leave="leave"
@after-leave="afterLeave"
@leave-cancelled="leaveCancelled"
>
<!-- ... -->
</transition>
缓存
会在mouted后面增加两个周期:activiated、deactivated
直接用keep-alive标签包裹,或者在router文件中配置keepAlive属性
(1)watch,用于监听数据变化,可以监听:props、data、computed内的数据;watch提供两个参数(newValue,oldValue),第一个参数是新值,第二个参数保存旧值;
(2)computed是计算属性,用于处理复杂的逻辑运算,有缓存机制,只有数据改变时才会触发,性能更佳;
beforeCrete => created => beforeMount
=>子组件:(beforeCrete => created => beforeMount=> mounted)
=>子组件:(beforeCrete => created => beforeMount=> mounted)
=> mouned
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus()
}
}
}
钩子函数:
bind
:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。inserted
:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。update
:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新componentUpdated
:指令所在组件的 VNode 及其子 VNode 全部更新后调用。unbind
:只调用一次,指令与元素解绑时调用。参数:
在watch函数中添加和监听对象同名的对象
dataName:{
handler(newVal, oldVal){
console.log(newVal)
},
deep:true
}
slot
本质上是返回VNode
的函数,一般情况下,Vue中的组件要渲染到页面上需要经过template
-> render function
-> VNode
-> DOM
过程
1.默认插槽
//父组件
<Child>
<div>默认插槽div>
Child>
// 子组件
<template>
<slot>
<p>插槽后备的内容p>
slot>
template>
2.具名插槽
//父组件
<child>
<template v-slot:default>默认插槽内容template>
<template v-slot:content>具名插槽template>
child>
//子组件
<template>
<slot>默认插槽内容slot>
<slot name="content">具名插槽slot>
template>
const routes = [
{
path: "/testId/:id",
name: "testId",
component: Home,
}
]
// 访问:
this.$route.params.id
// 调用:
this.$router.push("/testId/555");
this.$router.push(
{
name: "testId",
params: { id: 888 },
query: { data: "dataVal" },
}
);
用watch 检测
watch: { // watch的第二种写法
$route: {
handler (to, from){
console.log(to)
console.log(from)
},
deep: true
}
},
用params传值,页面刷新时,参数会消失,用query则不会,但参数会显示在地址栏中
path、name、component
(1)vue异步组件:
component: resolve => require(['@/components/home'],resolve)
(2)路由懒加载:
const Home = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/home')
(3)webpack的require.ensure(): (r就是resolve)
component: r => require.ensure([], () => r(require('@/components/home')), 'demo')
{
path:'double',
components: {
default:resolve=>require([’…/components/Vue06-a.vue’],resolve),
bottom:resolve=>require([’…/components/Vue06-b.vue’],resolve)
}
}
< router-view class = "view one" > </ router-view >
< router-view class = "view two" name = "a" > </ router-view >
想实现多个router-view就要使用components,并在里面配置router-view的name属性对应的组件。
default是默认路由,就是不设置路由的router-view都会显示default指向的组件。
children属性:
routes: [
{
path: "/user/:id" ,
component: User,
children: [
{ path : "/user/foo/:key" , component : Foo },
{ path : "/user/bar/:key" , component : Bar }
]
}
]
(1) router-link
(2) this.$router.push() (函数里面调用)
(3) this.$router.replace() (用法同push)
(4) this.$router.go(n)
hash —— 即地址栏 URL 中的 # 符号(此 hash 不是密码学里的散列运算)。hash模式背后的原理是onhashchange
事件,可以在window对象上监听这个事件。
window.onhashchange = function(event){
console.log(event.oldURL, event.newURL);
let hash = location.hash.slice(1);
document.body.style.color = hash;
}
history —— 利用了 HTML5 History Interface 中新增的 pushState()
和 replaceState()
方法。(需要特定浏览器支持)这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。
因此可以说,hash 模式和 history 模式都属于浏览器自身的特性,Vue-Router 只是利用了这两个特性(通过调用浏览器提供的接口)来实现前端路由。
两者的区别:
(1)state :存储数据比如一些变量和对象 ,使用语法:this.$store.state
(2)getters :可以认为是计算属性
(3)mutations: 用来更新state里面的数据
(4)actions :提交mutations而不是直接变更状态,actions可以包含任意异步操作
(5)modules : 可以把某个模块都能分割成具有state,actions ,mutations,actions的作用
(1)Axios 是一个基于 promise 的 HTTP 库。
(2)对Ajax的再封装,基于promise,链式调用
(3)可以拦截请求和响应
(4)自动转换 JSON 数据
(5)Axios的post请求参数默认不是fromdata格式需要用qs转换格式
(6)客户端支持防御 XSRF(跨站请求)
(7)axios体积小 只需在要使用的目录下 npm install axios --save
(8)ajax 需要导入jQuery【体积较大 只是为了ajax去引入是不值得的】
1)get传参方式是通过地址栏URL传递,是可以直接看到get传递的参数,post传参方式参数URL不可见,
2)get传递数据受到URL大小的限制,URL最大长度是2048个字符。post没有长度限制
3)get请求可以被缓存,post不可以被缓存
4)get请求的记录会留在历史记录中,post请求不会留在历史记录
主要利用axios的cancelToken属性。
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.post('/user/12345', {
name: 'new name'
}, {
cancelToken: source.token
})
source.cancel('Operation canceled by the user.');
let cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
cancel = c;
})
});
cancel();
ajax里也有:xmlHttpRequest的abort()
interceptors.request.use
interceptors.response.use
简单来说就是:不想用的功能可以先不用,不要求一次性接受并使用它的全部功能。
辨别一个 Web 应用是否是 PWA 有一些关键原则。一个 PWA 应该具有以下特点:
(1)vue使用的是template模版编写。react使用的是jsx语法。
(2)数据流不同:vue可以进行组件与dom之间v-modle双向绑定。react从始至终都只有单向数据流
(3)Vue 似乎是三个框架中最轻量的,也是最简单易用的
(4)vue、react更加灵活、他们的库可以和各种包搭配;Angular 是一个 “完整的解决方案” - 功能齐全,你可以愉快的开始开发。你不需要研究库,路由解决方案或类似的东西。
mvc和mvvm其实区别并不大。都是一种设计思想。主要就是mvc中Controller演变成mvvm中的viewModel。mvvm主要解决了mvc中大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。和当 Model 频繁发生变化,开发者需要主动更新到View的问题。
Vue.js是一套构建用户界面的渐进式框架(官方说明)。通俗点来说,Vue.js是一个轻量级的,易上手易开箱即用,便捷,灵活性强的前端MVVM框架。简洁的API,良好健全的中文文档,使开发者能够较容易的上手Vue框架
就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。
打包压缩、gizp压缩、精灵图、图片懒加载、图片压缩、避免重定向、缓存页面、路由懒加载
防抖:在第一次触发事件时,不立即执行函数,而是给出一个期限值比如200ms。(比如滚动监听,一直按方向键就一直会触发)
节流:即使用户不断拖动滚动条,也能在某个时间间隔之后给出反馈。
让函数执行一次后,在某个时间段内暂时失效,过了这段时间后再重新激活
// 防抖
function debounce(fnc, delay=3000) {
var timer = null; // 创建一个用来存放定时器的变量
return function () {
clearTimeout(timer); //只要触发就清除
timer = setTimeout(() => {
fnc.apply(this, arguments);
}, delay);
};
}
//节流
function throttled2(fn, delay = 500) {
let timer = null
return function (...args) {
if (!timer) { return false }
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, delay);
}
}
思路就是:从服务端一次性取到一个长列表,通过计算渲染对应索引的数据。设置一个固定高度的滚动区域,滚动的高度/每个列表的高度 = 起始的索引,起始索引+区域内渲染条数 = 尾部的索引。
expires
和 cache-control
来判断是否命中强缓存,如果命中则直接从缓存中获取资源。Etag
或者 Last-Modified
来判断是资源内容是否命中缓存。命中协商缓存返回304,接从缓存获取资源。etag
和 If-None-Math
的版本号是否一致,或者对比Last-Modified
和If-Modified-Since
的日期,判断是否过期)强缓存相关字段有expires,cache-control后者优先级更高
expires
:GMT 格式的时间点字符串,代表资源失效的时间;
cache-control
:一般用该字段的 max-age 值来进行判断,它是一个相对时间,代表资源有效期;
协商缓存相关字段:Last-Modified/If-Modified-Since,Etag/If-none-Match
Last-Modified/If-Modified-Since
:时间字符串,标记文件最后修改的时间,在服务器上根据文件的最后修改时间判断资源是否有变化。
Etag/If-none-Match
:唯一标识串,服务器通过比较标识是否一致来判定文件内容是否被改变。
轻松理解 HTTP 缓存策略
前端常见知识点一之HTTP
var ws = new WebSocket("wss://echo.websocket.org");
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
ws.onmessage = function(evt) {
console.log( "Received Message: " + evt.data);
ws.close();
};
ws.onclose = function(evt) {
console.log("Connection closed.");
};
滴:前端常见知识点四之webscoket
监听VisibilityChange事件,当页面不可见的时候就会documnet.visibilitystate==”hide”
引入express、新建express对象、配置跨域、app.get(post)定义接口、server.listen起服务
req.query:获取URL的查询参数串
req.body: 获取请求主体(post数据,需要设置中间件函数 json与urlencode)
req.cookies:获取Cookies (需要使用 cookie-parser 中间件)
req.hostname / req.ip:获取主机名和IP地址
req.params:获取路由的parameters
req.path:获取请求路径
req.protocol:获取协议类型
req.get():获取指定的HTTP请求头
res.header():设置请求头
res.status():设置HTTP状态码
res.send():传送HTTP响应
res.redirect():设置响应的Location HTTP头,并且设置状态码302
res.json():传送JSON响应
res.cookie(name,value [,option]):设置Cookie
res.clearCookie():清除Cookie
res.download():传送指定路径的文件
res.sendFile(path [,options] [,fn]):传送指定路径的文件 -会自动根据文件extension设定Content-Type
res.render(view [, locals] [, callback]) 渲染一个view
安装、引入MySQL;
·配置mysql(服务器地址,数据库,密码等);
·使用连接池,避开太多线程,提升性能;
·pool.getConnection()连接数据库
@loadstart="onloadstart" //开始加载
@loadedmetadata="onLoadedmetadata"
@play="onPlay" //开始
@pause="onPause"
@waiting="onWaiting" //开始等待
@playing="onplaying" //缓冲下一帧就绪
@loadeddata="onloadeddata" //没有足够的数据来播放指定音频
@timeupdate="onTimeupdate" //更新视频流
@error="onerror"
this.audio.currentTime //当前播放时间
this.audio.maxTime //音频时长
this.audio.volume //音量
分为对称和非对称加密
(1)对称加密。 客户端和服务端公用一个密钥对消息加解密。(客户端和服务端约定好一个加密钥匙。客户端在发消息浅用该密匙对消息加密,发送给服务器,服务器在用该密匙进行解密拿到消息)
(2)非对称加密。客户端和服务端都有公钥和私钥。公钥加密的内容只有对应的私钥解密。私钥自己留着,公钥发给对方。这样发送消息之前,对方的公钥对消息进行加密,受到后在用自己的私钥进行解密。