观察者模式
特点
- 发布&&订阅
- 一对N(一对一,一对多)
实现
- UML类图
- Subject类内部保存了一个其订阅者的列表同时还有当前状态:可以通过setState方法改变内部的状态,在状态发生变更的同时执行notifyAllObservers方法,遍历取出每个订阅者,执行update方法.Subject类暴露一个attach方法给Observer类来允许其进行订阅
let test = {
_name: "tom",
age: 12,
};
Object.defineProperty(test, "name", {
set: function (newName) {
note(this._name, newName);
this._name = newName;
},
get: function () {
return this._name;
},
});
function note(a, b) {
console.log(`从${a}变成了${b}`);
}
test.name = "jak";
let a = test.name;
test.name = "lj";
let b = test.name;
console.log(a);
console.log(b);
- 使用场景
1、jquery callback
2、promise
3、node.js自定义事件(stream,http请求处理,多进程通讯)
4、vue中的wacher
5、vue和react中的生命周期钩子函数
1、 jquery callback(部分源码)
可加如下参数:
once: 确保这个回调列表只执行 .fire() 一次
memory: 保持以前的值,将添加到这个列表的后面的最新的值立即执行调用任何回调
unique: 确保一次只能添加一个回调(所以在列表中没有重复的回调)
stopOnFalse: 当一个回调返回false 时中断调用
jQuery.Callbacks = function(options){
// 先对参数进行处理,比如 once、unique 等
options = createOptions(options);
// 参数定义,包括一些 flag 和 callbacks 数组
var list = [], queue = [] ...
// fire 是遍历数组,回掉函数的执行
var fire = function(){
...
}
// self 是最终返回的对象
var self = {
add: function(){...},
remove: function(){...},
has: function(){...},
disable: function(){...},
fireWith: function(){...},//这个其实是 fire 函数的执行
fire: function(){...}
...
}
return self;
}
因为前面
2、promise
promise的then方法相当于attach,对消息进行了订阅,而我们的resolve和reject方法相当于notifyAllObservers,当结果返回促使promise的state发生之后遍历执行订阅的队列,调用update方法
3、node.js中的自定义事件
4、vue中的watch
5、vue和react中的生命周期钩子
进制转化2~16
function trans(n, i) {
let base = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F",];
let arr = [];
while (Math.floor(n / i) !== 0) {
let str = n % i;
arr.push(base[str]);
n = Math.floor(n / i);
}
let str = n % i;
arr.push(base[str]);
console.log(arr.join(""));
}
trans(8, 3);
parseInt
第二个参数是2~36之间的整数值,这个值其实就是我们说的进制,比如,我们用二进制去解析第一个参数,那么就这么做:
parseInt(101,2)//返回5
parseInt(8,3) == NaN,parseInt(16,3) == 1
parseInt('dsff66',16) == 13
HTML5新增语义化标签大全
HTML5中新增的标签
<article>
定义文章
<aside>
定义页面内容旁边的内容
<audio>
定义声音内容
<canvas>
定义图形
<command>
定义一个控制按钮
<datagrid>
指树或表格状数据格式中的动态数据
<datalist>
定义一个下拉列表
<details>
定义一个元素的细节
<dialog>
定义会话或人的交谈
<embed>
定义额外的交互内容或插件
<figcaption>
定义指定元素的标题
<figure>
定义一组媒体内容,以及他们的标题
<footer>
为章节或页面定义一个底部
<header>
为章节或页面定义一个头部
<hgroup>
定义文档中某段落的信息
<keygen>
定义表单生成的关键
<mark>
定义被标记的文本
<meter>
定义预定义范围内的测量
<nav>
定义导航链接
<output>
定义某种类型的输出
<progress>
定义任意种类任务的进程
<rp>
定义浏览器不支持ruby元素的替代者
<rt>
定义ruby注释的解释
<ruby>
定义 ruby 注释(中文注音或字符)。
<section>
定义章节
<source>
定义媒体资源
<summary>
定义某”detail”元素的头部
<time>
定义日期/时间
<video>
定义视频
<wbr>
定义可能的换行
树
特点
- 一对多
树的相关术语
- 节点的度:一个节点含有的子树的个数称为该节点的度;
- 叶节点或终端节点:度为0的节点称为叶节点; (一般树图 的最下面的节点)
- 非终端节点或分支节点:度不为0的节点;
- 双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
- 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
- 兄弟节点:具有相同父节点的节点互称为兄弟节点;
- 树的度:一棵树中,所有节点的度中 最大 的值 称为树的度;
- 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
- 树的高度或深度:树中节点的最大层次;
- 堂兄弟节点:双亲在同一层的节点互为堂兄弟;
- 节点的祖先:从根到该节点所经分支上的所有节点;
- 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。
各种树
二叉树
- 二叉树:每个节点最多含有两个子树的树称为二叉树。
- 满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点。也可以这样理解,除叶子结点外的所有结点均有两个子结点。节点数达到最大值,所有叶子结点必须在同一层上
- 完全二叉树:若设二叉树的深度为h,除第 h 层外,其它各层 (1~(h-1)层) 的结点数都达到最大个数,第h层所有的结点都连续集中在最左边,这就是完全二叉树。
- 二叉树的遍历方式
先序遍历:先根节点->遍历左子树->遍历右子树
中序遍历:遍历左子树->根节点->遍历右子树
后序遍历:遍历左子树->遍历右子树->根节点
动态查找树
- 二叉查找树
二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
1、 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
2、 若它的右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
3、 它的左、右子树也分别为二叉排序树。 - 平衡二叉树
平衡二叉树(Balanced Binary Tree)又被称为AVL树。它或者是一棵空树,或者是具有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1。(注:平衡二叉树应该是一棵二叉排序树)
平衡因子BF=左子树深度-右子树深度.
平衡二叉树每个结点的平衡因子只能是1,0,-1。若其绝对值超过1,则该二叉排序树就是不平衡的。 - 红黑树
红黑树也是一种自平衡的二叉查找树
1、每个结点要么是红的要么是黑的。(红或黑)
2、根结点是黑的。 (根黑)
3、每个叶结点(叶结点即指树尾端NIL指针或NULL结点)都是黑的。 (叶黑)
4、如果一个结点是红的,那么它的两个儿子都是黑的。 (红子黑)
5、对于任意结点而言,其到叶结点树尾端NIL指针的每条路径都包含相同数目的黑结点。(路径下黑相同)
6、红黑树自平衡的调整操作方式就有旋转和变色两种
7、红黑树的查找、插入、删除的时间复杂度最坏为O(log n) - 哈夫曼树(Huffman Tree)
哈夫曼树是一种带权路径长度最短的二叉树,也称为最优二叉树。
多路查找树
- B树
B树(英语:B-tree)是一种自平衡的树,能够保持数据有序。
1、根结点至少有两个子女。
2、每个中间节点都包含k-1个元素和k个孩子,其中 m/2 <= k <= m
3、每一个叶子节点都包含k-1个元素,其中 m/2 <= k <= m
4、所有的叶子结点都位于同一层。
5、每个节点中的元素从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域分划。 - B-树的特性:
1.关键字集合分布在整颗树中;
2.任何一个关键字出现且只出现在一个结点中;
3.搜索有可能在非叶子结点结束;
4.其搜索性能等价于在关键字全集内做一次二分查找;
5.自动层次控制; - B-树的性能总是等价于二分查找(与M值无关),也就没有B树平衡的问题;
- B+树
1、B+ 树是一种树数据结构,通常用于关系型数据库(如Mysql)和操作系统的文件系统中。
2、B+ 树元素自底向上插入,这与二叉树恰好相反。
3、在B树基础上,为叶子结点增加链表指针(B树+叶子有序链表),所有关键字都在叶子结点 中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中。
4、B+树的非叶子节点不保存数据,只保存子树的临界值(最大或者最小),所以同样大小的节点,b+树相对于b树能够有更多的分支,使得这棵树更加矮胖,查询时做的IO操作次数也更少。
5、所有关键字都在叶子结点出现
6、其性能也等价于在关键字全集做一次二分查找; - B树
B树是B+树的变体,在B+树的非根和非叶子结点再增加指向兄弟的指针
在B+树基础上,为非叶子结点也增加链表指针,将结点的最低利用率从1/2提高到2/3。
B系列树小结
B树: 二叉树,每个结点只存储一个关键字,等于则命中,小于走左结点,大于走右结点;
B-树: 多路搜索树,每个结点存储M/2到M个关键字,非叶子结点存储指向关键字范围的子结点; 所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中;
B+树: 在B-树基础上,为叶子结点增加链表指针,所有关键字都在叶子结点中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中;
B*树: 在B+树基础上,为非叶子结点也增加链表指针,将结点的最低利用率从1/2提高到2/3;
叶子结点计算
d
n0 =( Σ n(i) * (i - 1)) + 1 (其中,i ∈ Integer,d为树的度)
i=1
例:n0 = n2 + 2* n3 + 1 = 401
堆
定义:
1、堆是一颗完全二叉树;
2、堆中的某个结点的值总是大于等于(最大堆)或小于等于(最小堆)其孩子结点的值。
3、堆中每个结点的子树都是堆树。
堆排序
堆排序与快速排序,归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法。
// 交换数组中两个位置的值
function swap(i, j, arr) {
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
//堆排序核心
function heapSort(arr, i, len) {
let temp = arr[i];
for (let j = 2 * i + 1; j < len; j = 2 * j + 1) {
temp = arr[i]; //记录当前i位置上的值
if (j + 1 < len && arr[j + i] > arr[j]) {
j++;
}
if (temp < arr[j]) {
swap(i, j, arr);
i = j; //跟踪交换是否引起堆变化
} else {
break;
}
}
}
//堆排序
function sort(arr) {
//初始化数组,形成最大堆
for (let i = Math.floor(arr.length / 2 - 1); i >= 0; i--) {
heapSort(arr, i, arr.length);
}
//交换最大堆根
for (let i = arr.length - 1; i > 0; i--) {
swap(0, i, arr);
heapSort(arr, 0, i);
}
return arr;
}
let arr = [1, 4, 3, 9, 12, 3, 8, 3, 6];
sort(arr);
Promise原理及实现
http状态码
301、302、304
- 301 Moved Permanently 永久移动。是指请求的资源已被永久的移动到新的URL,返回信息会包括新的URL,浏览器还会自动定向到新的URL。今后任何新的请求都应该使用新的URL来代替。
- 302 Found 临时移动。与301类似。但是资源只是临时被移动。客户端应该继续使用原有的URI
- 304 Not Modified 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存所访问过的资源。通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源。
什么时候会出现304
如果客户端发送了一个带条件的GET请求已被允许,而文档中的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个304状态码。即客户端和服务器端只需要传输很少的数据量来做文件的校验,如果文件没有修改过,则不需要返回全量的数据。
流程
客户端请求一个页面A。服务器返回页面A,并在A上加一个Tage客服端渲染该页面,并把Tage也存储在缓存中。客户端再次请求页面A。
并将上次请求的资源和ETage一起传递给服务器。服务器检查Tage.并且判断出该页面自上次客户端请求之后未被修改。直接返回304。
last-modified: 客服端请求资源,同时有一个last-modified的属性标记此文件在服务器最后修改的时间
客服端第二次请求此url时,根据http协议。浏览器会向服务器发送一个If-Modified-Since报头,
询问该事件之后文件是否被修改,没修改返回304。
强缓存和协商缓存
浏览器缓存分为强缓存和协商缓存,两者有两个比较明显的区别:
如果浏览器命中强缓存,则不需要给服务器发请求;而协商缓存最终由服务器来决定是否使用缓存,即客户端与服务器之间存在一次通信。
在 chrome 中强缓存(虽然没有发出真实的 http 请求)的请求状态码返回是 200 (from cache);而协商缓存如果命中走缓存的话,请求的状态码是 304 (not modified)。
请求流程
浏览器在第一次请求后缓存资源,再次请求时,会进行下面两个步骤:
浏览器会获取该缓存资源的 header 中的信息,根据 response header 中的 expires 和 cache-control 来判断是否命中强缓存,如果命中则直接从缓存中获取资源。
如果没有命中强缓存,浏览器就会发送请求到服务器,这次请求会带上 IF-Modified-Since 或者 IF-None-Match, 它们的值分别是第一次请求返回 Last-Modified或者 Etag,由服务器来对比这一对字段来判断是否命中。如果命中,则服务器返回 304 状态码,并且不会返回资源内容,浏览器会直接从缓存获取;否则服务器最终会返回资源的实际内容,并更新 header 中的相关缓存字段。.
Expires
是 http 1.0 的规范,值是一个GMT 格式的时间点字符串,比如 Expires:Mon,18 Oct 2066 23:59:59 GMT 。这个时间点代表资源失效的时间,如果当前的时间戳在这个时间之前,则判定命中缓存。有一个缺点是,失效时间是一个绝对时间,如果服务器时间与客户端时间偏差较大时,就会导致缓存混乱。而服务器的时间跟用户的实际时间是不一样是很正常的,所以 Expires 在实际使用中会带来一些麻烦。Cache-Control
这个字段是 http 1.1 的规范,一般常用该字段的 max-age 值来进行判断,它是一个相对时间,比如 .Cache-Control:max-age=3600 代表资源的有效期是 3600 秒。并且返回头中的 Date 表示消息发送的时间,表示当前资源在 Date ~ Date +3600s 这段时间里都是有效的。不过我在实际使用中常常遇到设置了 max-age 之后,在 max-age 时间内重新访问资源却会返回 304 not modified ,这是由于服务器的时间与本地的时间不同造成的。当然 Cache-Control 还有其他几个值可以设置, 不过相对来说都很少用了:- no-cache 不使用本地缓存。需要使用协商缓存。
- no-store直接禁止浏览器缓存数据,每次请求资源都会向服务器要完整的资源, 类似于 network 中的 disabled cache。
- public 可以被所有用户缓存,包括终端用户和 cdn 等中间件代理服务器。
- private 只能被终端用户的浏览器缓存。
如果 Cache-Control与 Expires 同时存在的话, Cache-Control 的优先级高于 Expires 。
协商缓存
协商缓存是由服务器来确定缓存资源是否可用。 主要涉及到两对属性字段,即第一次请求的响应头带上某个字, Last-Modified 或者 Etag,则后续请求则会带上对应的请求字段 If-Modified-Since或者 If-None-Match,若响应头没有Last-Modified 或者 Etag 字段,则请求头也不会有对应的字段。
Last-Modified/If-Modified-Since
二者的值都是GMT格式的时间字符串, Last-Modified 标记最后文件修改时间, 下一次请求时,请求头中会带上 If-Modified-Since 值就是 Last-Modified 告诉服务器我本地缓存的文件最后修改的时间,在服务器上根据文件的最后修改时间判断资源是否有变化, 如果文件没有变更则返回 304 Not Modified ,请求不会返回资源内容,浏览器直接使用本地缓存。当服务器返回 304 Not Modified 的响应时,response header 中不会再添加的 Last-Modified 去试图更新本地缓存的 Last-Modified, 因为既然资源没有变化,那么 Last-Modified 也就不会改变;如果资源有变化,就正常返回返回资源内容,新的 Last-Modified 会在 response header 返回,并在下次请求之前更新本地缓存的 Last-Modified,下次请求时,If-Modified-Since会启用更新后的 Last-Modified。
Etag/If-None-Match
, 值都是由服务器为每一个资源生成的唯一标识串,只要资源有变化就这个值就会改变。服务器根据文件本身算出一个哈希值并通过 ETag字段返回给浏览器,接收到 If-None-Match 字段以后,服务器通过比较两者是否一致来判定文件内容是否被改变。与 Last-Modified 不一样的是,当服务器返回 304 Not Modified 的响应时,由于在服务器上ETag 重新计算过,response header中还会把这个 ETag 返回,即使这个 ETag 跟之前的没有变化。
什么要有 Etag
HTTP1.1 中 Etag 的出现主要是为了解决几个 Last-Modified 比较难解决的问题:
- 一些文件也许会周期性的更改,但是内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
- 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since 能检查到的粒度是秒级的,使用 Etag 就能够保证这种需求下客户端在1秒内能刷新 N 次 cache。
- 某些服务器不能精确的得到文件的最后修改时间。
优先级
Cache-Control > expires > Etag > Last-Modified
水平垂直居中大全(持续更)
//第一种
position:absolute,
left:0,
top:0,
right:0,
bottom:0,
margin:auto
//第二种
position:absolute,
top:50%,
left:50%,
transform:translate(-50%,-50%)
//第三种
position:absolute,
top:50%,
left:50%,
margin-top:-Xpx,
margin-left:-Xpx
//第四种
display:flex,
justify-content:center,
align-items:center
前端前沿技术
vue的use
作用
Vue.use() 中的参数必须是一个function函数或者是一个Object对象,如果是对象的话,必须在对象中提供一个install方法。之后会将 Vue 作为参数传入。
也就是说:
1、参数为函数时,函数的参数是Vue对象
2、参数为对象时,它提供的install方法中参数是Vue对象
例子(注册组件)
/*****************************************组件代码*******************************************/
<template>
<div id="haha">
1231312213 demo 哈哈哈
</div>
</template>
<script>
export default {
name: 'haha'
}
</script>
/*********************************Vue.use() 使用的demo.js文件代码******************************/
import haha from '@/components/haha'
const demo = {
install: (Vue) => {
Vue.component('haha', haha)
}
}
export default demo
/*********************************main.js 调用 Vue.use 的代码*********************************/
// 在引入demo.js,并且使用 Vue.use() 调用
import demo from '@/components/demo.js'
Vue.use(demo)
// 完成之后,就可以在页面中直接使用组件了
源码
import { toArray } from '../util/index'
// Vue.use 源码
export function initUse (Vue: GlobalAPI) {
// 首先先判断插件plugin是否是对象或者函数:
Vue.use = function (plugin: Function | Object) {
const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
// 判断vue是否已经注册过这个插件,如果已经注册过,跳出方法
if (installedPlugins.indexOf(plugin) > -1) {
return this
}
// 取vue.use参数,toArray() 方法代码在下一个代码块
const args = toArray(arguments, 1)
args.unshift(this)
// 判断插件是否有install方法,如果有就执行install()方法。没有就直接把plugin当Install执行。
if (typeof plugin.install === 'function') {
plugin.install.apply(plugin, args)
} else if (typeof plugin === 'function') {
plugin.apply(null, args)
}
installedPlugins.push(plugin)
return this
}
}
// toArray 方法源码
export function toArray (list: any, start?: number): Array<any> {
start = start || 0
let i = list.length - start
const ret: Array<any> = new Array(i)
while (i--) {
ret[i] = list[i + start]
}
return ret
}
keep-alive属性原理
Props
include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例。
绑定组件name属性
原理
和 <transition>
相似,<keep-alive>
是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。
当组件在 <keep-alive>
内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。
在 2.2.0 及其更高版本中,activated 和 deactivated 将会在 树内的所有嵌套组件中触发。
created钩子会创建一个cache对象,用来作为缓存容器,保存vnode节点。
destroyed钩子则在组件被销毁的时候清除cache缓存中的所有组件实例。
render函数
首先通过getFirstComponentChild获取第一个子组件,获取该组件的name(存在组件名则直接使用组件名,否则会使用tag)。接下来会将这个name通过include与exclude属性进行匹配,匹配不成功(说明不需要进行缓存)则不进行任何操作直接返回vnode,成功覆盖VNode,然后返回vnode
- 如果需要多次获取数据,mounted只会执行一次,用activated
vue的name是干嘛的
1. 当项目使用keep-alive时,可搭配组件name进行缓存过滤
2. DOM做递归组件时
比如说detail.vue组件里有个list.vue子组件,递归迭代时需要调用自身name
3. 当我们使用vue.js官方提供的调试工具调试时,可以看到组件的名称,更好地定位
vue中data值无响应
data() {
return {
tableData:[{id:0,name:"lili",red:false,tip:false}]
}
}
this.$set(this.tableData[id],"red",true);
数据层次太多,没有触发render函数进行自动更新,需手动调用,调用方式如下:
this.$forceUpdate();
如果data里原本没有那个值,那么后续加值不会有响应,如果一开始就有,那会响应,
但是在已有值设置后加新增的值也会有,先点新增的值(未响应),再加已有的值也会出现,刚才加的新增的值???
bootstrap
container
.container {
padding-right: 15px;
padding-left: 15px;
margin-right: auto;
margin-left: auto;
@media (min-width: 768px) {
.container {
width: 750px;
}
@media (min-width: 992px) {
.container {
width: 970px;
}
@media (min-width: 1200px) {
.container {
width: 1170px;
}
栅格化实现
.row {
margin-right: -15px;
margin-left: -15px;
}
.col-xs-1, .col-sm-1, .col-md-1, ... {
position: relative;
min-height: 1px;
padding-right: 15px;
padding-left: 15px;
}
.col-xs-pull-11 {
right: 91.66666667%;
}
.col-xs-offset-12 {
margin-left: 100%;
}
清除浮动
a::before,a::after{
content:"",
display:table
}
::after{
clear:both
}
vue祖父组件传值
vuex
vueBus
安装: npm install vue-bus
在main.js 中引入vuebus:
import Vue from ‘vue’;
import VueBus from ‘vue-bus’;
Vue.use(VueBus);
this.$bus.emit(“onslected”,params)
this.$bus.on(“onslected”,function(){})
this.$bus.off(“onslected”);
$attrs,$listener,inheritAttrs
inheritAttrs:true 继承除props之外的所有属性;inheritAttrs:false 只继承class属性。
$attrs: 包含了父作用域中不被认为 (且不预期为) props 的特性绑定 (class 和 style 除外),并且可以通过 v-bind=”$attrs” 传入内部组件。当一个组件没有声明任何 props 时,它包含所有父作用域的绑定 (class 和 style 除外)。
$listeners: 包含了父作用域中的 (不含 .native 修饰符) v-on 事件监听器。它可以通过 v-on=”$listeners” 传入内部组件。它是一个对象,里面包含了作用在这个组件上的所有事件监听器,相当于子组件继承了父组件的事件。
provide和inject
如果data里设置了,created里又设置,后代可能会取到data里的而不是created里的
this._provided 指向当前vue实例的provide对象
provide 和 inject 绑定并不是可响应的。
要实现父子组件响应,父组件传递的数据类型必须是对象Object,子组件接收的数据类型必须是对象Object,其他数据类型都是不好使的,如果只要子组件响应,只要父组件穿对象???
provide(){
return {
userLevel:{name:"jack"},
}
}
// inject:['userLevel']
inject:{
userLevel:{
default:()=>{}
},
},
provide () {
return {
getReaciveNameFromParent: () => this.name
}
},
inject: ['getReaciveNameFromParent'],
vue生命周期详解
1、beforeCreated()
组件刚被创建,组件属性计算之前。此时,无法获取 data中的数据、methods中的方法。
2、created()
created:组件实例化创建完成,属性已经绑定,但是DOM还未生成,$el属性还不存在
可以调用methods中的方法、改变data中的数据
3、beforeMount()
在挂载开始之前被调用:相关的 render 函数首次被调用。
4、mounted()
mounted:模板编译
vue实例已经挂载到页面中,可以获取到el中的DOM元素,进行DOM操作
5、beforeUpdate()
数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。 你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。此处获取的数据是更新后的数据,但是获取页面中的DOM元素是更新之前的.
6、updated()
由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态,因为这可能会导致更新无限循环。
该钩子在服务器端渲染期间不被调用。组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作
7、beforeDestroy()
实例销毁之前调用。在这一步,实例仍然完全可用。
8、destroyed()
Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 该钩子在服务器端渲染期间不被调用。
V8引擎
元素获取
js 获取元素(父节点,子节点,兄弟节点)
childNodes只会返回文本和元素的节点,并不能返回属性节点!!!
childern指的是返回当前元素的所有元素节点
parentNode:顾名思义-父节点
parentElement:顾名思义-父元素
element.previousSibling、element.previousElementSibling
element.nextSibling、element.nextElementSibling
element.firstChild、element.firstElementChild
element.lastChild、element.lastElementChild
jquery 获取元素(父节点,子节点,兄弟节点)
$("#test1").parent(); // 父节点
$("#test1").parents(); // 全部父节点
$("#test1").parents(".mui-content");
$("#test").children(); // 全部子节点
$("#test").children("#test1");
$("#test").contents(); // 返回#test里面的所有内容,包括节点和文本
$("#test").contents("#test1");
$("#test1").prev(); // 上一个兄弟节点
$("#test1").prevAll(); // 之前所有兄弟节点
$("#test1").next(); // 下一个兄弟节点
$("#test1").nextAll(); // 之后所有兄弟节点
$("#test1").siblings(); // 所有兄弟节点
$("#test1").siblings("#test2");
$("#test").find("#test1");
三,元素筛选
// 以下方法都返回一个新的jQuery对象,他们包含筛选到的元素
$("ul li").eq(1); // 选取ul li中匹配的索引顺序为1的元素(也就是第2个li元素)
$("ul li").first(); // 选取ul li中匹配的第一个元素
$("ul li").last(); // 选取ul li中匹配的最后一个元素
$("ul li").slice(1, 4); // 选取第2 ~ 4个元素
$("ul li").filter(":even"); // 选取ul li中所有奇数顺序的元素
Promise/a+规范
规范内容
1、 不管进行什么操作都返回一个promise对象,这个对象里面会有一些属性和方法(这个效果类似于jquery中的链式编程,返回自己本身)
2、 这个promise有三种状态
pedding(未完成,初始状态)
Fulfilled(已完成)
rejected(失败、拒绝)
3、 这个promise对象的使用时通过then方法进行的调用
function myPromise(constructor){
let self=this;
self.status="pending";
self.value=undefined;//if pending->resolved
self.reason=undefined;//if pending->rejected
self.onFullfilledArray=[];//to deal with async(resolved)
self.onRejectedArray=[];//to deal with async(rejeced)
function resolve(value){
//pending->resolved
if(self.status==="pending"){
self.status="resolved";
self.value=value;
self.onFullfilledArray.forEach(function(f){
f(self.value);
})
}
}
function reject(reason){
if(self.status==="pending"){
self.status="rejected";
self.reason=reason;
self.onRejectedArray.forEach(function(f){
f(self.reason);
})
}
}
//According to the definition that the function "constructor" accept two parameters
//error catch
try {
constructor(resolve,reject);
} catch (e) {
reject(e);
}
}
myPromise.prototype.then=function(onFullfilled,onRejected){
onFullfilled=typeof onFullfilled==="function"?onFullfilled:function(x){return x};
onRejected=typeof onRejected==="function"?onRejected:function(e){throw e};
let self=this;
let promise2;
switch (self.status) {
case "pending":
promise2=new myPromise(function(resolve,reject){
self.onFullfilledArray.push(function(){
setTimeout(function(){
try {
let temple=onFullfilled(self.value);
resolvePromise(promise2,temple,resolve,reject);
} catch (e) {
reject(e)
}
})
});
self.onRejectedArray.push(function(){
setTimeout(function(){
try {
let temple=onRejected(self.reason);
resolvePromise(promise2,temple,resolve,reject);
} catch (e) {
reject(e)
}
})
})
});
break;
case "resolved":
promise2=new myPromise(function(resolve,reject){
setTimeout(function(){
try {
let temple=onFullfilled(self.value);
resolvePromise(promise2,temple,resolve,reject);
} catch (e) {
reject(e)
}
})
});
break;
case "rejected":
promise2=new myPromise(function(resolve,reject){
setTimeout(function(){
try {
let temple=onRejected(self.reason);
resolvePromise(promise2,temple,resolve,reject);
} catch (e) {
reject(e)
}
})
});
break;
default:
}
return promise2;
}
function resolvePromise(promise,x,resolve,reject){
// promise must != temple
if(promise===x){
return reject(new TypeError("Cyclic reference"));
}
let isUsed;
if(x!==null&&(typeof x==="object"||typeof x==="function")){
try{
let then=x.then;
if(typeof then==="function"){
//
then.call(x,function(y){
if(isUsed)return;
isUsed=true;
resolvePromise(promise,y,resolve,reject)
},function(e){
if(isUsed)return;
isUsed=true;
reject(e);
})
}else{
resolve(x);
}
}catch(e){
if(isUsed)return;
isUsed=true;
reject(e);
}
}else{
resolve(x);
}
}