本文仅作为本人复习梳理之用
参考:
作者:阳呀呀 juejin.cn/post/684490…
作者:张张-💫 链接:juejin.cn/post/684490…
小明同学呦 juejin.cn/post/684490…
blog.poetries.top/FE-Intervie… 淘淘笙悦 www.jianshu.com/p/c8b86b09d… yck segmentfault.com/a/119000001… 安歌 juejin.cn/post/694786…
CSS
盒模型
盒模型由margin、border、padding、content组成,分为标准盒模型和怪异盒模型,标准盒模型的宽度=content宽+左右padding,怪异盒模型的宽度=左右border+左右padding+content宽。
垂直居中的方法
1.将父元素设置成表格,子元素设置成表格元素
#parent {
display: table;
}
#child {
display: table-cell;
vertical-align: middle; //text-align: center;
}
Internet Explorer(甚至 IE8 beta)中无效
2.css2属性
//#parent {text-align: center;}
#child{
display: inline-block;
vertical-align: middle;
}
#cbrother{
display: inline-block; width: 0;
heigh: 100%
vertical-align: middle;
}
parent{
width: 0;
heigh: 100%
vertical-align: middle;
}
父相子绝
3.定位 + margin
parent{
position: relative;
}
#child {
position: absolute;
top: 50%;//left
height: 240px;
margin-top: -120px; /* negative half of the height */
}
4.定位
#parent{
position: relative;
}
#child {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
IE(IE8 beta)中无效
5.定位+动画
#parent{
position: relative;
}
#child{
position: absolute;
top: 50%;
transform: translateY(-50%);
}
6.flex布局
#parent{
display:flex;/*Flex布局*/
display: -webkit-flex; /* Safari */
align-items:center;/*指定垂直居中*/
}
三列布局
圣杯布局的思路是先将中列的宽度设为100%,然后用margin来控制左列和右列
双飞翼布局是先用margin控制中列(设置最小值),左右两侧留出空白区域,
然后再用margin来控制左列和右列填充
1、圣杯布局
圣杯布局将页面分三栏,页面布局为middle、left和right,middle的宽度为
100%,本来left和right会被挤到第二行,通过margin-left控制left和right
的位置在第一行左右两边,达到左右固定,中间自适应的效果。
<style type="text/css">
* {
margin: 0;
padding: 0;
}
.main>div {
/*在给定的祖先元素下匹配所有的后代元素,main下的div全部左浮动*/
float: left;
}
.left {
width: 200px;
background: red;
margin-left: -100%;
}
.right {
width: 200px;
background: blue;
margin-left: -200px;
}
.middle {
width: 100%;
background: yellow;
}
.content {
margin-left: 200px;
margin-right: 200px;
}
</style>
<body>
<div class="main">
<div class="middle">
<div class="content">
中间
</div>
</div>
<div class="left">
左边
</div>
<div class="right">
右边
</div>
</div>
</body>
2、双飞翼布局
<style>
body {
min-width: 500px;
}
#container {
width: 100%;
}
.column {
float: left;
}
#center {
margin-left: 200px;
margin-right: 150px;
}
#left {
width: 200px;
margin-left: -100%;
}
#right {
width: 150px;
margin-left: -150px;
}
#footer {
clear: both;
}
</style>
<body>
<div id="header"></div>
<div id="container" class="column">
<div id="center"></div>
</div>
<div id="left" class="column"></div>
<div id="right" class="column"></div>
<div id="footer"></div>
<body>
3.flex布局
左右固定宽度,中间设为flex:1
<style type="text/css">
html*{
margin: 0;
padding: 0;
}
.container{
display: flex;
}
.left{
background-color: aqua;
width: 300px;
height: 100px;
}
.center{
height: 100px;
flex: 1;
background: #f296ff;
}
.right{
height: 100px;
background-color: #6ee28d;
width: 300px;
}
</style>
<body>
<!-- 已知高度,写出三栏布局,左右宽度300px,中间自适应-->
<div class="container">
<div class="left"></div>
<div class="center"></div>
<div class="right"></div>
</div>
</body>
选择器权重计算方式
- !important 权重始终最高。
- 内联样式权重为1000。
- ID选择器权重为0100。
- 类,伪类和属性选择器权重为0010。
- 元素选择器和伪元素选择器权重为0001。
- 通配符、子选择器、相邻选择器等的。如*、>、+,权重为0000。
- 继承的样式权重继承自父级元素。
清除浮动的方法(防止高度塌陷的方法)
1.给父元素添加声明overflow:hidden; (触发一个BFC)
缺点:隐藏内容区以外的元素
2.在浮动元素下方添加空div,并给该元素添加声明:
div{clear:both; height:0; overflow:hidden;}
缺点:造成代码的冗余
3.万能清除浮动法(给父元素引用)
选择符:after{content:"";clear:both;display:block;height:0;
overflow:hidden;visibility:hidden; font-size:1px;}
BFC
1.什么是BFC
BFC(Block formatting context)直译为“块级格式化上下文”。它是一个独立的渲染区域, 只有Block-level box(块)参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。
2.怎么触发BFC
- float属性不为none
- position为absolute或fixed
- display为inline-block, table-cell, table-caption, flex, inline-flex
- overflow不为visible
3.BFC可以解决哪些问题
- 自适应两栏布局
- 清除内部浮动
- 防止margin上下重叠
如何实现一个自适应的正方形
.box{
width: 20%;//width:20vw也可以
height: 20vw;
background: pink;
}
如何用css实现一个三角形
<style>
.box {
height: 0;
width: 0;
overflow: hidden;
/* 这里设置overflow, font-size, line-height */
font-size: 0;
/*是因为, 虽然宽高度为0, 但在IE6下会具有默认的 */
line-height: 0;
/* 字体大小和行高, 导致盒子呈现被撑开的长矩形 */
border-color: #FF9600 #3366ff #12ad2a #f0eb7a;
border-style: solid;
border-width: 20px;
}
</style>
<body>
<div class="box"></div>
</body>
em和rem的区别
- rem等于html的font-size的大小
- em等于父级元素的字体大小
link与@import的区别
- link是HTML方式, @import是CSS方式,link标签除了可以加载CSS外,还可以做很多其它的事情,比如定义rel连接属性等,@import就只能加载CSS。
- 兼容性的差别,@import是CSS2.1提出的,只在IE5以上的才能识识别,而link标签无此问题。
- link引用的CSS会同时被加载,而@import引用的CSS 会等到页面全部被下载完再被加载,页面样式会短暂失效。
- 当使用javascript控制dom去改变样式的时候,只能使用link标签。
文本省略号显示
单行
text-overflow属性仅是...,要实现溢出时产生省略号的效果还需定义:
1、容器宽度:width:value;
2、强制文本在一行内显示:white-space:nowrap;
3、溢出内容为隐藏:overflow:hidden;
4、溢出文本显示省略号:text-overflow:ellipsis;
多行
overflow: hidden;
display: -webkit-box;// 将对象作为弹性伸缩盒子模型显示。
text-overflow: ellipsis;
-webkit-line-clamp: 2;//显示的行数
-webkit-box-orient: vertical; // 从上到下垂直排列子元素(设置伸缩盒子的子元素排列方式)
哪些元素可以继承
- 内联元素可继承:letter-spacing、word-spacing、white-space、line-height、color、font-family、font-size、font-style、font-weight、text- decoration、text-transform.
- 块状元素可继承:text-indent和text-align。
- 列表元素可继承:list-style、list-style-type、list-style-position、list-style-image。
- 表格元素可继承:border-collapse
谷歌浏览器字体12px以下显示
font-size: 10px;
-webkit-transform-origin-x: 0;
// 解决字体缩小后的偏移问题
-webkit-transform: scale(0.8);
css移动端0.5x的直线怎么实现
div::before {
content: "";
dispaly: block;
height: 1px;
width: 200%;
transform: scale(.5);
background: red;
position: absloute;
left: 50%;
}
js
var,let,conse的区别
- var声明的范围是函数作用域,let声明的范围是块级作用域
- var可以重复声明,JavaScript引擎会自动将多余的声明在作用域顶部合并为一个声明,let不能重复声明
- var声明的变量会提升到函数作用域顶部
- let声明的变量不会在作用域中被提升,JavaScript引擎会注意到块后面的let声明,在此之前不能以任何方式引用未声明的变量,在let声明之前的执行瞬间被称为“暂时性死区”,会抛出referenceError
- 使用var关键字在全局作用域中声明的变量会成为window对象的属性,let不会
- const 的行为与 let 基本一致,唯一重要区别是它声明的同时必须初始化。
手写题
防抖和节流
- 防抖:连续触发事件,函数在N秒之后只执行一次
function debounce(func, delay) {
let timer = null //借助闭包
return function() {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
func.apply(this, args)
}, delay) // 简化写法
}
}
- 节流:连续触发事件,函数在N秒内只执行一次
function throttle(func, wait) {
let timeout
return function() {
if (!timeout) {
timeout = setTimeout(() => {
func.apply(this, args)
timeout = null
}, wait)
}
}
}
赋值、浅拷贝和深拷贝
1.赋值:
var a = [1, 2, 3, 4, 5];
var b = a;
a[0] = 2;
console.log(a);//[2, 2, 3, 4, 5]
console.log(b);//[2, 2, 3, 4, 5]
//ab指向同一个内存地址
//b会随着a的变化而变化
2. 浅拷贝是对对象第一层的拷贝
Object.assign()
是一种对象浅拷贝,只能拷贝第一层,其他的只能是引用
var obj1 = {a: 1, b: 2, c: {d: 4, e: 5}};
var obj2 = Object.assign({}, obj1);
console.log(obj1.c === obj2.c);//true
3. 深拷贝的实现
简单的深拷贝
var a = [1, 2, 3, 4, 5];
var b = [];
forEach(element => {
b.push(element);
})
利用JSON深拷贝
var obj1 = {a: 1, b: 2, c: {d: 4, e: 5}};
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj1.c === obj2.c); //false,此时已经是对obj1.c 的整个复制,而不是只引用了地址
数组去重、数组排序
- 数组去重
方法一
function norepeat(arr) {
for (var i=0;i<arr.length;i++) {
for (var j=0;j<arr.length;j++) {
if (arr[i] == arr[j] && i !=j) {
arr.splice(j,1);
}
}
}
return arr;
}
方法二
function noRepeat(arr) {
return arr.filter(function(item, index) {
return arr.indexOf(item, 0) === index;
});
}
- 数组排序
- 冒泡排序
function bubbleSort(arr) {
var tem;
for (var i = 0; i < arr.length - 1; i++) {
for (var j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j+1]) {
tem = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tem;
}
}
}
return arr;
}
- 选择排序
function selectionSort(arr) {
var index, temp;
for (var i = 0; i < arr.length - 1; i++) {
index = i;
for (var j = i + 1; j < arr.length; j++) {
if (arr[index] > arr[j]) {
index = j;
}
if (index > i) {
temp = arr[index];
arr[index] = arr[i];
arr[i] = temp;
}
}
}
return arr;
}
}
继承
- 构造函数继承
构造函数继承无法继承原型中的方法
function Cat(n, m) {
this.name = n;
this.color =m;
this.trait = function () {
console.log('卖萌~');
}
Cat.prototype.behaviour = function (){
console.log('抓老鼠');
}
}
function Dog(n,c,f) {
this.food = f;
Cat.call(this,n,c);
}
var dog1 = new Dog('二哈','yellow','shi');
console.log(dog1.name); // 二哈
dog1.trait(); // 卖萌
dog1.behaviour(); // 报错 dog1.behaviour is not a function
- 原型链继承
原型链继承只能继承原型上的方法,无法继承自有方法
function Cat(n,c) {
this.name = n;
this.color = c;
this.trait = function (){
console.log('卖萌~');
}
}
Cat.prototype.behaviour = function () {
console.log('抓老鼠');
}
function Dog(n,c,f) {
this.food = f;
}
Dog.prototype = Object.create(Cat.prototype);
Dog.prototype.constructor = Dog;
var dog1 = new Dog('二哈', 'yellow', '骨头');
//原型链:dog1.__proto__->->Cat.prototype->Object.prototype->null
console.log(dog1.name); // undefined
console.log(dog1.food); // 骨头
dog1.trait(); // dog1.trait is not a function
dog1.behaviour(); // 抓老鼠
- 混合继承
function Cat(n,c) {
this.name = n;
this.color = c;
this.trait = function () {
console.log('卖萌~');
}
}
Cat.prototype.behaviour = function () {
console.log('抓老鼠');
}
function Dog(n,c,f) {
this.food = f;
Cat.call(this,n,c);
}
Dog.prototype = Object.create(Cat.prototype);
Dog.prototype.constructor = Dog;
var dog1=new Dog('二哈', 'yellow', '骨头');
console.log(dog1.name);// 二哈
console.log(dog1.food);// 骨头
dog1.trait();// 卖萌
dog1.behaviour();// 抓老鼠
console.log(dog1.constructor);// Dog
Promise
- promise
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
var num = parseInt(Math.random() * 10)
if (num > 5) {
resolve("1s请求成功")
} else {
reject("1s请求失败")
}
}, 1000)
}).then(data => {
console.log(data)
}).catch(data => {
console.log(data)
})
- promise.all 和 promise.race
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
var num = parseInt(Math.random() * 10)
if (num > 3) {
resolve("2s请求成功")
} else {
reject("2s请求失败")
}
}, 2000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
var num = parseInt(Math.random() * 10)
if (num > 3) {
resolve("1s请求成功")
} else {
reject("1s请求失败")
}
}, 1000)
})
let p3 = new Promise((resolve, reject) => {
setTimeout(() => {
var num = parseInt(Math.random() * 10)
if (num > 5) {
resolve("3s请求成功")
} else {
reject("3s请求失败")
}
}, 3000)
})
//Promise.all,相当于后一个promise写在前一个promise的then里,
所以只有前一个promise请求成功,才会执行后一个promise,全部
请求成功时,返回一个请求成功的结果数组,请求失败时,则会抛
出请求失败的那个Promise的结果
Promise.all([p1, p2, p3]).then(data => {
console.log(data)
}).catch(data => {
console.log(data)
})
//["2s请求成功", "1s请求成功", "3s请求成功"] 或 ns请求失败
// Promise.race只会捕获最先执行完成的Promise
Promise.race([p1, p2, p3]).then(data => {
console.log(data)
}).catch(data => {
console.log(data)
})
//1s请求成功 或 1s请求失败
promise、async await
async/await是在Promise之后产生的,它和Promise诞生的目的都是为了解决“回调地狱”
- async/await函数是异步代码的新方式
- async/await是基于promise实现的
- async/await使异步代码更像同步代码
- await 只能在async函数中使用,不能再普通函数中使用,要成对出现
- 默认返回一个promise实例,不能被改变
- await下面的代码是异步,后面的代码是同步的
- async 函数就是 Generator 函数的语法糖。
详细了解async await可参考:www.jianshu.com/p/2afb088ab…
如果async函数中是return一个值,这个值就是Promise对象中resolve的值;
如果async函数中是throw一个值,这个值就是Promise对象中reject的值。
async function imAsync(num) {
if (num > 0) {
return num // 这里相当于resolve(num)
} else {
throw num // 这里相当于reject(num)
}
}
//所以这个函数相当于
function imAsync(num) {
return new Promise((resolve, reject) => {
if (num > 0) {
resolve(num)
} else {
reject(num)
}
})
}
await的作用是暂停当前async函数的执行,等待后面的Promise的计算结果返回以后再继续执行当前的async函数
(async function () {
console.log(1);
await new Promise(resolve => {
//执行到这一步会先暂停 async函数的执行,先执行await后的promise
//所以打印结果是先打印1,1s后打印2-3
"use strict";
setTimeout(() => {
console.log(2);
resolve();
}, 1000);
});
console.log(3);
}())
正则实现一个邮箱
var email = /^[a-z0-9A-z\.\-\_]{1,14}@[a-z0-9A-z\.\-\_]{1,14}\.[a-z]{1,4}$/
浏览器相关
get和post的区别
- get参数通过url传递,post放在请求体(request body)中;
- get请求在url传递的参数有长度限制,而post没有;
- get比post更不安全,因为参数直接显示在url地址中,所以不能传递敏感数据;
- get请求浏览器会主动缓存,而post不会;
- get请求参数会使用保存在浏览器中的历史记录(使用cookie),而post请求不会;
- get和post本质上都是tcp连接。
ajax
- 使用ajax一共有4个步骤:
- 1.创建ajax
- 2.连接服务器
- 3.发送请求
- 4.接受返回值。
- readyState 属性存有XMLHttpRequest对象的状态
readyState 会从 0 到 4 发生变化:
- 0: 请求未初始化
- 1: 服务器连接已建立
- 2: 请求已接收
- 3: 请求处理中
- 4: 请求已完成
当 readyState 改变时就会触发 onreadystatechange 事件
status:http请求的状态码 状态码代表着http请求是成功还是失败等信息。
- 下面是常见的HTTP状态码(HTTP Status Code):
- 200:请求成功
- 301:网页被重定向到其它URL
- 304:文件未被修改,使用缓存资源
- 404:找不到此网页(指定的资源)
- 500:服务器内部错误
function ajax(options){
var xhr = null;
var params = formsParams(options.data);
//创建对象
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest()
} else {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
// 连接
if(options.type == "GET"){
xhr.open(options.type,options.url + "?"+ params,options.async);
//get请求会读取页面缓存,请求的地址没有改变,则get请求会直接从缓存拿数据,
//可以在params上拼接一个时间戳解决缓存问题 t=new Date().getTime()
xhr.send(null)
} else if(options.type == "POST"){
xhr.open(options.type,options.url,options.async);
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xhr.send(params);
}
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
options.success(xhr.responseText);
}
}
function formsParams(data){
var arr = [];
for(var prop in data){
arr.push(prop + "=" + data[prop]);
}
return arr.join("&");
}
}
ajax({
url : "a.php", // url---->地址
type : "POST", // type ---> 请求方式
async : true, // async----> 同步:false,异步:true
data : { //传入信息
name : "张三",
age : 18
},
success : function(data){ //返回接受信息
console.log(data);
}
})
jsonp
- jsonp跨域就是利用script标签的跨域能力请求资源
- 利用js创建一个script标签,把json的url赋给script的scr属性,把这个script插入到页面里,让浏览器去跨域获取资源
- callback是页面存在的回调方法,参数就是想得到的json
- 回调方法要遵从服务端的约定一般是用 callback 或者 cb
- 注意:jsonp只针对get请求
<body>
<input class="ipt"/>
<ul class="list"></ul>
</body>
<script>
var ipt = document.querySelector('.ipt');
var list = document.querySelector('.list');
var Script = null;
ipt.onkeyup = function () {
if (Script) {
document.body.removeChild(Script);
}
Script = document.createElement('script');
Script.src = 'http://suggestion.baidu.com/su?cb=myCb&wd='+ipt.value;
//文档接口要求传入两个查询字段 cb:回调函数myCb wd:关键字
document.body.appendChild(Script);
}
function myCb(json) {//接收处理数据
list.innerHTML = '';
for(var i = 0, len = json.s.length; i < len; i++){
list.innerHTML += '<li>'+ json.s[i] +'</li>';
}
}
javascript
闭包
当一个函数能够记住并访问到其所在的词法作用域及作用域链,特别强调是在其定义的作用域外进行的访问,此时该函数和其上层执行上下文共同构成闭包。
需要明确的几点:
- 闭包一定是函数对象
- 函数内保持对上层作用域的引用
- 闭包和词法作用域、作用域链、垃圾回收机制等息息相关
- 当函数在其定义的作用域外进行访问时,才产生闭包
- 闭包是由该函数和其上层执行上下文共同构成
作用域和作用域链
- 作用域
- 词法作用域,也叫静态作用域,它的作用域是指在词法分析阶段就确定了,不会改变。
- 动态作用域,是在运行时根据程序的流程信息来动态确定的。
词法作用域关注函数在何处声明,而动态作用域关注函数从何处调用。
- 作用域链
- 作用域链:本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。 (简而言之,作用域链,就是在当前作用域中如果没有该属性(局部变量)则向上一层作用域中寻找,一直到最上层,也就是window)
原型和原型链
- prototype(原型)
- 每一个函数,解析器都会向函数中添加一个prototype属性,这个属性对应着一个对象,这个对象就叫做原型对象。
- __proto__属性
- 每个对象都有一个隐藏属性__proto__,用于访问创建它的构造函数的原型。属性__proto__非官方标准属性,但主流的浏览器基本都支持
- 原型链
- 访问一个对象属性时,如果在当前对象中没有该属性,则向上一层原型对象中寻找,一直找到最外层,也就是null(Object.prototype__proto__指向null)。
原型链是靠_ _ proto _ _来维护的!
es6
proxy
参考:es6.ruanyifeng.com/#docs/proxy
ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。
var proxy = new Proxy(target, handler);
Proxy 对象的所有用法,都是上面这种形式,不同的只是handler参数的写法。其中,new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。
webpack
用过哪些loader和plugin
- loader
- style-loader: 将模块的导出作为样式添加到DOM中
- css-loader: 解析css文件后,使用import导入,并且返回css代码
- less/sass-loader:加载和转译less/sass文件
- postcss-loader: 给css代码添加浏览器兼容代码
- url/file-loader:用于加载图片
- babel-loader:将代码转译成es5
- vue-loader:允许以单文件组件的格式撰写 Vue 组件(必备)
- plugin
- UglifyjsWebpackPlugin:压缩javascript代码
- HtmlWebpackPlugin:打包HTML代码
- babel-plugin-component:按需引入组件(element)
- babel-plugin-import:按需引入组件(vant)
vue
vue生命周期
var vm = new Vue({
el: '#app',
data: {
title: '',
},
//1.孕育生命,初始化操作,主要是劫持data,设置get和set属性
beforeCreate: function () {
console.log('beforeCreate', this.$data, this.$el);//undefined undefined
},
//2.实例化完成
created: function () {
setInterval( () => {
// this.title = Math.random();
}, 2000)
console.log('created', this.$data, this.$el);
},//data undefined
//3.挂载前
beforeMount: function () {
console.log('beforeMount', this.$data, this.$el);
},//data el(<p>{{ title }}</p>)
//4.挂载元素,获取DOM节点,把编译结果放在页面上,但还没有渲染。
mounted: function () {
console.log('mounted', this.$data, this.$el);
},//data el(<p></p>)
5.可以监听到data的变化,但是view层没有被重新渲染。
beforeUpdate: function(){
console.log('beforeUpdate', this.$data);
},
6.view层才被重新渲染,数据更新。
updated: function(){
console.log('update', this.$data);
},
7.钩子函数在实例销毁之前调用。在这一步,实例仍然完全可用。
beforeDestroy: function () {
console.log('beforeDestroy');
}
8.Vue实例销毁后调用,Vue实例指示的所有东西都会解绑定
Destroyed: function () {
console.log('Destroyed');
}
})
vue的单项数据流
- 什么是单向数据流
- 所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
- 额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。 2.两种常见的试图改变prop的情形
- 这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data 属性并将这个 prop 用作其初始值
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}
- 这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
MVVM
M - Model,代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑
V - View,视图层,代表 UI 组件,它负责将数据模型转化为 UI 展现出来
VM - ViewModel,业务逻辑层,监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步 View 和 Model 的对象,连接 Model 和 View
- MVVM 将数据双向绑定(data-binding)作为核心思想,View 和 Model 之间没有联系,它们通过 ViewModel 这个桥梁进行交互。
- Model 和 ViewModel 之间的交互是双向的,因此 View 的变化会自动同步到 Model,而 Model 的变化也会立即反映到 View 上显示。
- 当用户操作 View,ViewModel 感知到变化,然后通知 Model 发生相应改变;反之当 Model 发生改变,ViewModel 也能感知到变化,使 View 作出相应更新。
参考:www.jianshu.com/p/bcad6a5a6…
简单的数据双向绑定实现
<div id="app">
<input v-model="msg" />
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: ''
}
});
</script>
vue中 key 值的作用
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。key的作用让每个item有一个唯一的识别身份,可以下标值index或者id, 主要是为了vue精准的追踪到每一个元素,高效的更新虚拟DOM。
作者:zsy氯化钠 链接:www.jianshu.com/p/df75f6061… 来源:简书
key 是为 Vue 中 vnode 的唯一标记,通过这个 key,我们的 diff 操作可以更准确、更快速。Vue 的 diff 过程可以概括为:oldCh 和 newCh 各有两个头尾的变量 oldStartIndex、oldEndIndex 和 newStartIndex、newEndIndex,它们会新节点和旧节点会进行两两对比,即一共有4种比较方式:newStartIndex 和oldStartIndex 、newEndIndex 和 oldEndIndex 、newStartIndex 和 oldEndIndex 、newEndIndex 和 oldStartIndex,如果以上 4 种比较都没匹配,如果设置了key,就会用 key 再进行比较,在比较的过程中,遍历会往中间靠,一旦 StartIdx > EndIdx 表明 oldCh 和 newCh 至少有一个已经遍历完了,就会结束比较。具体有无 key 的 diff 过程,可以查看作者写的另一篇详解虚拟 DOM 的文章《深入剖析:Vue核心之虚拟DOM》
所以 Vue 中 key 的作用是:key 是为 Vue 中 vnode 的唯一标记,通过这个 key,我们的 diff 操作可以更准确、更快速
更准确:因为带 key 就不是就地复用了,在 sameNode 函数a.key === b.key 对比中可以避免就地复用的情况。所以会更加准确。
更快速:利用 key 的唯一性生成 map 对象来获取对应节点,比遍历方式更快,源码如下:
let i, key
const map = {}
for (i = beginIdx; i <= endIdx; ++i) {
key = children[i].key
if (isDef(key)) map[key] = i
}
return map
}
作者:我是你的超级英雄 链接:juejin.cn/post/684490… 来源:掘金
vue初始化页面时在哪个生命周期发请求
- beforeCreate (
$el、$data) 拿不到任何信息,无法篡改数据,一般做loding,这个时候的vue实例还什么都没有,但是$route对象是存在的,可以根据路由信息进行重定向之类的操作 - created (
$el、$data) $el,没有初始化,数据已加载完成,可以篡改数据,并更新,不会触发beforeUpdate,updated,在这结束loading,还做一些初始化,实现函数自执行,$ref属性内容为空数组 - beforeMount ($el、$data) $el已被初始化,,数据已加载完成,可以篡改数据,并更新,不会触发beforeUpdate,updated,在挂载开始之前被调用,beforeMount之前,会找到对应的template,并编译成render函数
- mounted ($el、$data) $el已被初始化,,数据已加载完成,可以篡改数据,并更新,并且触发beforeUpdate,updated,在这发起后端请求,拿回数据,配合路由钩子做一些事情,$ref属性可以访问 综上所述:created可以做简单的请求,但不能操作dom,如需操作dom可以在mounted里发起请求
网络协议
HTTP状态码及其含义
1XX:信息状态码
- 100 Continue 继续,一般在发送post请求时,已发送了http
- header之后服务端将返回此信息,表示确认,之后发送具体参数信息
2XX:成功状态码
- 200 OK 正常返回信息
- 201 Created 请求成功并且服务器创建了新的资源
- 202 Accepted 服务器已接受请求,但尚未处理
3XX:重定向
- 301 Moved Permanently 请求的网页已永久移动到新位置。
- 302 Found 临时性重定向。
- 303 See Other 临时性重定向,且总是使用 GET 请求新的 URI。
- 304 Not Modified 自从上次请求后,请求的网页未修改过。
4XX:客户端错误
- 400 Bad Request 服务器无法理解请求的格式,客户端不应当尝试再次使用相同的内容发起请求。
- 401 Unauthorized 请求未授权。
- 403 Forbidden 禁止访问。
- 404 Not Found 找不到如何与 URI 相匹配的资源。
5XX: 服务器错误
- 500 Internal Server Error 最常见的服务器端错误。
- 503 Service Unavailable 服务器端暂时无法处理请求(可能是过载或维护)。
性能优化
- 减少 HTTP 请求数
- 减少 DNS 查询
- 使用 CDN
- 避免重定向
- 图片懒加载
- 减少 DOM 元素数量
- 减少DOM 操作
- 使用外部 JavaScript 和 CSS
- 压缩 JavaScript 、 CSS 、字体、图片等
- 优化 CSS Sprite
- 使用 iconfont
- 字体裁剪
- 多域名分发划分内容到不同域名
- 尽量减少 iframe 使用
- 避免图片 src 为空
- 把样式表放在link 中
- 把JavaScript放在页面底部
本文仅作为本人复习梳理之用