JSON语法规则
1:键值对的方式
2:键用双引号引用
3:键值以冒号分割
4:数据以逗号分割
{
"name": "Tom",
"age": 20,
"isMan": true,
"list": ["item1", "item2"],
"obj": {"height": 180, "weight": 90}
}
对象字面量命名规则
1:键值对的方式
2:键不需要使用双引号引用,但当键包含会导致语法错误的字符时,需加引号
3:键值以冒号分割
4:数据以逗号分割
let josn = {
name: "Tom",
age: 20,
isMan: true,
getHeight: function () {},
"first-name": "Demo",
list: ["item1", "item2"],
obj: {"height": 180, "weight": 90}
}
解构赋值
左右结构尽量一致,不需要可留空处理
数组解构赋值
let [x, y, [z, i]] = ['this', "is", ['js', 'es6']];
console.log(x, y, z, i); //this is js es6
let [x, y, m, n] = ['this', "is", 'js'];
console.log(x, y, m, n); //this is js undefined
let [x, [z, i]] = ['this', "is", ['js', 'es6']];
console.log(x, z, i); //this i s
// 留空处理
let [x, , [z, i]] = ['this', "is", ['js', 'es6']];
console.log(x, z, i); //this js es6
对象解构赋值
let {b} = {a: 1, b: 2, c: 3};
console.log(b); //2
let person = {
name: "Tom",
age: 20,
list: ["item1", "item2"],
};
//isMan可设置默认值
let {name, age, list: [i1, i2], isMan = true} = person;
console.log(name, age, i1, i2, isMan); //Tom 20 item1 item2 true
使用场景
1:交换变量
let x = 1, y = 2;
[x, y] = [y, x];
console.log(x, y); //2 1
2:如果一个函数接收一个对象作为参数,那么,可以使用解构直接把对象的属性绑定到变量中
age({name: "Tome", age: 20, isMan: true});
function age({name, age, isMan, height = 180}) {
console.log(name, age, isMan, height); //Tome 20 true 180
}
箭头函数规则
1:如果只有一个参数,()括号可以省略
2:如果只有一句return,{}大括号可以省略
3:如果返回对象,必须用()把对象包括起来
注意:箭头函数体中的 this 对象,是定义函数时的对象,而不是使用函数时的对象
let newArr = [10, 20].map(value => value * 2);
console.log(newArr[0], newArr[1]); //20 40
//如果返回对象,可以这样写
let newArr = [10, 20].map(value => {
return {
num: value * 2
}
});
console.log(newArr[0], newArr[1]); //{num: 20} {num: 40}
//如果返回对象,也可以这样写
let newArr = [10, 20].map(value => ({num: value * 2}));
console.log(newArr[0], newArr[1]); //{num: 20} {num: 40}
Object.assign使用
Object.assign(target, …sources)
用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。并返回目标对象
修改原有对象a
let a = {name: 'Tom', age: 20, son: {name: "Jack", age: 5}};
let b = {age: 25, weight: 90};
let c = Object.assign(a, b);
console.log(c); //{name: "Tom", age: 25, son: {name: "Jack", age: 5}, weight: 90}
console.log(a === c); //true 修改了a这个对象
创建新对象c
let c = Object.assign({}, a, b);
console.log(c);//{name: "Tom", age: 25, son: {name: "Jack", age: 5}, weight: 90}
console.log(c === a); //false 创建了新对象
创建新对象c,并修改原对象a内对象son的值
let c = Object.assign({}, a, b);
a.son.age = 3;
//因为拷贝的是son的引用,所以c对象内son的age也变为了3
console.log(c);//{name: "Tom", age: 25, son: {name: "Jack", age: 3}, weight: 90}
console.log(c === a); //false 创建了新对象
注意
通过assign()合并的对象是浅拷贝,假如源对象的属性值是一个对象,那么合并成的这个对象也只是指向了那个对象的引用。深拷贝可以通过:JSON.parse(JSON.stringify(obj))。
map
一对一映射,适合对数组中每个元素做相同的操作
1:对数组map时可传递三个参数,参数1:每个条目、参数2:条目角标、参数3:原始数组
2:必须有return 否则返回undefined
3:map返回一个新数组,原数组不变
传递三个参数
let arrMap = [1, 3, 5, 7, 9];
let newArrMap = arrMap.map((item, index, arr) => {
console.log(value, index, arr);
});
console.info(newArrMap); // [undefined, undefined, undefined, undefined, undefined]
console.log(newArrMap === arrMap); //false
传递两个参数
let arrMap = [1, 3, 5, 7, 9];
let newArrMap = arrMap.map((item, index) => item * 2);
console.info(newArrMap); // [2, 6, 10, 14, 18]
console.log(newArrMap === arrMap); //false
传递一个参数-不简写
let arr = [10, 20].map((item) => {
return item * 2
});
简写
let arr = [10, 20].map(item => item * 2);
forEach
循环数组
1:对数组forEach时可传递三个参数,参数1:每个条目、参数2:条目角标、参数3:原始数组
2:forEach没有返回值,原数组不变
let arr = [1, 3, 5, 7, 9];
let newArr = arr.forEach((item, index, arr) => {
console.log(item, index, arr);
});
filter
过滤数组,返回符合条件的新数组
1:对数组filter时可传递三个参数,参数1:每个条目、参数2:条目角标、参数3:原始数组
2:必须通过返回true来过滤返回需要的值,否则不返回(默认返回false)
3:filter返回符合条件的新数组,原数组不变
注意:当条件都不满足时,返回空数组[]、当有条件满足时返回数组带参数
无返回值示例
let arr = [1, 3, 5, 7, 9];
let filterArr = arr.filter((item, index, arr) => {
console.log(item, index, arr);
});
console.log(filterArr === arr); //false
console.log(filterArr); //[] 因为默认返回false 没有满足条件的值,所以返回空数组
有返回值示例
let arr = [1, 3, 5, 7, 9];
let filterArr = arr.filter((item, index, arr) => {
// if (index % 2) return true; //和下边这行效果一样
return index % 2;
});
console.log(filterArr); //[3,7]
find
查找符合条件的值,只要查找到符合条件的就返回符合条件的值
1:对数组find时可传递三个参数,参数1:每个条目、参数2:条目角标、参数3:原始数组
2:必须通过返回true才能停止循环并返回当前值,否则不返回
3:find返回的是数组中的值,原数组不变
注意:当条件都不满足时,返回undefined
let arr = [1, 3, 5, 7, 9];
let findArr = arr.find((item, index, arr) => {
console.log(item);
if (item > 3) return true
});
console.log(findArr); //5
输出结果:
1
3
5
5
some
用于查找数组中是否有一项满足条件
1:对数组some时可传递三个参数,参数1:每个条目、参数2:条目角标、参数3:原始数组
2:必须通过返回true才能停止循环,并返回true(不返回具体值),否则返回false(默认返回false)
3:some返回的是Boolean值,原数组不变
注意:当条件都不满足时,返回Boolean值false
let arr = [1, 3, 5, 7, 9];
let someArr = arr.some((item, index, arr) => {
console.log(item);
if (item == 5) {
return true
}
});
console.log(someArr)
输出结果:
1
3
5
true
every
用于判断数组中是否每一项都符合条件
1:对数组every时可传递三个参数,参数1:每个条目、参数2:条目角标、参数3:原始数组
2:必须都返回true才能返回true(不返回具体值),否则返回false(默认返回false)停止循环
3:every返回的是Boolean值,原数组不变
let arr = [1, 3, 5, 7, 9];
let everyArr = arr.every((value, index, arr) => {
console.log(value);
//这里默认返回false,所以只循环一次就停止了
});
console.log(everyArr); //false
输出结果:
1
false
find、some、every的区别
find:查找到符合条件的值后返回这个值,停止循环
some:查找到符合条件的值后返回true,停止循环
every:每一个条目都符合条件才返回true,只要有条目返回false,则停止循环
fill
填充修改原数组(改变了原始数组)
参数1:将要填充到数组中的值
参数2:可选,填充的起始索引(默认0)
参数3:可选,填充的终止索引(默认数组末端)
let arr = [1, 3, 5, 7, 9];
arr.fill(100, 2, 4);
console.log(arr); //[1, 3, 100, 100, 9]
findIndex
获取指定元素的索引值,没有返回-1
1:对数组findIndex时可传递三个参数,参数1:每个条目、参数2:条目角标、参数3:原始数组
2:必须返回true才能返回当前条目的索引(不返回具体值)并停止循环,否则返回false(默认返回false)
3:findIndex返回的是符合条件的索引值,没有返回-1,原数组不变
let arr = [1, 3, 5, 7, 9];
let findIndexArr = arr.findIndex((item, index, arr) => {
console.log(item);
if (item == 5) {
return true;
} else {
return false
}
});
console.log(findIndexArr); //2
输出结果:
1
3
5
2
reduce
arr.reduce(callback(accumulator, currentValue[, currentIndex[, array]])[, initialValue])
reduce接收一个callback回调函数和一个初始值,callback回调函数必需有返回值
callback回调函数接收四个值
- accumulator:必需 累计器累计回调的返回值
- currentValue:必需 数组中正在处理的元素
- currentIndex:可选 数组中正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则从索引1起始
- array 可选 原数组
初始值
- initialValue:可选 作为第一次调用回调函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错
注意
- 当数组为空并且没有提供initialValue初始值时,会抛出TypeError Reduce of empty array with no initial value
- 当提供initialValue初始值时,回调函数第一次执行时,accumulator取值为initialValue,currentValue取数组中角标为1的值
- 当提供initialValue初始值时,如果数组为空,那么此初始值将被返回并且callback不会被执行
- 当不提供initialValue值时,回调函数第一次执行时,accumulator取数组中角标为0的值,currentValue取数组中角标为1的值
- 当不提供initialValue值时,如果数组中仅一个元素(无论位置如何),那么此唯一值将被返回并且callback不会被执行
建议
- 提供initialValue初始值,通常更安全
提供默认值
let arr = [1, 3, 5, 7, 9]
let num = arr.reduce((accumulator, currentValue, currentIndex, array)=>{
return accumulator + currentValue
}, 0)
console.log(num) // 25
不提供默认值
let arr = [1, 3, 5, 7, 9]
let num = arr.reduce((accumulator, currentValue, currentIndex, array)=>{
return accumulator + currentValue
})
console.log(num) // 25
数组中只有一个值
let arr = [];
arr[10] = 100;
let num = arr.reduce((accumulator, currentValue, currentIndex, array) => {
return accumulator + currentValue // 不会执行
}
)
console.log(num); // 100
空数组且不提供initialValue初始值则报错
let arr = []
let num = arr.reduce((accumulator, currentValue, currentIndex, array) => {
return accumulator + currentValue
}
)
console.log(num) // Uncaught TypeError: Reduce of empty array with no initial value
ES6的模块
参考:https://www.runoob.com/w3cnote/es6-module.html
ES6的模块分为导出(export)和导入(import)两个模块
特点
1:ES6模块自动开启严格模式,不管你有没有在模块头部加use strict
2:模块可以导入导出各种类型的变量,如函数、对象、字符串、数组、布尔值、类等
3:每个模块都有自己的上下文,每个模块内声明的变量都是局部变量,不会污染到全局作用域
4:每一个模块只加载一次(单例的),若再去加载同目录下同文件,直接从内存中读取
注意
目前在使用模块的导入导出功能时,需要使用babel转码才能用export和import, 也就是需要把es6转成es5, 建议直接在Vue中使用
export内联导出
模块可以导入导出各种类型的变量,如函数、对象、字符串、数组、布尔值、类等
注意
导出的函数声明与类声明必须要有名称(export default 命令除外)
example.js文件
export const PI = 3.14;
export let str = "str";
export let num = 10;
export function test() {
console.log("function:test")
}
export class MyClass {
name = "MyClass"
}
export let obj = {
name: "Jack",
age: 25
};
export let arr = ["item1", "item2"];
const people = {name: "Tom"};
//一个模块只能有一个默认导出
export default people;
在Vue中通过import导入需要的内容,导入和导出的顺序可以不一致
注意
1:通过export方式导出时,在import时需要加{},而通过export default导出时则不需要
2:不需要使用的变量可以不导入
3:可同时导入通过export和export default导出的内容,若export和export default同时存在则可以用下面两种方式导入
4:可以通过as重新定义导入导出的变量名
vue.js文件
<script>
import people, {obj, MyClass, arr, test, PI} from './example'; //下边和这个同样效果
// import {obj, MyClass, arr, test, PI, default as people} from './example';
export default {
name: "Demo",
mounted() {
console.log(obj.name); //Jack
console.log(MyClass.name); //MyClass
console.log(arr[0]); //item1
test(); //function:test
console.log(PI); //3.14
console.log(people.name); //Tom
}
}
</script>
export对象导出
建议使用大括号指定所要导出的内容,也就是对象导出
export方式导出
let num = 10;
let obj = {
name: "Jack",
age: 25
};
export {num, obj};
在使用导入时(顺序可不一致)
import {obj, num} from './example';
export default方式导出
const obj = {
name: "Tom",
run() {
console.log("run");
}
};
export default obj;
在使用导入时(不能加花括号{})
import example from './example';
注意:可以通过as重新定义导入导出的变量名
export default命令特点
1:在一个文件或模块中,export、import可以有多个,export default最多只能有一个
export default a;
export default b; //错误 只能有一个
2:通过export方式导出,在导入时要加{},export default则不需要并且可以使用任意变量接收
export default b;
import xxx from "./xxx.js"; // 不需要加{}, 可使用任意变量接收
3:export default中的default对应的是导出的变量不能是表达式,但export可以直接导出表达式
export default const PI = 3.14; //错误 只能是导出变量,不能是表达式
import命令特点
1:只读属性:不允许在加载模块的脚本里面改写import变量类型为基本类型的变量,也不允许改写接口的引用指向,但可以改写引用指向的属性值
example.js文件
let num = 10;
let obj = {
name: "Jack",
age: 25
};
export {num, obj};
vue.js
<script>
import {obj, num} from './example';
export default {
name: "demo",
mounted() {
num = 20; //错误
obj = {}; //错误
obj.name = "Jack"; //正确
}
}
</script>
2:单例模式:多次重复执行同一句import语句,那么只会执行一次,而不会执行多次。import同一个模块,声明不同变量引用,则会声明对应变量,但只执行一次import
import {a} "./xxx.js";
import {a} "./xxx.js";
//相当于 import {a} "./xxx.js" 了一次
import { a } from "./xxx.js";
import { b } from "./xxx.js";
// 相当于 import { a, b } from "./xxx.js";
3:静态执行特性:import是静态执行,所以不能使用表达式和变量
//错误
import {"f"+"oo"} from "./xxx.js";
//错误
let module = "./xxx.js";
import {foo} from module;
//错误
if(true){
import {foo} from "./xxx.js";
}else{
import {foo} from "./xxx.js"
}
splice
向数组中添加或删除元素,然后返回含有被删除元素的数组
注意:这种方法会改变原始数组
语法
array.splice(index,howmany,item1,…,itemX)
参数
index:必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
howmany:要删除的元素数量。如果设置为 0,则不会删除项目。
如果未设置此参数,则删除从 index 开始到原数组结尾的所有元素。
item1, …, itemX 可选。向数组添加的新元素。
返回值
如果从 array 中删除了元素,则返回的是含有被删除元素的数组
不传参数–原始数组不被修改–这样用没什么意义
/**
* 返回一个空数组,并未修改原始数组
*/
let arr = [1, 3, 5, 7, 9];
let newArr = arr.splice();
console.log(arr); //[1, 3, 5, 7, 9]
console.log(newArr); //[]
传入一个参数–原始数组被修改
/**
* 参数1:从哪个角标开始删除之后的所有元素,并返回包含删除元素的数组
*/
let arr = [1, 3, 5, 7, 9];
let newArr = arr.splice(2);
console.log(arr); //[1, 3]
console.log(newArr); //[5, 7, 9]
传入两个参数–原始数组被修改
/**
* 第二个参数传入0就是不删除元素
* 参数1:从哪个角标开始删除元素
* 参数2:删除几个元素(传0就是不删除元素)
* 返回包含删除元素的数组
*/
let arr = [1, 3, 5, 7, 9];
let newArr = arr.splice(2, 0);
console.log(arr); //[1, 3, 5, 7, 9]
console.log(newArr); //[]
/**
* 第二个参数传2就是删除两个元素
*/
let arr = [1, 3, 5, 7, 9];
let newArr = arr.splice(2, 2);
console.log(arr); //[1, 3, 9]
console.log(newArr); //[5, 7]
只插入元素
/**
* 只插入元素- 从角标2开始先删除0个元素,并从角标2开始向数组中添加新元素
* 传入三个参数--原始数组被修改
* 参数1:从哪个角标开始删除元素
* 参数2:删除几个元素(传0就是不删除元素)
* 参数3、4、.....:从参数1的角标开始向数组中添加新元素
* 返回包含删除元素的数组
*/
let arr = [1, 3, 5, 7, 9];
let newArr = arr.splice(2, 0, 10, 20);
console.log(arr); // [1, 3, 10, 20, 5, 7, 9]
console.log(newArr); //[]
说明:代表插入元素,从角标2开始先删除0个元素,并用10,20替换那些被删除的元素,即从角标为2元素开始插入10,20两个元素
删除并插入元素
/**
* 删除并插入元素
* 传入三个参数--原始数组被修改
* 参数1:从哪个角标开始删除元素
* 参数2:删除几个元素(传0就是不删除元素)
* 参数3、4、.....:从参数1的角标开始向数组中添加新元素
* 返回包含删除元素的数组
*/
let arr = [1, 3, 5, 7, 9];
let newArr = arr.splice(1, 2, 10, 20, 30);
console.log(arr); // [1, 10, 20, 30, 7,9]
console.log(newArr); //[3, 5,]
slice
从原数组中返回选定元素的数组
注意:这种方法会不会改变原始数组
语法
array.slice(start,end)
参数
start: 必需。整数,规定从何处开始选取,使用负数可从数组结尾处规定位置
end: 可选。规定从何处结束选取。如果未指定参数,则从start开始一直截取到数组结尾
返回值
返回一个新的数组,包含从start到end(不包含该元素)的array中的元素
/**
* 获取新数组,内容从arr的角标3开始一直到结尾的所有元素,
*/
let arr = [1, 3, 5, 7, 9];
let newArr = arr.slice(3);
console.log(arr); // [1, 3, 5, 7, 9]
console.log(newArr); //[7, 9]
/**
* 获取新数组,内容从arr的角标3开始角标4结束(不包含角标4元素)
*/
let arr = [1, 3, 5, 7, 9];
let newArr = arr.slice(3, 4);
console.log(arr); // [1, 3, 5, 7, 9]
console.log(newArr); //[7]
splice、slice区别
1:splice会修改原数组,slice不会
2:splice可以删除、修改、替换原数组,slice只能截取数组中的值并生成新数组
3:splice可传递多个参数,slice最多只能传递两个参数
判断对象中是否包含某属性
1.1:点运算符
通过 obj.key 或 obj[‘key’] 判断指定的属性在指定 对象和原型链 上是否存在,存在则返回具体值,不存在则返回undefined
可以通过 obj.key !== undefined 判断对象是否包含某属性(记住是全等)
注意:如果某属性值就为undefined,则通过点运算符则无法判断
1.2:in 运算符
通过 “key” in obj 判断指定的属性在指定 对象和原型链 上是否存在,存在则返回true,不存在则返回false
通过in 运算符可以判断某属性值为undefined的情况
1.3:hasOwnProperty() 方法
通过 obj.hasOwnProperty(prop) 方法 判断指定的属性在指定 对象自身身上 是否存在,存在则返回true,不存在则返回false
判断对象是否为空
1.1:通过ES6语法Object.keys
Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的 数组(不包括原型上) ,数组中属性名的排列顺序和使用 for…in 循环遍历该对象时返回的顺序一致,
可通过返回数组的长度来判断对象是否为空
let obj = {
name:'liuyz',
sex:'man',
age:20
};
console.log(Object.keys(obj)); //["name", "sex", "age"]
console.log(Object.keys(obj).length); //3
1.2:通过 for…in… 遍历属性(包括原型链上)
function isEmpty(obj) {
for(let i in obj){
return true;
}
return false;
}
console.log(isEmpty(obj)); //true
JS循环遍历对象(包括原型链上)
for(let i in obj){
console.log(i + '--' + obj[i]);
}
JS循环遍历对象(不包括原型链上)
for (let i in obj) {
if (obj.hasOwnProperty(i)) {
console.log(i + "--" + obj[i]);
}
}
JS删除对象中某一字段(属性或方法)
delete obj.sex;
console.log(obj);
JS删除数组中某一角标
let arr = ["1", "2", "3"];
delete arr[1]; //删除数组某一项值,数组长度不变
console.log(arr); //["1", empty, "3"]
JS抛出一个异常
throw new Error('error');
解决div里面img图片下方有空白的问题
# 产生空白的原因
img标签是行内块元素即默认是:display: inline-block,且行内块元素的默认对齐方式是基线对齐即vertical-align: baseline
所以产生空白的原因是因图片底边与容器基线对齐了,留出了基线与底线的空白
# 解决空白方法
<div class="pic-container">
<img class="pic" src="~images/img1.jpg" alt="">
<img class="pic" src="~images/img2.jpg" alt="">
</div>
1.1:把图片父容器设置为flex布局
.pic-container {
width: 100%;
display: flex;
flex-direction: column;
.pic {
width: 100%;
}
}
1.2:把图片变成块状元素
.pic-container {
.pic {
display: block; //inline-block不可以
width: 100%;
}
}
1.3:设置图片的vertical-align
修改为vertical-align: middle使其相对容器中部对齐即居中对齐,这样图片就会充满整个容器
.pic-container{
.pic{
vertical-align: middle;
width: 100%;
}
}
1.4:把图片父容器行高置为 0
.pic-container {
line-height: 0;
.pic {
width: 100%;
}
}
1.5:把图片父容器文字大小置为 0
.pic-container {
font-size: 0;
.pic {
width: 100%;
}
}
background-size中cover和contain属性
cover:把背景图片扩展至足够大,以使背景图像完全覆盖背景区域。背景图片的某些部分也许无法显示在背景定位区域中
contain: 把图像扩展至最大尺寸,以使其宽度和高度完全适应内容区域
参考 CSS background-size 参考手册
nth-child(n)
选择器匹配属于其父元素的第 n 个子元素,不论元素的类型(第一个子元素的下标是 1)
如:p:nth-child(2) 匹配父元素的第二个子元素,并且第二个子元素是p标签,若不是则匹配失败
如::nth-child(5) 匹配父元素的第五个子元素,无论类型
1.1:Odd 和 even 是可用于匹配下标是奇数或偶数的子元素的关键词(第一个子元素的下标是 1)
在这里,我们为奇数和偶数 p 元素指定两种不同的背景色:
p:nth-child(odd) { /*也可使用类名 如: .class:nth-child(){}*/
background: #ff0000;
p:nth-child(even) {
background: #0000ff;
}
1.2:使用公式 (an + b)。描述:表示周期的长度,n 是计数器(从 0 开始,子元素下标从 1 开始),b 是偏移值
在这里,我们指定了下标是 3 的倍数的所有 p 元素的背景色
p:nth-child(3n+0){
background:#ff0000;
}
nth-of-type(n)
选择器匹配属于其父元素的 特定类型 的第 n 个子元素
如:p:nth-of-type(2) 匹配父元素内第二个 P 元素,如
<h1>这是标题</h1>
<p>第一个段落</p>
<p>第二个段落</p> //被选中,因为是特定类型下的第 n 个子元素
<p>第三个段落</p>
1.1:Odd 和 even 是可用于匹配下标是奇数或偶数的子元素的关键词(第一个子元素的下标是 1)。
在这里,我们为奇数和偶数 p 元素指定两种不同的背景色:
p:nth-of-type(odd){
background:#ff0000;
}
p:nth-of-type(even){
background:#0000ff;
}
1.2:使用公式 (an + b)。描述:表示周期的长度,n 是计数器(从 0 开始),b 是偏移值。
在这里,我们指定了下标是 3 的倍数的所有 p 元素的背景色:
p:nth-of-type(3n+0){
background:#ff0000;
}
nth-child 和 nth-of-type 区别
nth-child:不区分类型,匹配的是其父元素内的第 n 个子元素(子元素下标从1开始)
nth-of-type:区分类型,匹配的是其父元素内 特定类型 的第 n 个子元素(子元素下标从1开始)
this.$route和this.$router区别
this.$route:路由信息对象,包含当前路由的name、params、path、query等属性
this.$router:等同于全局路由实例对象,因为在 Vue 实例内部,可通过 this.$router 访问路由实例,用于路由跳转
如图:
Vue给对象添加属性
vm.$set( target, propertyName/index, value )
this.$set(obj, 'propertyName', 'lucy')
Vue删除对象属性
vm.$delete( target, propertyName/index )
this.$delete(obj, 'propertyName')
Vue操作数组数据
增
this.list.unshift({name: "宙斯"}) //添加到数组头部
this.list.push({name: "宙斯"}) //添加到数组尾部
删
this.list.shift() //删除数组头部一个元素
this.list.pop() //删除数组尾部一个元素
改
this.$set(this.list, 0, {name:"宙斯"}); //修改数组角标为0的数据
发送网络请求时注意事项
1.1:当字段值是undefined时,在请求时如post中不会出现该字段
id: undefined; //不会出现在请求携带的参数中
1.2:当字段值是""时,在请求时如post中会出现该字段
id: ""; //在请求携带的中会出现
CSS 盒子模型(Box Model)
CSS盒模型本质上是一个盒子,它包括:边距margin、边框border、填充padding、实际内容content。
1.1:盒模型有两种
- 标准盒模型:width和height等于实际内容(content)的宽高
- IE盒模型,width和height等于content+padding+border的总宽高。
1.2:css设置两种盒模型
- box-sizing: content-box; //标准盒模型
- box-sizing: border-box; //IE盒模型
绝对定位元素不设置偏移属性
如果绝对元素不设置偏移属性,则他的位置原地不动,但完全脱离文档流,并覆盖默认文档流中的元素
作用:
比如一个悬浮框想在一个列表下方根据状态显示或隐藏,但列表高度不固定,则使用绝对定位但不设置偏移属性最合适。
如果想让悬浮框在列表下方右边显示怎么做?
可以只添加一个属性 right: 0; 则悬浮框就会出现在列表下方右边。
ES6中let、const和var的区别
-
var: 函数作用域、变量会提升、根级变量会挂载到window
-
let: 块级作用域、不会变量提升、根级变量会挂载到window、同一作用域内不能重复定义同名变量、有暂时性死区
-
const: 和let一样,不同的是声明后必须赋值,赋值后不能修改
暂时性死区
var a = 1;
if (true) {
a = 2; // ReferenceError
let a;
}
- 如果块级作用域中有let或const声明的变量,则该变量就会绑定这个块级作用域,作用域内的该变量不会提升,但它已经存在,只是声明之后才可使用,这被称为暂时性死区。并且作用域内该变量也不受外部变量影响
- 如果块级作用域内查找不到存在的变量,则还是会向外层作用域查找
暂时性死区 让typeof不再绝对安全
if (true) {
console.log(typeof a); // ReferenceError
let a = 1;
}
事件捕获、冒泡,事件委托
事件捕获:从document开始触发事件一层一层传递并触发事件,直到当前元素事件触发为止
事件冒泡:从当前元素触发事件并向上级一层一层传递并触发事件,直到document为止
事件委托:基于事件冒泡实现,通过父元素来监听子元素冒泡上来的事件
通过 addEventListener() 的第三个属性设置事件类型,true:表示事件捕获、false:表示事件冒泡,默认为false
阻止事件冒泡:event.stopPropagation()
阻止事件默认行为:event.preventDefault()
数组去重
1:使用数组filter和indexOf方法
let arr = [1, 2, 3, 2, 4, 5, 3];
let newArr = arr.filter((item, index, arr) =>{
return arr.indexOf(item) === index;
});
console.log(newArr); //[1, 2, 3, 4, 5]
2:使用ES6的Set (元素唯一特性)
let arr = [1, 2, 3, 2, 4, 5, 3];
let set = new Set(arr);
let newArr = [...set];
console.log(newArr); //[1, 2, 3, 4, 5]
Set与Array转换
1:Set转Array
let arr = [1, 2, 3];
let set = new Set(arr);
let newArr = [...set];
或者
let arr = [1, 2, 3];
let set = new Set(arr);
let newArr = Array.from(set);
from说明
Array.from() 方法从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例
2:Array转Set
let arr = [1, 2, 3];
let set = new Set(arr);
图片加载前占位
<div class="wrapper">
<img class="img"
src="http://mp-piao-admincp.qunarzz.com/mp_piao_admin_mp_piao_admin/admin/20192/c64e6f7308f67f0862adb64b9d9fcff0.jpg_750x200_37c4c320.jpg"
ref="img"
@load="loadSuccess">
</div>
.wrapper {
height: 0;
padding-bottom: 26%;
overflow: hidden;
background-color: #eee;
.img {
width: 100%;
}
}
- 1:各个banner图片宽高比一致
- 2:给img父元素高度设置为0,通过padding-bottom撑开其父元素
如上方img标签内src的链接图片,它的 宽 x 高= 750 x 200,宽高比约等于10 : 2.6
所以img父元素通过 padding-bottom:26% 来占位高度
提示
padding和margin的百分比是 基于其父元素的宽度的百分比的内边距,也就是基于其父元素的内容宽度,不包括父元素的padding、border、margin的宽度。
var a=b=1 和 var a=1,b=1 区别
function test(ab = 1) {
var a = b = 1
let a1 = b1 = 1
const a2 = b2 = 1
var a3 = 1, b3 = 1
let a4 = 1, b4 = 1
const a5 = 1, b5 = 1
}
test()
console.log(b, b1, b2) //1 1 1
console.log(window)
// console.log(a) //报错 Uncaught ReferenceError: a is not defined
// console.log(ab) //报错 Uncaught ReferenceError: ab is not defined
window对象
由打印的window对象图可知,调用test函数后会给window也就是全局添加b、b1、b2三个全局变量,其他变量如:ab(形参)、a、a3、b3等都属于test函数的局部变量,不能在全局访问
Object.freeze冻结
如果确定data中的数据不会发生变化如(对象、数组、Number、Boolean、String),那么可以使用Object.freeze冻结数据,使Vue不对该数据设置响应式监听,以便提高性能
Object.freeze的原理就是把数据上值的这三个属性 configurable、enumerable、writable都设置为false。以便对数据不可配置、不可枚举、不可修改
注意
- Object.freeze一般只冻结引用数据,也就是堆内存中的数据
- 当冻结Number、Boolean、String时,数据也变成非响应式的,但当重新赋值时,就又会变成响应式
data中的冻结数据
obj:Object.freeze({
num:1
}),
arr:Object.freeze([1,2,3]),
此时通过下面这种方式都无法修改数据
this.obj.num = 30;
this.$set(this.arr, 1, 20)
但可以通过修改obj和arr的引用来修改数
this.obj = Object.freeze({
num:40
}),
this.arr = Object.freeze([10,20,30])
也可以再变成响应式对象
this.obj = {
num: 100,
}
this.arr = [100, 200, 300]
vueRouter的params、query传参 动态路由匹配 动态路径参数
通过params传递参数
命名路由 userId不会出现在url上
this.$router.push({ name: 'user', params: { userId: '123' }})
获取传递的参数
this.$route.params.userId
- 只能使用name,不能使用path,因为使用path后params会被忽略
- 参数不会显示在路径上
- 浏览器强制刷新参数会被清空
注意:name的值是在router路由里定义的name值,而不是组件中定义的name值
通过query传递参数
带查询参数,变成 /register?plan=private
this.$router.push({name:'register',query:{ plan: 'private' }})
带查询参数,变成 /register?plan=private
this.$router.push({ path: '/register', query: { plan: 'private' }})
获取参数
this.$route.query.plan
- 可以使用name,也可以使用path
- 参数会显示在路径上
- 浏览器强制刷新参数不会丢失
动态路由匹配
记住: 参数或查询的改变并不会触发进入/离开的导航守卫
动态路径参数 以冒号开头,如 { path: ‘/user/:id’, component: xxx },使用动态路径参数可以达到动态路由匹配的效果
通过 /:id 的这种动态路由匹配时,当匹配到一个路由时,参数值通过 this.$route.params.id 获取到
当使用路由参数时,例如从 /user/foo 导航到 /user/bar,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。
复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch (监测变化) $route 对象:
watch: {
'$route' (to, from) {
// 对路由变化作出响应...
}
}
或者使用 2.2 中引入的 beforeRouteUpdate 导航守卫:
beforeRouteUpdate (to, from, next) {
// react to route changes...
// don't forget to call next() 不要忘记调用next
}
动态路径参数的跳转方法
如:
{ path: '/user/:userId', component: xxx }
1:命名路由跳转
this.$router.push({name: 'user',params: { userId: 123, sex:'man' }}) //匹配为/user/123
params中userId必须和上面路径中的 userId(/user/:userId)名一直,userId位置随意,还可以传递其他参数
2:带查询参数跳转
this.$router.push({path: '/user/123',query: { sex: 'man' }}) //匹配为 /user/123?sex=max
path路径格式和路由里定义的一样,:userId匹配123,同时路径上会添加sex=man属性
函数中返回字面量对象
function test(age){
return {
name:"liu"
}
}
let obj1 = test(10)
obj1.name = 'y'
let obj2 = test(20)
obj2.name = 'z'
console.log(obj1 == obj2) // false
console.log(obj1) // {name: "y"}
console.log(obj2) // {name: "2"}
说明:函数中返回字面量对象时,每一次调用都会创建返回一个新的对象
数组内String转Number
let arr = ['3', '21', 10, 40, '22','', null, undefined]
let numberArr = Array.from(arr, n => n - 0)
console.log(numberArr)
// 打印结果: [3, 21, 10, 40, 22, 0, 0, NaN]
数组内Number转String
let arr = ['3', '21', 10, 40, '22','', null, undefined]
let stringArr = Array.from(arr, n => n + '')
console.log(stringArr)
// 打印结果: ["3", "21", "10", "40", "22", "", "null", "undefined"]
package.json中符合说明
一个完整的版本号组表示为: [主要版本号,次要版本号,补丁版本号]
波浪符号(~):主要版本和次要版本号不变,只会自动更新补丁版本号。如"element-ui": “~2.5.2” ,只会自动更新到2.5.x的最新版本,即2.5.2<=element-ui版本号<2.6.0
插入符号(^):主要版本号不变,会自动更新次要版本号和补丁版本号。如"element-ui": "^2.5.2"只会自动更新到2.x.x的最新版本,即2.5.2<=element-ui版本号<3.0.0
对象深克隆
function deepClone(obj) {
//判断深拷贝的是数组还是对象
var objClone = Array.isArray(obj) ? [] : {};
//进行深拷贝的不能为空,并且是对象或者是数组
if (obj && typeof obj === "object") {
for (key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === "object") {
objClone[key] = deepClone(obj[key]);
} else {
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
多维数组打平
function flattenMd(arr){
var result=[]
function flatten(arr){
for (var i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
flatten(arr[i]);
}else{
result.push(arr[i]);
}
}
}
flatten(arr);
return result;
}