实现垂直水平居中的方式
- 定位 + margin
position: absolute;/* 父节点要定位 */
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
- 定位 + 负margin
width: 100px;
height: 100px;
position: absolute;/* 父节点要定位 */
top: 50%;
bottom: 50%;
margin-top: -50px;
margin-left: -50px;
- 定位 + transform
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
- 弹性盒(父盒子设置)
display: flex;
justify-content: center;
align-items: center;
原生js
JavaScript是一门什么样的语言,它有哪些特点?]
是一种什么语言
- 一种直译式脚本语言,,是一种动态类型、弱类型、基于原型的语言,内置支持类型
- 它的解释器被称为JavaScript引擎,为浏览器的一部分
- 广泛用于客户端的脚本语言
- avaScript兼容于ECMA标准,因此也称为ECMAScript。
JavaScript特点
- 简单性
- 动态性
- 跨平台性
JavaScript是依赖于浏览器本身
- 安全性
它不允许访问本地的硬盘,并不能将数据存入到服务器上,不允许对网络文档进行修改和删除,只能通过浏览器实现信息浏览或动态交互。从而有效地防止数据的丢失。
Javascript的数据类型
字符串、数字、布尔、数组、对象、Null、Undefined
typeof返回的数据类型
[undefined string boolean number symbol(ES6) Object Function]
强制类型转换:
1.将任意类型转为字符串 string(要转换的类型)
2.将其他类型转为值类型 Number(要转换的类型)
隐式类型转换:
“2” + 3; 得到 “23”
3 + true; 得到4
实现图片懒加载的原理:
- 开始:在img标签的src属性上,放一张小图或者设为空。
- 先将图片的地址存到自定义的属性中,当js监听到该图片元素进入到可视窗口时,则把自定义属性中的地址赋给src ,从而达到图片懒加载效果。
- 优点:1. 减少服务器压力 2. 增加用户体验
-
vue图片懒加载插件vue-lazyload
-
vue-lazyload懒加载的插件参考文档 [https://www.cnblogs.com/DZzzz/p/8889280.html]
预加载:
- 提前加载图片,当用户需要查看时可直接从本地缓存中渲染
- 预加载会增加服务器的压力,可以说是牺牲服务器前端性能,换取更好的用户体验,这样可以使用户的操作得到最快的反映。
split() join() 的区别
- join(’,’) : 返回字符串,用于把数组中的所有元素放入一个字符串,元素通过指定的分隔符来分隔。 数组 - ->字符串
- split(a,b) 返回数组 ,a是指定以什么拆分,b从什么地方开始切割 字符串–>数组,(支持正在表达式)
var str="how are you?"; console.log(str.split("")+"<br />");//h,o,w, ,a,r,e, ,y,o,u,? console.log(str.split("a")+"<br />");//how ,re you? 不包含a本身 console.log(str.split(" ")+"<br />");//how,are,you? console.log(str.split("",3)+"<br />");//h,o,w
数组方法
- 数组操作
pop()删除数组的最后一项
push()增加到数组最后一项
unshift()增加到数组第一项
shift()删除数组的第一项
splice(index,qty,…item)在数组中插入,删除,替换的通用方法,返回新数组 - splice的参数:index为起始的索引位置,qty要删除的数量,item要插入的元素(可多个)
事件
-
普通事件和绑定事件的区别
普通事件如果出现相同,则会被覆盖 只支持单个事件,并且不可以取消
事件绑定可以绑定多个,不会相互覆盖 可以绑定多个事件,还可以取消 -
IE和DOM事件流的区别
ie 采用冒泡型事件模型
ODM采用捕获型事件模型 -
事件冒泡
1.当使用事件冒泡时,子级元素先触发,父级元素后触发
2.只会在父子之间进行传递,不会在同级元素之间发生
3.传播过程中不会因为某个父级元素没有相同类型的事件而终止. -
事件捕获
当你使用事件捕获时,父级元素先触发,子级元素后触发
-
阻止事件捕获
DOM标准通过调用e.preventDefault()方法
在IE下,通过设置event.returnValue为false -
阻止事件传播(需要阻止哪一个传播就在哪一个添加)
在IE下只能阻止事件冒泡,通过设置event.cancelBubble为true
DOM标准通过调用e.stopPropagation()方法
IE和标准下有哪些兼容性的写法
- event对象 var e = e || window.event
- 获取body的大小 document.documentElement.clientWidth || document.body.clientWidth
- 事件源对象 var target = e.srcElement||e.target
- 阻止浏览器默认行为 event.returnValue=false || e.preventDefault()
this
this值指当前函数运行的环境
函数方法
- call和apply与bind()的区别
call()执行函数,并接收不定数量的参数 第一个参数改变this指向(不需要接收)
apply()执行函数,接收两个参数, 第一个参数改变this指向(不需要接收) 第二个参数且为数组
bind()不执行函数,接收多个参数 第一个参数改变this指向(不需要接收)
继承
- 继承是面向对象中一个非常重要的特征。指的是:子类继承父类的属性和方法。
- j继承方法
用new var b=new B();
在原型对象中继承 B.prototype=new A();
function Father(param){}
function Child(param){
Father.call(this, param);
}
es6的继承
定义类
//定义类
class Person {
constructor(name,age) {
this.name = name;
this.age = age;
}
getInfo() {
return `我叫${this.name},今年${this.age}岁`;;
}
}
- 写在类里面的方法实际是给Person.prototype添加方法
- constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。如果没有constructor方法,则得使用默认的constractor方法
extends继承
- 子类继承了父类,在子类构造函数中必须调用super方法。
- 子类的constructor方法没有调用super之前,不能使用this关键字,否则报错,而放在super方法之后就是正确的。
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
class Man extends Person {
constructor(name, age, gender) {
//this.gender = gender; // 报错
super(name, age);
this.gender = gender; // 正确
}
}
静态方法
-
如果在一个方法前,加上static关键字,这就称为“静态方法”
-
静态方法方法不会被实例继承,而是直接通过类来调用Person.getInfo()
-
父类的静态方法,可以被子类继承Man.getInfo()
class Person {
constructor(){
this.name = 'laoxie',
this.age = 18;
}
static getInfo(){
return this.name
}
say(){
console.log(`Hello everyone, my name is ${this.name}, I'm ${this.age} years old`)
}
}
class Man extends Person {}
闭包
- 原理:
闭包是指有权限访问另一函数作用域中的变量的函数
- 闭包函数:
函数嵌套函数 ,将函数return 到函数的外部
- 变量访问规则:
不能访问函数内部的变量
- 垃圾回收机制:
函数执行完毕,垃圾回收机制会自动清除内部的无引用变量
- 作用域 :
内部函数可以访问外部函数的变量,外部不能访问内部函数的变量
- 特性:
- 封闭性:外界无法访问闭包内部的变量,除非闭包主动向外界提供访问接口。
- 持久性:一般的函数,调用完毕之后,系统自动注销函数,而对于闭包来说,在外部函数被调用之后,闭包结构依然保存在。
- 优点:
- 减少全局变量
- 减少传递函数的参数量
- 缺点:
- 占用内存资源,过多使用闭包会导致内存溢出
事件委托
- 原理
利用事件冒泡的原理来实现,把事件绑定给父级元素
- 优点
- 减少事件绑定的数量
- 让新添加的元素具有行为
DOM
-
节点的操作:
1.插入:
创建元素节点:createElement() 将新节点添加到节点列表的后面 appendChild() 将新节点添加到节点列表的前面 insertBefore()
- 删除:
删除节点 removeChild() parent.removeChild()删除并返回当前行,parent指定的子元素节点
- 复制节点 cloneNode(boolean),true为深复制
cloneNode()
- 替换节点:
将新节点替换旧节点 repalceChild()
- 查找:
getElementById() 通过id查 getElementsByTagName() 通过标签名 getElementsByClassName() 通过类查 querySelector() 返回匹配的第一个元素 querySelectorAll() 返回匹配元素的集合
- 判断:判断当前节点是否拥有子节点,返回布尔值
parent.hasChildNodes()
- 获取属性
ele.getAttribute(attr) 获取所有的属性值
- 设置属性
ele.setAttribute(attr,val)
- 删除属性
ele.removeAttribute(attr)
- 判断属性是否存在
hasAttribute(attr) 判断是否存在attr属性
javascript的本地对象,内置对象和宿主对象:
- 本地对象:本地对象就是 ECMA-262 定义的类(引用类型)
本地对象有:[Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError]
2. 内置对象:Global 、 Math它们也是本地对象,根据定义,每个内置对象都是本地对象
3. 宿主对象:浏览器提供的对象。所有的BOM和DOM都是宿主对象。
4. 自定义对象:就是自己定义的对象
document load 和document ready的区别:
- load 等页面所有资源加载完成后执行
- ready 加载完dom数后执行,不等待css等其他资源加载完成
http协议
- http是超文本传输协议,信息是明文传输
- 功能: 用于www服务器传输超文本到本地浏览器的传输协议
http通讯流程:
1. 客户端与服务端建立TCP连接,端口默认80
2. 客户端向服务器发送请求
3. 服务器向客户发起端响应
4. TCP连接断开
5. 通讯完毕,TCP连接断开
http请求方法有8种,分别为:
- GET:请求获取由 Request-URI 所标识的资源。
- POST:在 Request-URI 所标识的资源后附加新的数据。
- HEAD:请求获取由 Request-URI 所标识的资源的响应消息报头。
- OPTIONS:请求查询服务器的性能,或查询与资源相关的选项和需求。
- PUT:请求服务器存储一个资源,并用 Request-URI作为其标识。
- DELETE:请求服务器删除由 Request-URI所标识的资源。
- TRACE:请求服务器回送收到的请求信息,主要用语测试或诊断。
- CONNECT 要求用隧道协议连接代理, 要求在与代理服务器通信时建立隧道,实现用隧道协议进行TCP通信
GET请求与POST请求的区别:
-
传输方式不同:
* POST将请求数据放在请求的body里(请求体)
* GET则是将他放在请求行里(url)上,多个参数用&连接 -
大小不同:
- url的长度是有限制的,2083字节
- GET提交时,传输数据受到URL长度的限制
- 而POST不会
-
安全性:
- POST的安全性要比GET的安全性高
- GET提交数据,用户名和密码将明文出现在URL上
同源策略
- 原理:访问的 协议、域名、端口 必须是同一个站点资源,否则就会受同源策略的限制
URL构成:
- 模式(或协议),服务器主机地址(IP地址),端口,路径,参数
http请求状态码
页面404原因
未找到资源文件
常见http转态码:
- 100: 继续 客户端应当继续发送请求。客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应。
- 101: 转换协议 在发送完这个响应最后的空行后,将会切换到在Upgrade 消息头中定义的那些协议。只有在切换新的协议更有好处的时候才应该采取类似措施。
- 102: 继续处理 由WebDAV(RFC 2518)扩展的状态码,代表处理将被继续执行。
- 200: 请求成功 处理方式: 获得响应的内容,进行处理
- 201: 请求完成,结果是创建了新资源。新创建资源的URI可在响应的实体中得到 处理方式: 爬虫中不会遇到
- 202: 请求被接受,但处理尚未完成 处理方式: 阻塞等待
- 204: 服务器端已经实现了请求,但是没有返回新的信 息。如果客户是用户,则无须为此更新自身的文档视图。 处理方式: 丢弃
- 300: 该状态码不被HTTP/1.0的应用程序直接使用, 只是作为3XX类型回应的默认解释。存在多个可用的被请求资源。 处理方式: 若程序中能够处理,则进行进一步处理,如果程序中不能处理,则丢弃
- 301: 请求到的资源都会分配一个永久的URL,这样就可以在将来通过该URL来访问此资源 处理方式: 重定向到分配的URL
- 302: 请求到的资源在一个不同的URL处临时保存 处理方式: 重定向到临时的URL
- 304: 请求的资源未更新 处理方式: 丢弃
- 400: 非法请求 处理方式: 丢弃
- 401: 未授权 处理方式: 丢弃
- 403: 禁止 处理方式: 丢弃
- 404: 没有找到 处理方式: 丢弃
- 500: 服务器内部错误 服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在的源代码出现错误时出现。
- 501: 服务器无法识别 服务器不支持当前请求所需要的某个功能。当服务器无法识别请求的方法,并且无法支持其对任何资源的请求。
- 502: 错误网关 作为网关或者工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。
- 503: 服务出错 由于临时的维护或者过载,服务器当前无法处理请求。这个状况是临时的,并且将在一段时间以后恢复。
数组去重方案
- indexOf方法
新建一新数组,遍历传入数组,值不在新数组就push进该新数组中
function indexof(arr){
var arr1 = [];
for(var i = 0 ;i <arr.length; i++){
if(arr1.indexOf(arr[i]) == -1){
arr1.push(arr[i]);
}
}
return arr1;
}
var arr = [1,2,3,4,5,6,7,1,2,4,5];
consoloe.log(arr);
- sort 方法
给传入数组排序,排序后相同值相邻,然后遍历时,新数组只加入不与前一值重复的值
function sort(array){
array.sort();
var temp=[array[0]];
for(var i = 1; i < array.length; i++){
if( array[i] !== temp[temp.length-1]){
temp.push(array[i]);
}
}
return temp;
}
var aa = [1,2,"2",4,9,"a","a",2,3,5,6,5];
console.log(uniq(aa));
- indexOf方案2
// * 实现思路:如果当前数组的第i项在当前数组中第一次出现的位置不是i,
// * 那么表示第i项是重复的,忽略掉。否则存入结果数组。
function uniq(array){
var temp = [];
for(var i = 0; i < array.length; i++) {
//如果当前数组的第i项在当前数组中第一次出现的位置是i,才存入数组;否则代表是重复的
if(array.indexOf(array[i]) == i){
temp.push(array[i])
}
}
return temp;
}
var aa = [1,2,"2",4,9,"a","a",2,3,5,6,5];
console.log(uniq(aa));
- 用循环实现
思路: 实现思路:获取没重复的最右一值放入新数组。检测到有重复值时终止当前循环同时进入顶层循环的下一轮判断
function uniq(array){
var temp = [];
var index = [];
var l = array.length;
for(var i = 0; i < l; i++) {
for(var j = i + 1; j < l; j++){
if (array[i] === array[j]){
i++;
j = i;
}
}
temp.push(array[i]);
index.push(i);
}
console.log(index);
return temp;
}
var aa = [1,2,2,3,5,3,6,5];
console.log(uniq(aa));
- es6扩展符方法
function dedupe(array) {
return [...new Set(array)]
}
var arr = [1,2,2,3,3,4,4,5,5]
console.log(dedupe(arr))
-
es6中set与map方法实现
四个操作方法:
- add(value):添加某个值,返回Set结构本身。
- delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
- has(value):返回一个布尔值,表示该值是否为Set的成员。
- clear():清除所有成员,没有返回值
- set内部的元素可以遍历for…of…
// 例一
var set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]
var s = new Set();
[2, 3, 5, 4, 5, 2, 2].map(x => s.add(x));
for (let i of s) {
console.log(i);// 2 3 5 4
}
获取页面中的所有checkbox
var domList = document.getElementsByTagName(‘input’)
var checkBoxList = []; // 定义一个存储checkbox的空数组
var len = domList.length; // 第一步获取的数组的长度
while (len--) { //使用while的效率会比for循环更高 // 开始循环判断
if (domList[len].type == 'checkbox') {
checkBoxList.push(domList[len]); // 就把那个元素加入到上面定义的数组中
}
}
复制对象的方法
浅复制–> 复制后,操作会相互影响
- 最简单的浅拷贝
const originArray = [1,2,3,4,5];
const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneArray = originArray;
const cloneObj = originObj;
- es6方法:Object.assign();参数1为目标对象,可空对象或者源对象,参数2为源对象,可多个
let target = {a: 123};
let source1 = {b: 456};
//浅复制,将source1对象复制到obj这个对象中
let obj = Object.assign({},source1);
//合并对象,将多个对象放在数组中,返回目标对象
//参数1为目标对象,可空对象或者源对象,参数2为源对象
let obj = Object.assign({},[target,source1]);
//拷贝属性值,可用es6扩展符1
const originArray = [1,2,3,4,5,[6,7,8]];
const cloneArray = [...originArray];
console.log(originArray); //1, 2, 3, 4, 5, [6,7,8]
//打印结果
console.log(obj);
//es6扩展符实现浅拷贝2
var obj = {
name: 'FungLeo',
sex: 'man',
old: '18'
}
var { ...obj2 } = obj
obj.old = '22'
console.log(obj)
console.log(obj2)
// for in 方法实现浅拷贝
let obj = {
aa: 11,
bb: {
cc: 22
}
}
let newObj = {};
for (const key in obj) {
newObj[key] = obj[key];
}
深复制 : 复制后,操作不会相互影响
* JSON.parse(JSON.stringify(test)) 方法
JSON.parse 是将一个 JSON 字符串转成一个 JavaScript 值或对象。
JSON.stringify 是将一个 JavaScript 值转成一个 JSON 字符串。
var test={
a:"ss",
b:"dd",
c:[
{dd:"css",ee:"cdd"},
{mm:"ff",nn:"ee"}
]
};
var test1 = JSON.parse(JSON.stringify(test));//拷贝数组,注意这行的拷贝方法
console.log(test);
console.log(test1);
test1.c[0].dd="change"; //改变test1的c属性对象的d属性
console.log(test); //不影响test
console.log(test1);
复制数组方法
-
concat 合并数组,concat 只是对数组的第一层进行深拷贝
const cloneArray = originArray.concat();
-
slice 截取数组,也可以达到复制效果
const originArray = [1,[1,2,3],{a:1}];
const cloneArray = originArray.slice();
- for循环实现深拷贝
function copyArr(arr) {
let res = [];
for (let i = 0; i < arr.length; i++) {
res.push(arr[i]);
}
return res
}
var arr = [1,2,3,4,5];
console.log(copyArr(arr));
- es6扩展符实现深拷贝
var arr = [1,2,3,4,5]
var [ ...arr2 ] = arr
arr[2] = 5
console.log(arr)
console.log(arr2)
同步与异步的原理
同步(不推荐)
等待程序执行完毕再执行后面的代码/阻塞后面的代码执行
异步
不等待程序的执行/不会阻塞后面的代码执行
Ajax
原生ajax的基本使用
- readystate(0 ~ 4)的4个状态
0 -> 初始状态
1 -> 已打开未发送
2 -> 已获取响应头
3 -> 正在下载响应体
4 -> 完成
1 . 第一种写法
let xhr = new XMLHttpRequest();
xhr.onload = ()=>{
let status = [200,304];
if(status.indexOf(xhr.status) >=0){
let res = JSON.parse(xhr.responseText);
}
}
//post请求
xhr.open('post',`../api/longin.php`,true);
xhr.send(`username=${username}&password=${password}`);
//get请求
xhr.open('get',`../api/longin.php?username=${username}&password=${password}`,true);
xhr.send();
- 第二种写法
var status = [200,304];
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if(xhr.readyState === 4 && status.indexOf(xhr.status) >= 0) {
if(xhr.responseText) {
//接收返回结果
let res = JSON.parse(xhr.responseText);
}
}
}
//post请求
xhr.open('POST','../api/login.php',true);
//设置请求头
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send(`username=${username}&&password=${password}`);
//get请求
xhr.open('get',`../api/login.php?username=${username}&&password=${password}`,true);
//设置请求头
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send();
Jquery的ajax的基本使用
$.ajax({
url:"../api/login.php",
type:"POST",
timeout:3000,//设置请求超时时间(毫秒)。此设置将覆盖全局设置。
async:true,//是否异步,默认true
data:{
username:username,
password:password
},
success:function(data){
//打印返回结果
console.log(data);
if(data){
//判断不为空
console.log(data);
}
}
})
Axios
axios的基本使用
1.发送POST请求
axios({
method:"post",
url:"/user/logon",
data:{
username:"name",
password:"pass"
}
}).then(function(response){
//在这里打印结果
console.log(response);
})
.catch(function(error){
//在这里打印报误
console.log(error);
});
2.发送get请求
//第一种写法
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
}) .catch(function (error) {
console.log(error);
});
//第二种写法
axios.get('/user', {
params: {
ID: 12345
}
}) .then(function (response) {
console.log(response);
}) .catch(function (error) {
console.log(error);
});
3.多个请求并发(可以两种不同的请求类型)
//第一种写法:
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// 两个请求现在都执行完成
}));
//第二种写法:
axios.all([
axios.get('/user/logon'),
axios.get('/user/getgoods',
{
name:"laoyao",
gender:"男"
})]).then(axios.spread(function(acct,perms){
//请求回来的两个结果
console.log(acct,perms);
}));
axios和ajax区别
-
Ajax:
1. ajax 是一种现有的标准的方法 2. 最大的优点就是不重新加载整个页面的情况下,可以和服务器交换数据,更新部分页面 3. 不需要任何的插件,但需要用户语序JAVASCRIPT在浏览器运行
-
Axios:
1. 用于浏览器和node.js的基于promise的http客户端 2. 从浏览器制作XMLhttpRequest; 3. 让http从nodejs 请求 4. 支持promise API ; 5. 可以设置响应和请求拦截器; 6. 自动转换JSON数据;
ES6的新特性
1. 关键字 let
* 声明不会提前
* 同作用域下不能多次声明同一变量
* let 在块及作用域内
* 块及作用域:花括号代表代码块{}
2. 关键字 const
* 与let的规则相同
* 声明变量后的值无法修改
* 约定全部大写
3. set集合
* 类似于数组,但成员的值都是唯一的
* 可自动去重(默认去重,恒等关系)
* 定义一个set
let myset = new set();
* set操作
1. 添加值,返回set结构本身 add(value)
例: arr.add(1,2,3,4);
2. 删除值,返回boolear delete(value)
例: arr.delete(1,4);
3. 判断值是否存在,返回boolear has(value)
例: arr.has(4);
4. 清除所有成员,无返回值 clear()
例: arr.clear();
* 将set转为数组:set -> Array
方法: Array.from()
例: let myArr = Array.from(mySet);
4. map映射(键值对)key/value
* 定义map
列: let myMap = new Map();
* 类似于对象的数据集合:map映射,他能让所有类型的数据作为属性名
* js对象只能用字符串来当做属性名
* map操作方法
1. 设置属性 set()
例: set(key,value);
2. 获取属性 get()
例: get(key,value);
3. 判断属性是否存在 has()
例: has(key,value);
4. 删除属性 delete()
例: delete(key,value);
5. 清空所有
例: clear();
* map遍历方法
1. keys() 获取所有的键
2. values() 获取所有的值
3. entries() 获取所有键值对,返回类数组
4. forEach() 遍历map的所有成员,循环遍历,配合结构赋值
5. 生成器函数 Generator
* 应用场景:新手导向
function * show(){}
* 函数和函数名之间有一个*星号
* 函数体内使用了yield表达式
* 生成器函数有 next()方法
* 执行next()方法后,得到一个yield或return 返回值组成的数组对象(包含value,done属性)
*对象中的done是否为true取决函数是否执行完毕
{value:123,done:false}
value:为返回值
done:为函数执行是否结束
* 暂停函数执行: yield
6. 结构
* 对数组和对象中提取值,对变量进行赋值
* 结构失败得到undefine
*用途:
1. 交换变量
2. 函数返回多个值
3. 定义函数形参,函数的参数定义方式,不用考虑参数顺序问题
* 参数可以设置默认值
*结构失败: 没有同名属性
结构失败可指定默认值:声明一个变量并赋值
7. 箭头函数
* 选择性省略function,(),{},return
* 无参数:var sun =()=>{}
* 1个参数: var sun = a=>{}
* 2个参数及以上: var sun =(a,b)=>{}
* 剩余参数 ...
* 箭头函数中没有this
8. symbol 数据类型
* 定义方式: let ss = symbol();
* 带标识的定义方式; let ss= symbol('aa');
* symbol.for('aa')
特点:会自动寻找aa是否存在,有则用,无则创建
* 一种新的原始数据类型
* 值是唯一的,声明后的值无法修改
* 是一种类似于字符串的数据类型
* 不能与其他数据类型运算,否则报错
9. 字符串模板 ``
* 使用反引号 ``
* 在字符串模板中,只要是变量,就要用规定格式:格式为 ${}
js兼容
1. 获取内联样式: getcomputedStyle(ele) || ele.currentStyle['attr'];
2. 获取window事件源 e =e || window.event;
3. 键盘事件 e = e.which || e.keycode;
4. 阻止浏览器默认行为 e.preventDefault() || event.returnValue = false;
5. 停止冒泡 event.stoppropagation() || event.cancelBubble = true;
6. 事件监听 addEventListener || attachEvent
7. 移除事件监听 removeEeventListener || datachEvent
8. 获取事件源对象 event.target || event.srcElement
mongodb与mysql的区别
1. mysql是关系类型的数据库,mongodb不是关系类型数据库
2. 关系类型数据库组成:
* 数据库
* 表
* 记录
三个概念组成。
3. mongodb组成:
* 数据库
* 集合
* 文档对象
三个层次组成。
4. mongodb没有表的概念,这体现了模式自由的特点。
Vue
vue的组件通信
- 使用Vuex
- 使用自定义事件
- 使用第三方实例
vuex
什么是vuex?
就是专门为vue.js应用程序开发的状态管理模式
是一种集中式管理应用的所有组件状态
vuex用法
- 安装: cnpm install vuex --save
// 第一步:引入状态管理
import Vue from 'vue';
import Vuex from 'vuex';
//赋到全局
Vue.use(Vuex);
//第二步:定义一个容器 store
const store = new Vuex.Store({
//state放数据
state: {
opt:"",
page:0
},
//设置状态
mutations:{
inputVal (state,data) {
state.opt = data;
},
setpageVal(state,res){
state.page = res;
}
},
//异步修改状态
actions:{
setInputVal (context,data) {
context.commit('inputVal',data);
}
},
//返回结果
getters:{
getInputVal(state){
return state.opt
},
getPage(state){
return state.page
}
}
})
//第三步:将store注入根节点
new Vue({
store,
render: h => h(App)
}).$mount('#app')
//组件中使用
// 在组件中获取数据
this.$store.getters.getPage.page;
// 在组件中 改变状态同步和异步的写法:
/*
dispatch:含有异步操作,例如向后台提交数据,写法:
this.$store.dispatch('mutations方法名',值);
commit:同步操作,写法:
this.$store.commit('mutations方法名',值);
*/
//在组件中使用时,如下
methods: {
increment(){
this.$store.dispatch("updateUserInfo", 'nick');
this.$store.commit("increment", 'nick');
},
decrement() {
this.$store.dispatch("updateCartCount", 1);
this.$store.commit("decrement", 1);
}
}
vuex方法介绍
Actions:
接受一个context对象参数,该参数具有和store实例相同的属性和方法, 所以我们可以通过context.commit(); 提交mutations中的方法,或者可以通过context.state和context.getters去获取state和getters。
在Actions里对应的方法中第二个参数接受分发是传递的值。
注:context并不是store实例本身
vue-router
- 安装: cnpm install vue-router --save-dev
// 引入:
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
// 定义路由
const routes = [{
path:'/',
component: Home
}, {
path: '/home',
component: Home
}, {
path: '/list',
component: List
}
];
// 创建 router 实例,然后传 `routes` 配置
const router = new VueRouter({
routes
// routes:routes 缩写为 routes
});
//将router挂载到根节点
const app = new Vue({
router
}).$mount('#app');
//路由出口: 路由匹配到的组件将在这里渲染,在app.vue中添加
<router-view></router-view>
- 在全局的根节点注入了router后:
我们可以在任何组件内通过 this. r o u t e r 访 问 路 由 器 也 可 以 通 过 t h i s . router 访问路由器 也可以通过 this. router访问路由器也可以通过this.route 访问当前路由
例: this.$router.list
router-link
- 全局在路由配置中设置linkActiveClass属性,,一般写为active
匹配成功 -> 自动设置 class 属性值 .router-link-active
// 使用 router-link 组件来导航,相当a标签
// to指要跳转的组件
<router-link to="/foo">Go to Foo</router-link>
动态路由传参
- 动态路径参数 ,以冒号开头
routes: [
// 动态路径参数 ,以冒号开头
{ path: '/list/list/:id', component: list}
//在这里配置了props=true之后,在路由自己中可以通过props接收id参数去使用了
]
// 多个路由都要进入list组件,这时候在配置路由路径后加个:id(id可随便取名,标识),这个属性id可以在$route.params.id中获取.
<router-link to="/list/list/on">Go to Foo</router-link>
//获取这个传的值:
let on = $route.params.id; //得到On
// 经过以上的配置,传的参数在url上是没有?号的,如果没有以上配置是 ?id=1 这样的参数
带参数的路由,跟获取传来的参数值
- 当router-link被激活点击时,会将当前的to的值push到router对象当中(路由栈),所以这个值可以是string也可以是obj。
- 传参数的时候,我们就写成对象的形式,用到v-bind的js表达式。
//例:
<router link :to="{path:'/list/list/hot',query:{name:'lhf'}}"> 带参数跳到list的hot去</router-link>
//获取这个传的值:
let lhf = this.$router.query.name;
prop将路由与组件解耦
在组件中接收路由参数需要this.$route.params.id,代码冗余,现在可以在路由表里配置props:true
{path:'detail/:id',component:AppNewsDetail,name:'detail',props:true}
在路由自己中可以通过props接收id参数去使用了
props:['id']就可以获取到了
路由模式
路由有两种模式:hash、history
路由钩子
- 作用: 在某些情况下,当路由跳转前或跳转后、进入、离开某一个路由前、后,需要做某些操作,就可以使用路由钩子来监听路由的变化
全局路由钩子:
// 在任意路由跳转前执行
router.beforeEach((to, from, next) => {
//会在任意路由跳转前执行,next一定要记着执行,不然路由不能跳转了
console.log('beforeEach');
console.log(to,from);
next();
})
///在任意路由跳转后执行
router.afterEach((to, from) => {
//会在任意路由跳转后执行
console.log('afterEach')
})
单个路由钩子:
只有beforeEnter,在进入前执行,to参数就是当前路由
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
console.log('beforeEnter');
next();
}
}
]
路由组件钩子:
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
命名视图
有时候想同时(同级)展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar(侧导航) 和 main(主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default。
<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>
- 一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components 配置(带上 s):
const router = new VueRouter({
routes: [
{
path: '/',
components: {
default: Foo,//默认的,没有name的router-view
a: Bar,
b: Baz
}
}
]
})
默认路由和重定向:
当我们进入应用,默认像显示某一个路由组件,或者当我们进入某一级路由组件的时候想默认显示其某一个子路由组件,我们可以配置默认路由:
{path:'',component:Main}
当我们需要进入之后进行重定向到其他路由的时候,或者当url与路由表不匹配的时候:
{path:'',redirect:'/main'}
///...放在最下面
{path:'**',redirect:'/main'}
多级路由:
在创建路由表的时候,可以为每一个路由对象创建children属性,值为数组,在这个里面又可以配置一些路由对象来使用多级路由,注意:一级路由path前加’/’
const routes = [
{path:'/main',component:AppMain},
{path:'/news',component:AppNews,children:[
{path:'inside',component:AppNewsInside},
{path:'outside',component:AppNewsOutside}
]},
]
二级路由组件的切换位置依然由router-view来指定(指定在父级路由组件的模板中)
<router-link to='inside'>inside</router-link>
<router-link to='outside'>outside</router-link>
<router-view></router-view>
脚手架vue-cli(3.0版本)
//安装
npm install -g @vue/cli
//初始化项目
vue create my-project
//进入项目
cd my-project
//启动项目
npm run serve
vue-cli脚手架(2.0版本)
现在使用前端工程化开发项目是主流的趋势,也就是说,我们需要使用一些工具来搭建vue的开发环境,一般情况下我们使用webpack来搭建,在这里我们直接使用vue官方提供的,基于webpack的脚手架工具:vue-cli
安装方法:
//全局安装 vue-cli
npm install --global vue-cli
//创建一个基于 webpack 模板的新项目
vue init webpack my-project
//init之后可以定义模板的类型
//安装依赖,走你
cd my-project
npm install
npm run dev
模板类型:(2.0版本)
-
simple 对应的是一个超级简单的html文件
-
webpack 在配置的时候可以选择是否需要vue-router
-
注意的是,模板创建的时候会询问使用需要使用ESLINT来标准化我们的代码
-
在脚手架中,开发目录是src文件夹,build负责打包的,config是负责配置(内置服务器的端口、proxy代理),static是静态目录,test是测试
-
src中main.js是入口文件,在里面创建了一个根实例,根实例的模板就是根组件App的模板,其他的组件都在根组件里面进行嵌套实现。
-
每一个组件都是一个单文件组件,这种文件会被webpack利用vue-loader的工具进行编译
-
template部分负责写组件的模板内容,script中创建组件。style里写组件的样式
-
assets目录也是静态目录,在这个目标中的文件我们使用相对路径引入,而static目录中的文件使用绝对地址来引入
-
在style上添加scoped能使这个style里的样式只作用于当前的组件,不加scoped就是全局样式
-
习惯于在App.vue根组件的style里写全局样式,而每个组件的style最好都是局部的
-
配置sass编译环境
-
vue-cli没有内置sass编译,我们需要自己修改配置
-
下载对应工具:node-sass(4.0.0)和 sass-loader
-
在build目录下的webpack.base.conf.js中的module.rule里添加如下配置
{
test: /\.scss$/,
loader:'style-loader!css-loader!sass-loader'
}
- 在需要使用scss代码的组件的style标签中添加 lang=‘scss’
防止表达式闪烁:
-
v-cloak
给模板内的元素添加v-cloak属性后,元素在vue没有加载完的时候就有这个属性,当vue加载完成后这个属性就消失了,所以我们可以给这个属性设置css样式为隐藏
<style>
[v-cloak]{
visibility: hidden;
}
</style>
<ul v-cloak v-for="item in items">
<li>{{ item.name }}</li>
</ul>
vue双向数据绑定原理
- 数据劫持、vue是通过Object.defineProperty()来实现数据劫持
- 其中会有getter()和setter方法;当读取属性值时,就会触发getter()方法
- 在view中如果数据发生了变化,就会通过Object.defineProperty( )对属性设置一个setter函数,当数据改变了就会来触发这个函数。
// vue双向数据绑定实现原理
let middle = 'hello';
Object.defineProperty(_data,'message',{
get () {
return middle;
},
set (val) {
middle = val;
//执行对应的watcher,让viewmodel去更新视图
}
})
vue生命周期
参考文档:[https://blog.csdn.net/qq_27828675/article/details/80455854]
钩子函数 | 说明 |
---|---|
beforeCreate | vue实例创建(new Vue()) 后,初始化完成, 创建前调用, 无数据、无模板、未挂载 |
created | vue实例创建完成后触发,有数据,无模板,未挂载 |
beforeMount | vue实例挂载前触发,有数据,有模板,无挂载 |
mounted | vue实例挂载后触发,有数据,有模板,已挂载 |
beforUpdate | 数据更新前触发 |
updated | 数据更新后触发 |
beforeDestroy | 实例销毁前触发 |
destroyed | 实例销毁后触发 |
activated | keep-alive 组件激活时触发 |
deactivated | keep-alive 组件停用时触发 |
errorCaptured | 当捕获一个来自子孙组件的错误时被调用 |
vue组件通信
Slot插槽:
- 父组件给子组件传值还可以通过标签内容传递,而slot插槽则是标记html内容分别应该放在子组件模板中的什么位置。
Porp
- prop可以传入任何类型值
- 所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态.
- 每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值
- 子组件不应使用prop
- 可以指定每个prop的数据类型
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object
}
命名规范
-
对于 props 声明的属性,在父组件的 template 模板中,属性名需要使用中划线写法;
-
子组件 props 属性声明时,使用小驼峰或者中划线写法都可以;而子组件的模板使用从父组件传来的变量时,需要使用对应的小驼峰写法。别担心,Vue 能够正确识别出小驼峰和下划线命名法混用的变量
prop静态传值
<blog-post title="My journey with Vue"></blog-post>
prop动态传值 (v-bind()指令)
<!-- 动态赋予一个变量的值 -->
<blog-post v-bind:title="post.title"></blog-post>
<!-- 动态赋予一个复杂表达式的值 -->
<blog-post v-bind:title="post.title + ' by ' + post.author.name"></blog-post>
<!-- v-bind可简写 -->
<blog-post :title="post.title"></blog-post>
获取prop传的值
* props: ['size']
* 获取值需要转换类型时:
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
Prop 验证
- required可以使用required选项来声明这个参数是否必须传入
props: {
fooMessage: {
type: Number,
required: true
}
}
- default使用default选项来指定当父组件未传入参数时props变量的默认值:
props: {
fooMessage: {
type: Number,
default: 128
}
}
当type的类型为Array或者Object的时候default必须是一个函数
props: {
fooMessage: {
type: Array,
default: function(){
return ['foo', 'bar'];
}
}
}
//使用自定义函数来校验
props: {
fooMessage: {
validator: function(value){
return value>=0 && value<=128;
}
}
}
//dafult与required同时使用
props: {
fooMessage: {
type: Number,
required: true,
default: 128
}
}
-
type可以是以下原生类型:[String,Number,Boolean,Function,Object,Array,Symbo]
-
type验证 例如:
props: {
// 基础的类型检查 (`null` 匹配任何类型)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
自定义指令
官网:[https://cn.vuejs.org/v2/guide/custom-directive.html#ad]
自定义指令的钩子函数
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
- bind:只调用一次,指令第一次绑定到元素时调用。
- inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
- update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
- componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用
- unbind:只调用一次,指令与元素解绑时调用
Vue和react的区别,优缺点
模式 | 区别 |
---|---|
在模式上 | Vue采用MVVm模式,react才用mvc模式 |
数据绑定 | Vue采用双向速度绑定,react采用单向数据绑定 |
虚拟DOM | 两者都采用虚拟DOM ,vue根据数据更改,局部重新渲染, react数据更改,全部重新渲染 |
钩子函数 | vue用了8个钩子函数,react 拥有11个钩子函数 shouldcomponentUpdate;componentWillRecevieProps 组件接受新的props触发 |
路由配置 | vue需要全局配置路由,react直接在父组件直接配置路由就可以,路由灵活 |
内置方法和指令 | vue内部封装了很多方法和指令;react内部更接近原生JS |
组件通信 | vue和react组件通信简单说说就可以 |
React
React生命周期
钩子函数 | 说明 |
---|---|
getDefaultProps | 设置默认的props,也可以用dufaultProps设置组件默认的属性 |
constructor | 数据的实例化 |
componentWillMount | 组件将要挂载 |
render | 组件挂载 |
componentDidMount | 组件已挂载 |
componentWillReceiveProps | props更新,接收一个参数:新的props |
shouldComponentUpdate | 数据(state)更新后,决定是否更新视图返回true更新视图接收两个参数:props和新后state |
componentWillUpdate | 数据已经更新,但视图未更新接收两个参数:props和新的state如果上一个生命周期shouldComponentUpdate 返回false,那么这个生命周期不会被执行 |
componentDidUpdate | 视图已更新,接收两个参数:props和新的state |
componentWillUnmount | 组件卸载 |
脚手架create-react-app
- 安装:npm install -g create-react-app
- 生成项目:create-react-app my-app
- 进入项目:cd my-app
- 启动:npm start
constructor构造函数
接收两个参数:
* props
* context
-
可以获取到父组件传下来的props和context
-
在constructor构造函数内部使用props或context,(注意是内部哦,在组件其他地方是可以直接接收的)。需要传入super对象
-
在constructor外部使用props和context,只需要传入一个参数(props),或者不传;一般传props
-
ES6的class constructor和super
只要组件存在constructor,就一定要写super;否则this指向会发生错误