HTML语义化就是让页面内容结构化,它有如下优点:
如:
<header>代表头部
<nav>代表超链接区域
<main>定义文档主要内容
<article>可以表示文章、博客等内容
<aside>通常表示侧边栏或嵌入内容
<footer>代表尾部
有<header>,<footer><aside><nav><video><audio><canvas>等
盒模型分为标准和模型和怪异盒模型(IE盒模型)
box-sizing:content-box //标准盒模型
box-sizing:border-box //怪异盒模型
标准盒模型:元素的宽度等于style里的width+margin+border+padding宽度
如下代码,整个宽高还是120px
div{
box-sizing: content-box;
margin: 10px;
width: 100px;
height: 100px;
padding: 10px;
}
怪异盒模型:元素宽度等于style里的width宽度
如下代码,整个宽高还是100px
div{
box-sizing: border-box;
margin: 10px;
width: 100px;
height: 100px;
padding: 10px;
}
rem是根据根的font-size变化,而em是根据父级的font-size变化
通配符:*
ID选择器:#ID
类选择器:.class
元素选择器:p、a 等
后代选择器:p span、div a 等
伪类选择器:a:hover 等
属性选择器:input[type="text"] 等
!important -> 行内样式 -> #id -> .class -> 元素和伪元素 -> * -> 继承 -> 默认
transition:过渡
transform:旋转,缩放,移动或者倾斜
animation:动画
gradient:渐变
shadow:阴影
border-radius:圆角
默认宽度由父容器决定,默认高度由内容决定,独占一行并且可以设置宽高的元素,我们将其叫做块级元素,例如:
、
、等
相对定位和绝对定位的区别
- position:absolute
绝对定位:是相对于元素最近的已定位的祖先元素
- position:relative
相对定位:相对定位是相对于元素在文档中的初始位置
Flex布局(待补充)
复习链接:https://juejin.im/post/5d428c5451882556dc30535c
BFC
复习链接:https://blog.csdn.net/wyf521995/article/details/103106913
简单描述
- 什么是BFC?
BFC格式化上下文,它是一个独立的渲染区域,让处于 BFC 内部的元素和外部的元素相互隔离,使内外元素的定位不会相互影响
- 如何产生BFC?
display: inline-block position: absolute/fixed
- BFC作用
BFC最大的一个作用就是:在页面上有一个独立隔离容器,容器内的元素和容器外的元素布局不会相互影响
解决上外边距重叠;重叠的两个box都开启bfc; 解决浮动引起高度塌陷;容器盒子开启bfc 解决文字环绕图片;左边图片div,右边文字容器p,将p容器开启bfc
水平垂直居中(待补充)
- Flex布局
display: flex //设置Flex模式 flex-direction: column //决定元素是横排还是竖着排 flex-wrap: wrap //决定元素换行格式 justify-content: space-between //同一排下对齐方式,空格如何隔开各个元素 align-items: center //同一排下元素如何对齐 align-content: space-between //多行对齐方式
- 水平居中
行内元素:display: inline-block; 块级元素:margin: 0 auto; Flex: display: flex; justify-content: center
- 垂直居中
行高 = 元素高:line-height: height flex: display: flex; align-item: center
less,sass,styus三者的区别
- 变量
Sass声明变量必须是『$』开头,后面紧跟变量名和变量值,而且变量名和变量值需要使用冒号:分隔开。
Less 声明变量用『@』开头,其余等同 Sass。
Stylus 中声明变量没有任何限定,结尾的分号可有可无,但变量名和变量值之间必须要有『等号』。
- 作用域
Sass:三者最差,不存在全局变量的概念
Less:最近的一次更新的变量有效,并且会作用于全部的引用!
Stylus:Sass 的处理方式和 Stylus 相同,变量值输出时根据之前最近的一次定义计算,每次引用最近的定义有效;
- 嵌套
三种 css 预编译器的「选择器嵌套」在使用上来说没有任何区别,甚至连引用父级选择器的标记 & 也相同
- 继承
Sass和Stylus的继承非常像,能把一个选择器的所有样式继承到另一个选择器上。使用『@extend』开始,后面接被继承的选择器。Stylus 的继承方式来自 Sass,两者如出一辙。 Less 则又「独树一帜」地用伪类来描述继承关系;
导入@import
Sass 中只能在使用 url() 表达式引入时进行变量插值
$device: mobile; @import url(styles.#{$device}.css);
Less 中可以在字符串中进行插值
@device: mobile; @import "styles.@{device}.css";
Stylus 中在这里插值不管用,但是可以利用其字符串拼接的功能实现
device = "mobile" @import "styles." + device + ".css"
link与@import区别于选择(待补充)
<style type="text/css"> @import url(CSS文件路径地址); </style> <link href="CSSurl路径" rel="stylesheet" type="text/css" /
link功能较多,可以定义 RSS,定义 Rel 等作用,而@import只能用于加载 css;
当解析到link时,页面会同步加载所引的 css,而@import所引用的 css 会等到页面加载完才被加载;
@import需要 IE5 以上才能使用;
link可以使用 js 动态引入,@import不行
多行文本的文本省略号(待补充)
overflow : hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical
JavaScript
JS的几条基本规范
1、不要在同一行声明多个变量 2、请使用===/!==来比较true/false或者数值 3、使用对象字面量替代new Array这种形式 4、不要使用全局变量 5、Switch语句必须带有default分支 6、函数不应该有时候有返回值,有时候没有返回值 7、For循环必须使用大括号 8、IF语句必须使用大括号 9、for-in循环中的变量 应该使用var关键字明确限定作用域,从而避免作用域污染
JS引用方法
行内引入
<body> <input type="button" onclick="alert('行内引入')" value="按钮"/> <button onclick="alert(123)">点击我</button> </body>
内部引入
<script> window.onload = function() { alert("js 内部引入!"); } </script>
外部引入
<body> <div></div> <script type="text/javascript" src="./js/index.js"></script> </body>
注意:
1,不推荐写行内或者HTML中插入
JS的基本数据类型(待补充)
Undefined、Null、Boolean、Number、String、新增:Symbol
数组操作(待补充)
在 JavaScript 中,用得较多的之一无疑是数组操作,这里过一遍数组的一些用法
map: 遍历数组,返回回调返回值组成的新数组 forEach: 无法break,可以用try/catch中throw new Error来停止 filter: 过滤 some: 有一项返回true,则整体为true every: 有一项返回false,则整体为false join: 通过指定连接符生成字符串 push / pop: 末尾推入和弹出,改变原数组, 返回推入/弹出项【有误】 unshift / shift: 头部推入和弹出,改变原数组,返回操作项【有误】 sort(fn) / reverse: 排序与反转,改变原数组 concat: 连接数组,不影响原数组, 浅拷贝 slice(start, end): 返回截断后的新数组,不改变原数组 splice(start, number, value...): 返回删除元素组成的数组,value 为插入项,改变原数组 indexOf / lastIndexOf(value, fromIndex): 查找数组项,返回对应的下标 reduce / reduceRight(fn(prev, cur), defaultPrev): 两两执行,prev 为上次化简函数的return值,cur 为当前值(从第二项开始)
JS有哪些内置对象
Object是JavaScript中所有对象的父对象 数据封装对象:Object、Array、Boolean、Number和String 其他对象:Function、Arguments、Math、Date、RegExp、Error
get请求传参长度的误区
误区:我们经常说get请求参数的大小存在限制,而post请求的参数大小是无限制的
实际上HTTP 协议从未规定 GET/POST 的请求长度限制是多少。对get请求参数的限制是来源与浏览器或web服务器,浏览器或web服务器限制了url的长度。为了明确这个概念,我们必须再次强调下面几点:
1、HTTP 协议 未规定 GET 和POST的长度限制
2、GET的最大长度显示是因为 浏览器和 web服务器限制了 URI的长度
3、不同的浏览器和WEB服务器,限制的最大长度不一样
4、要支持IE,则最大长度为2083byte,若只支持Chrome,则最大长度 8182byte
补充get和post请求在缓存方面的区别
- get请求类似于查找的过程,用户获取数据,可以不用每次都与数据库连接,所以可以使用缓存。
- post不同,post做的一般是修改和删除的工作,所以必须与数据库交互,所以不能使用缓存。因此get请求适合于请求缓存。
闭包
什么是闭包
函数A里面办函了函数B,而函数B里面使用了函数A的变量,那么函数B被称为闭包
又或者:闭包就是能够读取其他函数内部变量的函数
function A() { var a = 1; function B() { console.log(a); } return B(); }
闭包的特征
- 函数内再嵌套函数
- 内部函数可以引用外层的参数和变量
- 参数和变量不会被垃圾回收机制回收
对闭包的理解
使用闭包主要是为了设计私有的方法和变量.闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易曹成内存泄漏,在js中,函数即闭包,只有函数才会产生作用域的概念
闭包最大的用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量时钟保持在内存中
闭包的另一个用处就是封装对象的私有属性和私有方法
闭包的好处
能够实现封装和缓存等
闭包的坏处
就是消耗内存,不正当使用会造成内存溢出的问题
使用闭包的注意点
由于闭包会使得函数中的变量都被保存在内存中,内存消耗恒大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能会导致内存泄漏
解决方法是:在退出函数之前,将不使用的局部变量全部删除
闭包的经典问题
for(var i = 0; i < 3; i++) { setTimeout(function() { console.log(i); }, 1000); }
这段代码输出:
答案:3个3 解析:首先,for 循环是同步代码,先执行三遍 for,i 变成了 3;然后,再执行异步代码 setTimeout,这时候输出的 i,只能是 3 个 3 了
有什么办法依次输出0 1 2
第一种方法:使用let
for(let i = 0; i < 3; i++) { setTimeout(function() { console.log(i); }, 1000); }
在这里,每个 let 和代码块结合起来形成块级作用域,当 setTimeout() 打印时,会寻找最近的块级作用域中的 i,所以依次打印出 0 1 2
如果这样不明白,我们可以执行下边这段代码
for(let i = 0; i < 3; i++) { console.log("定时器外部:" + i); setTimeout(function() { console.log(i); }, 1000); }
此时浏览器依次输出的是:
定时器外部:0 定时器外部:1 定时器外部:2 0 1 2
即代码还是先执行 for 循环,但是当 for 结束执行到了 setTimeout 的时候,它会做个标记,这样到了 console.log(i) 中,i 就能找到这个块中最近的变量定义
第二种方法
使用立即执行函数解决闭包问题
for(let i = 0; i < 3; i++) { (function(i){ setTimeout(function() { console.log(i); }, 1000); })(i) }
JS作用域及作用域链
作用域
在JavaScript中,作用域分为 全局作用域 和 函数作用域
- 全局作用域
代码在程序的任何地方都能被访问,window 对象的内置属性都拥有全局作用域
- 函数作用域
在固定的代码片段才能被访问
作用域有上下级关系,上下级关系的确定就看函数是在哪个作用域下创建的。如上,fn作用域下创建了bar函数,那么“fn作用域”就是“bar作用域”的上级。
作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。
变量取值:到创建 这个变量的函数的作用域中取值
作用域链
一般情况下,变量取值到创建这个变量的函数的作用域中取值。
但是如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链
原型和原型链
原型和原型链的概念
每个对象都会在其内部初始化一个属性,就是prototype(原型),当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,于是就这样一直找下去
原型和原型链的关系
instance.constructor.prototype = instance.__proto__
原型和原型链的特点
JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变,当我们需要一个属性的时,Javascript引擎会先看当前对象中是否有这个属性, 如果没有的就会查找他的Prototype对象是否有这个属性,如此递推下去,一直检索到 Object 内建对象
组件化和模块化
组件化
为什么要组件化开发
有时候页面代码量太大,逻辑太多或者同一个功能组件在许多页面均有使用,维护起来相当复杂,这个时候,就需要组件化开发来进行功能拆分、组件封装,已达到组件通用性,增强代码可读性,维护成本也能大大降低
组件化开发的优点
很大程度上降低系统各个功能的耦合性,并且提高了功能内部的聚合性。这对前端工程化及降低代码的维护来说,是有很大的好处的,耦合性的降低,提高了系统的伸展性,降低了开发的复杂度,提升开发效率,降低开发成本
组件化开发的原则
- 专一
- 可配置性
- 标准型
- 复用性
- 可维护性
模块化
为什么要模块化
早期的javascript版本没有块级作用域、没有类、没有包、也没有模块,这样会带来一些问题,如复用、依赖、冲突、代码组织混乱等,随着前端的膨胀,模块化显得非常迫切
模块化的好处
- 避免变量污染,命名冲突
- 提高代码复用率
- 提高了可维护性
- 方便依赖关系管理
模块化的几种方法
函数封装
var myModule = { var1: 1, var2: 2, fn1: function(){ }, fn2: function(){ } }
总结:这样避免了变量污染,只要保证模块名唯一即可,同时同一模块内的成员也有了关系
缺陷:外部可以睡意修改内部成员,这样就会产生意外的安全问题立即执行函数表达式
var myModule = (function(){ var var1 = 1; var var2 = 2; function fn1(){ } function fn2(){ } return { fn1: fn1, fn2: fn2 }; })();
总结:这样在模块外部无法修改我们没有暴露出来的变量、函数
缺点:功能相对较弱,封装过程增加了工作量,仍会导致命名空间污染可能、闭包是有成本的
图片的预加载和懒加载
- 预加载:提前加载图片,当用户需要查看时可以直接从本地缓存中渲染
- 懒加载:懒加载的主要目的是作为服务器前端的优化,减少请求数或延迟请求数
两种技术的本质:两者的行为是相反的,一个是提前加载,一个是迟缓甚至不加载。预加载则会增加服务器前端压力,懒加载对服务器有一定的缓解压力作用。
mouseover和 mouseenter的区别
- mouseover:当鼠标移入元素或者其他子元素都会触发事件,所以有一个重复触发,冒泡的过程,对应的移除事件是mouseout
- mouseenter:当鼠标移除元素本身(不包含元素的子元素)会触发事件,也就是不会冒泡,对应的移除事件是mouseleave
解决异步回调地狱(待补充)
promise,generator,async/await
对This对象的理解(待补充)
- this总是指向函数的直接调用者(而非间接调用者)
- 如果有new关键字,this指向new出来的那个对象
- 在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window
Vue
Vue生命周期
- 什么是Vue生命周期?
参考博文:https://blog.csdn.net/wyf521995/article/details/103114989
简单描述:Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期
Vue生命周期的作用是什么?
它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑
Vue生命周期总共有几个阶段?
它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后
第一次页面加载会触发哪几个钩子?
第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子
DOM渲染在哪个周期中就已经完成?
DOM 渲染在 mounted 中就已经完成了
每个生命周期适合哪些场景?
生命周期钩子的一些使用方法:
beforecreate : 可以在这加个loading事件,在加载实例时触发
created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
mounted : 挂载元素,获取到DOM节点
updated : 如果对数据统一处理,在这里写上相应函数
beforeDestroy : 可以做一个确认停止事件的确认框
nextTick : 更新数据后立即操作dom
v-show与v-if的区别
v-show是css切换,v-if是完整的销毁和重新创建
使用 频繁切换时用v-show,运行时较少改变时用v-if
v-if=‘false’ v-if是条件渲染,当false的时候不会渲染
开发中常用的指令有哪些?
v-model :一般用在表达输入,很轻松的实现表单控件和数据的双向绑定 v-html: 更新元素的 innerHTML v-show 与 v-if: 条件渲染, 注意二者区别 v-on : click: 可以简写为@click,@绑定一个事件。如果事件触发了,就可以指定事件的处理函数 v-for:基于源数据多次渲染元素或模板块 v-bind: 当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM
绑定Class的数组方法
对象方法
v-bind:class="{'orange': isRipe, 'green': isNotRipe}"
数组方法
v-bind:class="[class1, class2]"
行内
v-bind:style="{color: color, fontSize: fontSize+'px' }"
组件之间的传值通信
父组件给子组件传值
使用props,字组件可以使用props接收父组件传递的数据
父组件vue模板father.vue
<template> <child :msg="message"></child> </template> <script> import child from './child.vue'; export default { components: { child }, data () { return { message: 'father message'; } } } </script>
子组件vue模板child.vue
<template> <div>{{msg}}</div> </template> <script> export default { props: { msg: { type: String, required: true } //我觉得这样写有点麻烦,直接用数组接收就可以了 /* props:['msg'], */ } } </script>
子组件向父组件通信
父组件向子组件传递事件方法,子组件通过$emit触发事件,回调给父组件
子组件vue模板child.vue
<template> <button @click="handleClick">点我</button> </template> <script> export default { props: { msg: { type: String, required: true } }, methods () { handleClick () { //........ this.$emit('msgFunc',msg); } } } </script>
父组件vue模板fatehe.vue
<template> <child @msgFunc="func"></child> </template> <script> import child from './child.vue'; export default { components: { child }, methods: { func (msg) { console.log(msg); } } } </script>
非父子,兄弟组件之间通信
可以通过实例一个vue实例Bus作为媒介,要相互通信的兄弟组件之中,都引入Bus,然后通过分别调用Bus事件触发和监听来实现通信和参数传递
bus.js代码如下:
import Vue from 'vue' export default new Vue()
在需要通信的组件都引入Bus.js:
<template> <button @click="toBus">子组件传给兄弟组件</button> </template> <script> import Bus from '../common/js/bus.js' export default{ methods: { toBus () { Bus.$emit('on', '来自兄弟组件') } } } </script>
另一个组件也import Bus.js 在钩子函数中监听on事件
import Bus from '../common/js/bus.js' export default { data() { return { message: '' } }, mounted() { Bus.$on('on', (msg) => { this.message = msg }) } }
详细可以参考文章:https://blog.emier.cn/post/2019-11-17-vue-jing-dian-mian-shi-ti-yu-zhi-shi-dian-chuan-shao/
路由跳转方式
1,<router-link to='home'> router-link标签会渲染为<a>标签,咋填template中的跳转都是这种; 2,另一种是编程是导航 也就是通过js跳转 比如 router.push('/home')
详细可参考文章:https://blog.emier.cn/post/2019-11-17-vue-jing-dian-mian-shi-ti-yu-zhi-shi-dian-chuan-shao/
MVVM
M - Model,Model 代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑 V - View,View 代表 UI 组件,它负责将数据模型转化为 UI 展现出来 VM - ViewModel,ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步 View 和 Model 的对象,连接 Model 和 View
computed和watch有什么区别?
computed:
- computed是计算属性,也就是计算值,它更多用于计算值的场景
- computed具有缓存性,computed的值在getter执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取computed的值时才会重新调用对应的getter来计算
- computed适用于计算比较消耗性能的计算场景
watch:
- 更多的是「观察」的作用,类似于某些数据的监听回调,用于观察props $emit或者本组件的值,当数据变化时来执行回调进行后续操作
- 无缓存性,页面重新渲染时值不变化也会执行
小结
- 当我们要进行数值计算,而且依赖于其他数据,那么把这个数据设计为computed
- 如果你需要在某个数据变化时做一些事情,使用watch来观察这个数据变化
key
参考文章:https://www.jianshu.com/p/4bdd2690859c
组件中的data为什么是函数?
为什么组件中的data必须是一个函数,然后return一个对象,而new Vue实例里,data可以直接是一个对象?
// data data() { return { message: "子组件", childName:this.name } } // new Vue new Vue({ el: '#app', router, template: '
', components: {App} }) 因为组件是用来复用的,JS里对象是引用关系,这样作用域没有隔离,而new Vue的实例,是不会被复用的,因此不存在引用对象问题
Class与Style如何动态绑定?
Class 可以通过对象语法和数组语法进行动态绑定
class对象语法
<div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div> data: { isActive: true, hasError: false }
class数组语法
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div> data: { activeClass: 'active', errorClass: 'text-danger' }
style对象语法
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div> data: { activeColor: 'red', fontSize: 30 }
style数组语法
<div v-bind:style="[styleColor, styleSize]"></div> data: { styleColor: { color: 'red' }, styleSize:{ fontSize:'23px' } }
vue的单项数据流(待补充)
keep-alive(待补充)
v-model的原理
vue 项目中主要使用 v-model 指令在表单 input、textarea、select 等元素上创建双向数据绑定,我们知道 v-model 本质上不过是语法糖,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:
- text 和 textarea 元素使用 value 属性和 input 事件;
- checkbox 和 radio 使用 checked 属性和 change 事件;
- select 字段将 value 作为 prop 并将 change 作为事件;
以input表单元素为例:
<input v-model='something'>
相当于:
<input v-bind:value="something" v-on:input="something = $event.target.value">
如果在自定义组件中,v-model 默认会利用名为 value 的 prop 和名为 input 的事件,如下所示:
父组件: <ModelChild v-model="message"></ModelChild> 子组件: <div>{{value}}</div> props:{ value: String }, methods: { test1(){ this.$emit('input', '小红') }, },
nextTick() -待补充
在下次DOM更新循环结束之后执行延迟回调。在修改数据之后,立即使用的这个回调函数,获取更新后的DOM
// 修改数据 vm.msg = 'Hello' // DOM 还未更新 Vue.nextTick(function () { // DOM 更新 })
Vue插槽(待补充)
匿名插槽
当子组件模板只有一个没有属性的插槽时,
父组件传入的整个内容片段将插入到插槽所在的 DOM 位置,
并替换掉插槽标签本身命名插槽
solt元素可以用一个特殊的特性name来进一步配置如何分发内容。
多个插槽可以有不同的名字。 这样可以将父组件模板中 slot 位置,
和子组件 slot 元素产生关联,便于插槽内容对应传递作用域插槽
在父级中,具有特殊特性 slot-scope 的 元素必须存在,
表示它是作用域插槽的模板。slot-scope 的值将被用作一个临时变量名,
此变量接收从子组件传递过来的 prop 对象Vue-Router有哪几种导航钩子?
全局前置守卫: const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // ... }) 全局解析守卫: 你可以用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似, 区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。 全局后置钩子: 你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身: router.afterEach((to, from) => { // ... }) 路由独享的守卫: const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ] }) 组件内的守卫: 你可以在路由组件内直接定义以下路由导航守卫: const Foo = { template: `...`, beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` } }
vuex(待学待补充)
vuex是什么?
vuex 就是一个仓库,仓库里放了很多对象。其中 state 就是数据源存放地,对应于一般 vue 对象里面的 data
state 里面存放的数据是响应式的,vue 组件从 store 读取数据,若是 store 中的数据发生改变,依赖这相数据的组件也会发生更新
它通过 mapState 把全局的 state 和 getters 映射到当前组件的 computed 计算属性
五种属性
- state
- mutations
- getters
- action
总结
vuex 一般用于中大型 web 单页应用中对应用的状态进行管理,对于一些组件间关系较为简单的小型应用,使用 vuex 的必要性不是很大,因为完全可以用组件 prop 属性或者事件来完成父子组件之间的通信,vuex 更多地用于解决跨组件通信以及作为数据中心集中式存储数据
你对Vue项目进行哪些优化?
代码层面的优化
v-if 和 v-show 区分使用场景 computed 和 watch 区分使用场景 v-for 遍历必须为 item 添加 key,且避免同时使用 v-if 长列表性能优化 事件的销毁 图片资源懒加载 路由懒加载 第三方插件的按需引入 优化无限列表性能 服务端渲染 SSR or 预渲染
webpack层面的优化
Webpack 对图片进行压缩 减少 ES6 转为 ES5 的冗余代码 提取公共代码 模板预编译 提取组件的 CSS 优化 SourceMap 构建结果输出分析 Vue 项目的编译优化
基础的web技术优化
开启 gzip 压缩
浏览器缓存
CDN 的使用
使用 Chrome Performance 查找性能瓶颈补充
Vue路由的两种模式
小白回答:hash模式url带#号,history模式不带#号
大牛解答:hash模式url里面永远带着#号,我们在开发当中默认使用这个模式。那么什么时候要用history模式呢?如果用户考虑url的规范那么就需要使用history模式,因为history模式没有#号,是个正常的url适合推广宣传。当然其功能也有区别,比如我们在开发app的时候有分享页面,那么这个分享出去的页面就是用vue或是react做的,咱们把这个页面分享到第三方的app里,有的app里面url是不允许带有#号的,所以要将#号去除那么就要使用history模式,但是使用history模式还有一个问题就是,在访问二级页面的时候,做刷新操作,会出现404错误,那么就需要和后端人配合让他配置一下apache或是nginx的url重定向,重定向到你的首页路由上就ok啦。
hash与history的区别:
hash history url显示 有#,很Low 无#,好看 回车刷新 可以加载到hash值对应页面 一般就是404掉了 支持版本 支持低版本浏览器和IE浏览器 HTML5新推出的API hash模式
我们先来认识下这位朋友#,这个#就是hash符号,中文名哈希符或锚点,当然这在我们前端领域姑且这么称呼。然后哈希符后面的值,我们称之为哈希值。OK,接下来我们继续分析他的原理。路由的哈希模式其实是利用了window可以监听onhashchange事件,也就是说你的url中的哈希值(#后面的值)如果有变化,前端是可以做到监听并做一些响应(搞点事情),这么一来,即使前端并没有发起http请求他也能够找到对应页面的代码块进行按需加载。
后来人们给他起了一个霸气的名字叫前端路由,成为了单页应用标配。
history模式
我们先介绍一下H5新推出的两个神器:pushState与replaceState具体自行百度,简而言之,这两个神器的作用就是可以将url替换并且不刷新页面,好比挂羊头卖狗肉,http并没有去请求服务器该路径下的资源,一旦刷新就会暴露这个实际不存在的“羊头”,显示404。
那么如何去解决history模式下刷新报404的弊端呢,这就需要服务器端做点手脚,将不存在的路径请求重定向到入口文件(index.html),前后端联手,齐心协力做好“挂羊头卖狗肉”的完美特效。
总之,pushState方法不会触发页面刷新,只是导致history对象发生变化,地址栏会有反应。
history模式下,build之后本地 index.html 打开是无效的。
hash模式下,build之后本地 index.html 打开正常!
如何解决SPA应用首屏加载过慢
将全局引入转换为按需引入文件
在 config/index.js 文件中将productionSourceMap 的值设置为false. 不生成映射资源
路由懒加载:懒加载即组件的延迟加载,通常vue的页面在运行后进入都会有一个默认的页面,而其他页面只有在点击后才需要加载出来,使用懒加载可以将页面中的资源划分为多份,从而减少第一次加载的时候耗时
这种优化,就是将每个组件的js代码独立出来,在使用到这个组件时,才向服务器请求文件,并且请求过一次后就会缓存下来,再次使用到这个组件时,就会使用缓存,不再发送请求
压缩css和js文件
使用cdn托管(就是把原服务器上数据复制到其他服务器上,用户访问时,哪台服务器近访问到的就是哪台服务器上的数据。)
ES6
var,let,const之间的区别
var声明变量可以重复声明,而let不可以重复声明
var是不受限于块级的,而let是受限于块级
var会与window相映射(会挂一个属性),而let不与window相映射
var可以在声明的上面访问变量,而let有暂存死区,在声明的上面访问变量会报错
const声明之后必须赋值,否则会报错
const定义不可变的量,改变了就会报错
const和let一样不会与window相映射、支持块级作用域、在声明的上面访问变量会报错
解构赋值
数组解构
let [a, b, c] = [1, 2, 3] //a=1, b=2, c=3 let [d, [e], f] = [1, [2], 3] //嵌套数组解构 d=1, e=2, f=3 let [g, ...h] = [1, 2, 3] //数组拆分 g=1, h=[2, 3] let [i,,j] = [1, 2, 3] //不连续解构 i=1, j=3 let [k,l] = [1, 2, 3] //不完全解构 k=1, l=2
对象结构
let {a, b} = {a: 'aaaa', b: 'bbbb'} //a='aaaa' b='bbbb' let obj = {d: 'aaaa', e: {f: 'bbbb'}} let {d, e:{f}} = obj //嵌套解构 d='aaaa' f='bbbb' let g; (g = {g: 'aaaa'}) //以声明变量解构 g='aaaa' let [h, i, j, k] = 'nice' //字符串解构 h='n' i='i' j='c' k='e'
函数参数的定义
一般我们在定义函数的时候,如果函数有多个参数时,在es5语法中函数调用时参数必须一一对应,否则就会出现赋值错误的情况,来看一个例子:
function personInfo(name, age, address, gender) { console.log(name, age, address, gender) } personInfo('william', 18, 'changsha', 'man')
上面这个例子在对用户信息的时候需要传递四个参数,且需要一一对应,这样就会极易出现参数顺序传错的情况,从而导致bug,接下来来看es6解构赋值是怎么解决这个问题的:
function personInfo({name, age, address, gender}) { console.log(name, age, address, gender) } personInfo({gender: 'man', address: 'changsha', name: 'william', age: 18})
这么写我们只知道要传声明参数就行来,不需要知道参数的顺序也没关系
变换变量的值
在es5中我们需要交换两个变量的值需要借助临时变量的帮助,来看一个例子:
var a=1, b=2, c c = a a = b b = c console.log(a, b)
来看ES6如何实现
let a=1, b=2; [b, a] = [a, b] console.log(a, b)
函数默认参数
在日常开发中,经常会有这种情况:函数的参数需要默认值,如果没有默认值在使用的时候就会报错,来看es5中是怎么做的:
function saveInfo(name, age, address, gender) { name = name || 'william' age = age || 18 address = address || 'changsha' gender = gender || 'man' console.log(name, age, address, gender) } saveInfo()
在函数离 main先对参数做一个默认值赋值,然后再使用避免使用的过程中报错,再来看es6中的使用的方法:
function saveInfo({name= 'william', age= 18, address= 'changsha', gender= 'man'} = {}) { console.log(name, age, address, gender) } saveInfo()
forEach,for in,for of三者的区别(待补充)
forEach更多的用来遍历数
for in 一般常用来遍历对象或json
for of数组对象都可以遍历,遍历对象需要通过和Object.keys()
for in循环出的是key,for of循环出的是value
使用箭头函数应该注意什么?(待补充)
1、用了箭头函数,this就不是指向window,而是父级(指向是可变的)
2、不能够使用arguments对象
3、不能用作构造函数,这就是说不能够使用new命令,否则会抛出一个错误
4、不可以使用yield命令,因此箭头函数不能用作 Generator 函数Set、Map的区别
应用场景Set用于数据重组,Map用于数据储存
Set:
1,成员不能重复
2,只有键值没有键名,类似数组
3,可以遍历,方法有add, delete,hasMap:
1,本质上是健值对的集合,类似集合
2,可以遍历,可以跟各种数据格式转换promise对象的用法,手写一个promise(待补充)
promise是一个构造函数,下面是一个简单实例
var promise = new Promise((resolve,reject) => { if (操作成功) { resolve(value) } else { reject(error) } }) promise.then(function (value) { // success },function (value) { // failure })
Ajax
Github
webpack
微信小程序
网络协议
性能优化