P7小实训
一 javascript原型与原型链
- 每个函数都有一个prototype属性,被称为显示原型
- 每个实例对象都会有
_ _proto_ _
属性,其被称为隐式原型,每一个实例对象的隐式原型_ _proto_ _
属性指向自身构造函数的显式原型prototype - 每个prototype原型都有一个constructor属性,指向它关联的构造函数
- 原型链:获取对象属性时,如果对象本身没有这个属性,那就会去他的原型
__proto__
上去找,如果还查不到,就去找原型的原型,一直找到最顶层(Object.prototype
)为止。Object.prototype对象也有__proto__属性值为null。
二 作用域和自由变量
1.作用域:变量作用域:就是一个变量可以使用的范围。
2.作用域种类:
-
js中首先有一个最外层的作用域,全局作用域
-
s中可以通过函数来创建一个独立作用域称为
函数作用域
,函数可以嵌套,所以作用域也可以嵌套; -
es6新增了块级作用域
{}
比如if{} for{}
-
es6作用域,只适用于const,let
3.自由变量:当前作用域没有定义的变量
-
一个变量在当前作用域没有定义,但被使用了
-
向上级作用域,一层一层依次寻找,直达找到为止
-
如果全局作用域都没找到,则报错 xx is not defined
-
作用域链:自由变量向上级作用域一层一层查找,直到找到为止,最高找到全局作用域,这就是作用域链
-
变量提升(预解析)
**var声明的变量,function声明的函数存在变量提升 let const 不会变量提升 **
- javascript中声明并定义一个变量时,会把声明提前
- 函数声明也会把整个函数提升到作用域的最上面
- 函数表达式不能变量提升,只会把声明的 var fn 提升到作用域的最顶端,
三 闭包
- 什么是闭包?
- 要理解闭包,首先理解javascript特殊的变量作用域,变量的作用于无非就是两种:全局变量,局部变量。
- javascript语言的特殊处就是函数内部可以读取外部作用域中的变量。
- 我们有时候需要得到函数内的局部变量,但是在正常情况下,这是不能读取到的,这时候就需要用到闭包。在javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。闭包是指有权访问另一个函数作用域中的变量的函数。其本质是函数的作用域链中保存着外部函数变量对象的引用。
- (当一个函数的返回值是另外一个函数,而返回的那个函数如果调用其父函数的内部变量,且返回的那个函数在外部执行,就产生闭包)
2.闭包的应用场景
-
函数作为参数被传递
-
函数作为返回值被返回
-
实际应用(隐藏数据):为什么说隐藏数据了呢,因为普通用户只能通过get、set等api对数据进行查看和更改等操作,没法对data直接更改,达到所谓隐藏数据的效果;jquery就利用了这一特性,必须调用$.ajax()才能访问内部属性方法。
封装功能时(需要使用私有的属性和方法),
函数防抖、函数节流
单例模式3.闭包的优点
-
变量长期驻扎在内存中
-
另一个就是可以重复使用变量,并且不会造成变量污染
①全局变量可以重复使用,但是容易造成变量污染。不同的地方定义了相同的全局变量,这样就会产生混乱。”
②局部变量仅在局部作用域内有效,不可以重复使用,不会造成变量污染。
③闭包结合了全局变量和局部变量的优点。可以重复使用变量,并且不会造成变量污染
-
闭包的缺点
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
5.闭包的三个特性
1.函数嵌套函数 2.内部的函数可以访问外部函数的内部变量或参数 3.变量或参数不会被垃圾回收机制回收。
**闭包的两种写法:
1:
function a () { var num=1; function b () { alert(num) } return b; //把函数 b 返回给函数 a; } alert(a())//弹出函数 a, 值是函数 b;
2:
function a () { var num=1; return function b () { //把函数 b 返回给函数 a; alert(num=num+2) } } alert(a());//弹出函数 a, 值是函数 b;
调用方式:
//1:直接调用
a()()//内部函数的执行
//2:通过赋值在调用var f = a();
f();
四 继承
-
原型链继承
- 父类的实例作为子类的原型
- 可以使用父类原型上的方法,不可以传递参数
-
构造函数继承
- 在子类内使用
call()
调用父类方法,将父类this的指向修改为子类的this,相当于把实列属性复制一份给子类 - 可以父类实例中的方法,可以传递参数。不能使用父类原型的方法
- 在子类内使用
-
组合继承
- 即在子类中使用
call()
方法,再把父类的实例作为子类的原型 - 既能调用父类实例的方法,又能调用父类原型的方法,还可以传递参数
- 即在子类中使用
-
Es6 class 继承
- 使用class来创建一个子类,使用extends关键字来继承,使用super来调用父类的方法
- Class在语法上更加贴合面向对象的写法
- Class在实现继承上更加易读、易理解
- 本质上还是prototype
五 深拷贝
-
浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用
-
深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”
-
手写
var arr=[100,[{a:'hello',b:'world'}],{data:[1,2,3,4]}]; //如何深拷贝 function deepClone(obj={}){ if(typeof obj !=='object' ||obj==null){ return obj; } let result; if(obj instanceof Array) { result=[]; }else{ result={}; } for(var item in obj){ //不拷贝原型上属性 if(obj.hasOwnProperty(item){ result [item]=deepClone(obj[item]) } } return result; } let arr1=deepClone(arr); arr1[1][0].a='123456789' console.log(arr1); console.log(arr);
六 Promise
-
什么是Promise?
- Promise简单来说就是一个容器,里面存放着未来才会结束的事件(一个异步操作的结果)从语法上来说promise是一个对象
- 他可以获取异步操作的最终状态Promise是一个构造函数,对外提供统一的API,自己身上有all,reject,resolve等方法,原型上有then,catch方法
-
Promise特点?
- 状态:pending 初始 fufiled 成功 rejected 失败
- promise对象的状态不受外界影响,只有异步操作的结果可以决定当前是哪一种状态,其他任何操作无法改变
- Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可逆,只能由pending变成fufiled或者由pending变成rejected
-
Promise有哪些API
- then
- 把原来的回调分离出来,用链式调用的方式回调,then有两个回调函数,第一个成功,第二个失败
- catch
- 和then的参数一样,用来指定错误的reject的回调,在执行then方法时,如果报错会执行catch方法
- all
- 并行执行异步操作,在所有异步操作完成后回调
- racel
- 用法和all一样,只有一个异步操作完成后回调,其他没有执行完成的异步操作会继续执行
- then
-
Promise的应用场景
- Ajax,axios的get和post的封装
- 微信小程序中封装wx.requset()
- uniapp开发 uni.requser()
Promise的链式调用,解决了地狱回调
七 async/await
- async:异步的简写,用于声明一个异步的函数
- await:用于等待一个异步方法执行完成
- 特点
- async 用法它作为一个关键字放到函数前面,这个普通函数就变成了异步函数
- 异步async函数调用,跟普通函数的使用方式一样
- 异步async函数返回一个Promise
- async配合await关键字使用(阻塞代码往下执行)是异步的方式,但是是阻塞式的
- async和await优点
- 方便级联调用
- 同步代码的编写方式
- 多个参数传递
- 同步代码和异步代码一起编写
- async和await是对promise的优化
- 使用场景
- async主要处理异步操作
- 简化Promise的链式回调 最终版处理地狱回调
八 数据双向绑定
vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图。
- 具体分为四部
- 需要
observer
的数据对象进行递归遍历
,包括子属性对象的属性,都加上 setter和getter
这样的话,给这个对象的某个值赋值
,就会触发setter
,那么就能监听到了数据变化 - compile`解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
Watcher
订阅者是Observer
和Compile
之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep
)里面添加自己
2、自身必须有一个update
()方法
3、待属性变动dep.notice()
通知时,能调用自身的update()方法
,并触发Compile中绑定的回调
,则功成身退。MVVM
作为数据绑定的入口,整合Observer、Compile和Watcher三者,
通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
- 需要
九 虚拟DOM和diff算法
- 虚拟dom
用js来模拟DOM中的节点。传说中的虚拟DOM。
virtual DOM 虚拟DOM,用普通js对象来描述DOM结构,因为不是真实DOM,所以称之为虚拟DOM。
- diff算法
- diff算法就是进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方,最后用patch记录的消息去局部更新Dom。
十 组件通信
- 父传子
- 在父组件的子组件标签上绑定一个属性,挂载要传输的变量
- 在子组件中通过props来接受数据,props可以是数组也可以是对象,接受的数据可以直接使用 props:[“属性 名”] props:{属性名:数据类型}
- 子传父
- 在父组件的子组件标签上自定义一个事件,然后调用需要的方法
- 在子组件的方法中通过 this.$emit(“事件”)来触发在父组件中定义的事件,数据是以参数的形式进行传递的
- 兄弟组件通信
- 在src中新建一个Bus.js的文件,然后导出一个空的vue实例
- 在传输数据的一方引入Bus.js 然后通过Bus. e m i t ( “ 事 件 名 ” , " 参 数 " ) 来 来 派 发 事 件 , 数 据 是 以 emit(“事件名”,"参数")来来派发事件,数据是以 emit(“事件名”,"参数")来来派发事件,数据是以emit()的参数形式来传递
- 在接受的数据的一方 引入 Bus.js 然后通过 Bus.$on(“事件名”,(data)=>{data是接受的数据})
十一 vuex
概念:是一个专为vue.js开发的状态管理器,采用集中式存储的所有组件状态
-
基本使用
-
新建store.js文件,最后在main.js中引入,并挂载到实列上
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const state = {} const getters = {} const mutations = {} const actions = {} export default new Vuex.Store({ state, getters, mutations, actions })
-
-
五大属性
- state属性: 存放状态,例如你要存放的数据
- getters: 类似于共享属性,可以通过this.$store.getters来获取存放在- state里面的数据
- mutations: 唯一能改变state的状态就是通过提交mutations来改变,this.$store.commit()
- actions: 一步的mutations,可以通过dispatch来分发从而改变state
- module: 模块化
-
vue持久化
- vuex里面存放的数据,页面一经刷新会丢失:
解决办法: 存放在localStorage或者sessionStorage里面,进入页面时判断是否丢失,丢失再去localStorage或者sessionStorage里面取;
在app.vue根组件的created里面判断是否丢失,在进行上面的操作; - vuex-persistedstate 插件
- vuex里面存放的数据,页面一经刷新会丢失:
vuex的映射
state,getters需要映射在computed实例而mutations,action等需要在methods实例中。
#vuex运行机制
vuex提供数据来驱动视图,通过dispath派发actions,在其中可以做一些异步操作,然后通过commit来提交mutations,
最后mutations来更改state。
十二 keep-alive
概念:是Vue的内置组件,能在组件切换过程中将状态保留在内存中,取消组件的销毁函数,防止重复渲染DOM。
-
我们在切换路由的时候,想保存组件的状态,比如列表页面进入详情,我们想保存列表滚动的位置,我们就可以使用keep-alive保存列表页面的滚动位置。
-
组件使用keep-alive以后会新增两个生命周期 actived() deactived()
-
keep-alive用法
- 全局配置
全局保存在App.vue中 <keep-alive>把<routerView/>包裹起来
-
router.js中配置
{ path: '/child1', name: 'Child1', component: Child1, meta:{ keepAlive:true,//保存keep-alive状态 } }
-
用v-if来显示router-view是否在keep-alive中出现
<keep-alive> <router-view v-if="$route.meta.keepAlive"></router-view> </keep-alive> <router-view v-if="!$route.meta.keepAlive"></router-view>
-
使用keep-alive的标签属性, include() exclude()
<keep-alive inclue="list,detail" ></keep-alive> //include 包含标签名字被缓存 exclude 包含的标签不被缓存 //缓存名字组件中有个name属性进行定义即可
十三 自定义指令
很多时候我们需要直接操作 dom 元素,如果只是个别需要操作 dom 元素,我们可以通过 ref 获取当前 dom 元素,并对其进行操作,但是如果
特别多的时候,我们不可能每次都去写一遍 ref 还有方法,所以这时候自定义指令就可以帮你轻松解决这个问题
分为全局和局部;
-
自定义指令分为全局自定义指令和局部自定义指令
- 使用
Vue.directive('focus',{bind(el,binding){},inserted(){}})
进行全局自定义指令 - 参数1 :指令的名称
- 参数2: 是一个对象,这个对象身上,有钩子函数.
- 使用
-
钩子函数
- bind(){} 只调用一次,指令第一次绑定到元素时调用
- inserted(){}被绑定元素插入父节点时调用
- update(){}被绑定元素所在的模板更新时调用,而不论绑定值是否变化
- componentUpdated(){}被绑定元素所在模板完成一次更新周期时调用
- unbind(){}只调用一次, 指令与元素解绑时调用
实际应用
// 注册一个全局自定义指令 `v-focus` Vue.directive('focus', { // 当被绑定的元素插入到 DOM 中时 inserted: function (el) { // 聚焦元素 el.focus() } }) <input v-focus>
十四 自定义组件(组件封装)
我用vue开发的所有项目,都是采用组件化的思想开发的。一般我在搭建项目的时候,会创建一个views目录和一个commen目录和一个feature目录,views目录中放页面级的组件,commen中放公共组件(如:head(公共头组件),foot(公共底部组件)等),feature目录内放功能组件(如:swiper(轮播功能组件),tabbar(切换功能组件)、list(上拉加载更多功能组件))
首先,组件可以提升整个项目的开发效率。能够把页面抽象成多个相对独立的模块,解决了我们传统项目开发:效率低、难维护、复用性低等问题。
使用Vue.extend方法创建一个组件,然后使用Vue.component方法注册组件。但是我们一般用脚手架开发项目,每个 .vue单文件就是一个组件。在另一组件import 导入,并在components中注册,子组件需要数据,可以在props中接受定义。而子组件修改好数据后,想把数据传递给父组件。可以采用emit方法。
1.命名要用驼峰命名法
2.引入用i没import来引入,然后注册
3.页面写入标签
十五 路由守卫
router.beforeEach() 全局路由守卫的钩子函数,可以写到main.js中
beforeRouteEnter 进入组件之前触发方法
beforeRouteUpdate 组件参数更新的时候触发
beforeRouteLeave 离开组件的时候触发的钩子函数
to 即将要进入页面的路由信息
from 离开页面路由信息
next 是否继续进入进入路由 next(false)阻止进入 next()继续进入路由地址
十六 生命周期函数
-
1.创建
beforeCreate() 创建前的阶段,这个时候data中的数据,还未定义,所以不能使用
created() 最早开始使用 data和methods中数据的钩子函数 -
2.挂载
beforeMount() 指令已经解析完毕内存中已经生成dom树,还没有渲染到本地
mounted() dom已经渲染完毕,最早可以操作DOM元素钩子函数 -
3.更新
beforeUpdate() 当data的数据发生改变会执行这个钩子 内存更新,但是DOM节点还未更新
updated() 数据更新完成以后触发的方法,DOM节点已经更新 -
4.销毁
beforeDestroy()即将销毁 data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作
destroyed()已经销毁完毕 -
9.activated(组件激活时)和上面的beforeDstroy和destroyed用一样,但是如果我们需要一个实例,在销毁后再次出现的话,用beforeDestroy和destroyed的话,就太浪费性能,实例被激活时使用,用于重复激活一个实例的时候。
10.deactivated(组件未激活时):实例没有被激活的。
11.errorcaptured(错误调用):当捕获一个来自后台组件错误是被调用。
-
keep-alive 方法
actived() 组件加上keep-alive,进入组件触发的方法
deactived 离开组件的时候触发的方法。 -
errorCaptured() 组件内发生错误的时候的触发的方法
十七 常见的状态码
200 请求成功
201 创建成功
204 删除成功
400 请求的地址不存在或者包含不支持的参数
401 未授权
403 被禁用访问
404 请求的资源不存在
422 当创建一个对象时,发生一个验证错误
500 内部错误
十八 输入url到页面出现发生了什么
- 通过DNS服务器:url=>ip地址;
- 到达ip地址对应的服务器;
- 服务器接收用户的请求;
- 把处理后的结果返回给客户端;
- 客户端把结果渲染到浏览器即可,最后页面显示出来 输入了一个域名,域名要通过DNS解析找到这个域名对应的服务器地址(ip),通过TCP请求链接服务,通过 WEB服务器(apache)返回数据,浏览器根据返回数据构建DOM树,通过css渲染引擎及js解析引擎将页面渲 染出来,关闭tcp连接
十九 跨域
-
为什么会出现跨域问题
-
出于浏览器的同源策略限制,同源策略 是由NetScape提出的一个著名的安全策略,它是浏览器最核心也最基本的安 全功能
所谓的同源,指的是协议,域名,端口相同。浏览器处于安全方面的考虑,只允许本域 名下的接口交互,不同源的客户端脚本,在没有明确授权的情况下,不能读写对方的资源
-
-
什么是跨域
- 当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
-
jsonp解决跨域
-
JSONP 是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,兼容性好(兼容低版本IE),缺点是只支持get请求,不支持post请求。
核心思想:网页通过添加一个
<script>元素
,向服务器请求 JSON 数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。this.$http.jsonp('http://www.domain2.com:8080/login', { params: {}, jsonp: 'handleCallback' }).then((res) => { console.log(res);
-
-
vue中解决跨域
-
在项目根目录新建vue.config.js文件
module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:4000', //对应自己的接口 changeOrigin: true, ws: true, pathRewrite: { '^/api': '' } } } } }
-
在main.js文件,配置一下axios.defaults.baseURL = ‘/api’ 这样就可以保证动态的匹配生产和开发环境的定义前缀了
-
重启项目即可
-
二十 项目开发流程
P7小实训
一 javascript原型与原型链
- 每个函数都有一个prototype属性,被称为显示原型
- 每个实例对象都会有
_ _proto_ _
属性,其被称为隐式原型,每一个实例对象的隐式原型_ _proto_ _
属性指向自身构造函数的显式原型prototype - 每个prototype原型都有一个constructor属性,指向它关联的构造函数
- 原型链:获取对象属性时,如果对象本身没有这个属性,那就会去他的原型
__proto__
上去找,如果还查不到,就去找原型的原型,一直找到最顶层(Object.prototype
)为止。Object.prototype对象也有__proto__属性值为null。
二 作用域和自由变量
1.作用域:变量作用域:就是一个变量可以使用的范围。
2.作用域种类:
-
js中首先有一个最外层的作用域,全局作用域
-
s中可以通过函数来创建一个独立作用域称为
函数作用域
,函数可以嵌套,所以作用域也可以嵌套; -
es6新增了块级作用域
{}
比如if{} for{}
-
es6作用域,只适用于const,let
3.自由变量:当前作用域没有定义的变量
-
一个变量在当前作用域没有定义,但被使用了
-
向上级作用域,一层一层依次寻找,直达找到为止
-
如果全局作用域都没找到,则报错 xx is not defined
-
作用域链:自由变量向上级作用域一层一层查找,直到找到为止,最高找到全局作用域,这就是作用域链
-
变量提升(预解析)
**var声明的变量,function声明的函数存在变量提升 let const 不会变量提升 **
- javascript中声明并定义一个变量时,会把声明提前
- 函数声明也会把整个函数提升到作用域的最上面
- 函数表达式不能变量提升,只会把声明的 var fn 提升到作用域的最顶端,
三 闭包
- 什么是闭包?
- 要理解闭包,首先理解javascript特殊的变量作用域,变量的作用于无非就是两种:全局变量,局部变量。
- javascript语言的特殊处就是函数内部可以读取外部作用域中的变量。
- 我们有时候需要得到函数内的局部变量,但是在正常情况下,这是不能读取到的,这时候就需要用到闭包。在javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。闭包是指有权访问另一个函数作用域中的变量的函数。其本质是函数的作用域链中保存着外部函数变量对象的引用。
- (当一个函数的返回值是另外一个函数,而返回的那个函数如果调用其父函数的内部变量,且返回的那个函数在外部执行,就产生闭包)
2.闭包的应用场景
-
函数作为参数被传递
-
函数作为返回值被返回
-
实际应用(隐藏数据):为什么说隐藏数据了呢,因为普通用户只能通过get、set等api对数据进行查看和更改等操作,没法对data直接更改,达到所谓隐藏数据的效果;jquery就利用了这一特性,必须调用$.ajax()才能访问内部属性方法。
封装功能时(需要使用私有的属性和方法),
函数防抖、函数节流
单例模式3.闭包的优点
-
变量长期驻扎在内存中
-
另一个就是可以重复使用变量,并且不会造成变量污染
①全局变量可以重复使用,但是容易造成变量污染。不同的地方定义了相同的全局变量,这样就会产生混乱。”
②局部变量仅在局部作用域内有效,不可以重复使用,不会造成变量污染。
③闭包结合了全局变量和局部变量的优点。可以重复使用变量,并且不会造成变量污染
-
闭包的缺点
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
5.闭包的三个特性
1.函数嵌套函数 2.内部的函数可以访问外部函数的内部变量或参数 3.变量或参数不会被垃圾回收机制回收。
**闭包的两种写法:
1:
function a () { var num=1; function b () { alert(num) } return b; //把函数 b 返回给函数 a; } alert(a())//弹出函数 a, 值是函数 b;
2:
function a () { var num=1; return function b () { //把函数 b 返回给函数 a; alert(num=num+2) } } alert(a());//弹出函数 a, 值是函数 b;
调用方式:
//1:直接调用
a()()//内部函数的执行
//2:通过赋值在调用var f = a();
f();
四 继承
-
原型链继承
- 父类的实例作为子类的原型
- 可以使用父类原型上的方法,不可以传递参数
-
构造函数继承
- 在子类内使用
call()
调用父类方法,将父类this的指向修改为子类的this,相当于把实列属性复制一份给子类 - 可以父类实例中的方法,可以传递参数。不能使用父类原型的方法
- 在子类内使用
-
组合继承
- 即在子类中使用
call()
方法,再把父类的实例作为子类的原型 - 既能调用父类实例的方法,又能调用父类原型的方法,还可以传递参数
- 即在子类中使用
-
Es6 class 继承
- 使用class来创建一个子类,使用extends关键字来继承,使用super来调用父类的方法
- Class在语法上更加贴合面向对象的写法
- Class在实现继承上更加易读、易理解
- 本质上还是prototype
五 深拷贝
-
浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用
-
深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”
-
手写
var arr=[100,[{a:'hello',b:'world'}],{data:[1,2,3,4]}]; //如何深拷贝 function deepClone(obj={}){ if(typeof obj !=='object' ||obj==null){ return obj; } let result; if(obj instanceof Array) { result=[]; }else{ result={}; } for(var item in obj){ //不拷贝原型上属性 if(obj.hasOwnProperty(item){ result [item]=deepClone(obj[item]) } } return result; } let arr1=deepClone(arr); arr1[1][0].a='123456789' console.log(arr1); console.log(arr);
六 Promise
-
什么是Promise?
- Promise简单来说就是一个容器,里面存放着未来才会结束的事件(一个异步操作的结果)从语法上来说promise是一个对象
- 他可以获取异步操作的最终状态Promise是一个构造函数,对外提供统一的API,自己身上有all,reject,resolve等方法,原型上有then,catch方法
-
Promise特点?
- 状态:pending 初始 fufiled 成功 rejected 失败
- promise对象的状态不受外界影响,只有异步操作的结果可以决定当前是哪一种状态,其他任何操作无法改变
- Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可逆,只能由pending变成fufiled或者由pending变成rejected
-
Promise有哪些API
- then
- 把原来的回调分离出来,用链式调用的方式回调,then有两个回调函数,第一个成功,第二个失败
- catch
- 和then的参数一样,用来指定错误的reject的回调,在执行then方法时,如果报错会执行catch方法
- all
- 并行执行异步操作,在所有异步操作完成后回调
- racel
- 用法和all一样,只有一个异步操作完成后回调,其他没有执行完成的异步操作会继续执行
- then
-
Promise的应用场景
- Ajax,axios的get和post的封装
- 微信小程序中封装wx.requset()
- uniapp开发 uni.requser()
Promise的链式调用,解决了地狱回调
七 async/await
- async:异步的简写,用于声明一个异步的函数
- await:用于等待一个异步方法执行完成
- 特点
- async 用法它作为一个关键字放到函数前面,这个普通函数就变成了异步函数
- 异步async函数调用,跟普通函数的使用方式一样
- 异步async函数返回一个Promise
- async配合await关键字使用(阻塞代码往下执行)是异步的方式,但是是阻塞式的
- async和await优点
- 方便级联调用
- 同步代码的编写方式
- 多个参数传递
- 同步代码和异步代码一起编写
- async和await是对promise的优化
- 使用场景
- async主要处理异步操作
- 简化Promise的链式回调 最终版处理地狱回调
八 数据双向绑定
vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图。
- 具体分为四部
- 需要
observer
的数据对象进行递归遍历
,包括子属性对象的属性,都加上 setter和getter
这样的话,给这个对象的某个值赋值
,就会触发setter
,那么就能监听到了数据变化 - compile`解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
Watcher
订阅者是Observer
和Compile
之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep
)里面添加自己
2、自身必须有一个update
()方法
3、待属性变动dep.notice()
通知时,能调用自身的update()方法
,并触发Compile中绑定的回调
,则功成身退。MVVM
作为数据绑定的入口,整合Observer、Compile和Watcher三者,
通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
- 需要
九 虚拟DOM和diff算法
- 虚拟dom
用js来模拟DOM中的节点。传说中的虚拟DOM。
virtual DOM 虚拟DOM,用普通js对象来描述DOM结构,因为不是真实DOM,所以称之为虚拟DOM。
- diff算法
- diff算法就是进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方,最后用patch记录的消息去局部更新Dom。
十 组件通信
- 父传子
- 在父组件的子组件标签上绑定一个属性,挂载要传输的变量
- 在子组件中通过props来接受数据,props可以是数组也可以是对象,接受的数据可以直接使用 props:[“属性 名”] props:{属性名:数据类型}
- 子传父
- 在父组件的子组件标签上自定义一个事件,然后调用需要的方法
- 在子组件的方法中通过 this.$emit(“事件”)来触发在父组件中定义的事件,数据是以参数的形式进行传递的
- 兄弟组件通信
- 在src中新建一个Bus.js的文件,然后导出一个空的vue实例
- 在传输数据的一方引入Bus.js 然后通过Bus. e m i t ( “ 事 件 名 ” , " 参 数 " ) 来 来 派 发 事 件 , 数 据 是 以 emit(“事件名”,"参数")来来派发事件,数据是以 emit(“事件名”,"参数")来来派发事件,数据是以emit()的参数形式来传递
- 在接受的数据的一方 引入 Bus.js 然后通过 Bus.$on(“事件名”,(data)=>{data是接受的数据})
十一 vuex
概念:是一个专为vue.js开发的状态管理器,采用集中式存储的所有组件状态
-
基本使用
-
新建store.js文件,最后在main.js中引入,并挂载到实列上
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const state = {} const getters = {} const mutations = {} const actions = {} export default new Vuex.Store({ state, getters, mutations, actions })
-
-
五大属性
- state属性: 存放状态,例如你要存放的数据
- getters: 类似于共享属性,可以通过this.$store.getters来获取存放在- state里面的数据
- mutations: 唯一能改变state的状态就是通过提交mutations来改变,this.$store.commit()
- actions: 一步的mutations,可以通过dispatch来分发从而改变state
- module: 模块化
-
vue持久化
- vuex里面存放的数据,页面一经刷新会丢失:
解决办法: 存放在localStorage或者sessionStorage里面,进入页面时判断是否丢失,丢失再去localStorage或者sessionStorage里面取;
在app.vue根组件的created里面判断是否丢失,在进行上面的操作; - vuex-persistedstate 插件
- vuex里面存放的数据,页面一经刷新会丢失:
vuex的映射
state,getters需要映射在computed实例而mutations,action等需要在methods实例中。
#vuex运行机制
vuex提供数据来驱动视图,通过dispath派发actions,在其中可以做一些异步操作,然后通过commit来提交mutations,
最后mutations来更改state。
十二 keep-alive
概念:是Vue的内置组件,能在组件切换过程中将状态保留在内存中,取消组件的销毁函数,防止重复渲染DOM。
-
我们在切换路由的时候,想保存组件的状态,比如列表页面进入详情,我们想保存列表滚动的位置,我们就可以使用keep-alive保存列表页面的滚动位置。
-
组件使用keep-alive以后会新增两个生命周期 actived() deactived()
-
keep-alive用法
- 全局配置
全局保存在App.vue中 <keep-alive>把<routerView/>包裹起来
-
router.js中配置
{ path: '/child1', name: 'Child1', component: Child1, meta:{ keepAlive:true,//保存keep-alive状态 } }
-
用v-if来显示router-view是否在keep-alive中出现
<keep-alive> <router-view v-if="$route.meta.keepAlive"></router-view> </keep-alive> <router-view v-if="!$route.meta.keepAlive"></router-view>
-
使用keep-alive的标签属性, include() exclude()
<keep-alive inclue="list,detail" ></keep-alive> //include 包含标签名字被缓存 exclude 包含的标签不被缓存 //缓存名字组件中有个name属性进行定义即可
十三 自定义指令
很多时候我们需要直接操作 dom 元素,如果只是个别需要操作 dom 元素,我们可以通过 ref 获取当前 dom 元素,并对其进行操作,但是如果
特别多的时候,我们不可能每次都去写一遍 ref 还有方法,所以这时候自定义指令就可以帮你轻松解决这个问题
分为全局和局部;
-
自定义指令分为全局自定义指令和局部自定义指令
- 使用
Vue.directive('focus',{bind(el,binding){},inserted(){}})
进行全局自定义指令 - 参数1 :指令的名称
- 参数2: 是一个对象,这个对象身上,有钩子函数.
- 使用
-
钩子函数
- bind(){} 只调用一次,指令第一次绑定到元素时调用
- inserted(){}被绑定元素插入父节点时调用
- update(){}被绑定元素所在的模板更新时调用,而不论绑定值是否变化
- componentUpdated(){}被绑定元素所在模板完成一次更新周期时调用
- unbind(){}只调用一次, 指令与元素解绑时调用
实际应用
// 注册一个全局自定义指令 `v-focus` Vue.directive('focus', { // 当被绑定的元素插入到 DOM 中时 inserted: function (el) { // 聚焦元素 el.focus() } }) <input v-focus>
十四 自定义组件(组件封装)
我用vue开发的所有项目,都是采用组件化的思想开发的。一般我在搭建项目的时候,会创建一个views目录和一个commen目录和一个feature目录,views目录中放页面级的组件,commen中放公共组件(如:head(公共头组件),foot(公共底部组件)等),feature目录内放功能组件(如:swiper(轮播功能组件),tabbar(切换功能组件)、list(上拉加载更多功能组件))
首先,组件可以提升整个项目的开发效率。能够把页面抽象成多个相对独立的模块,解决了我们传统项目开发:效率低、难维护、复用性低等问题。
使用Vue.extend方法创建一个组件,然后使用Vue.component方法注册组件。但是我们一般用脚手架开发项目,每个 .vue单文件就是一个组件。在另一组件import 导入,并在components中注册,子组件需要数据,可以在props中接受定义。而子组件修改好数据后,想把数据传递给父组件。可以采用emit方法。
1.命名要用驼峰命名法
2.引入用i没import来引入,然后注册
3.页面写入标签
十五 路由守卫
router.beforeEach() 全局路由守卫的钩子函数,可以写到main.js中
beforeRouteEnter 进入组件之前触发方法
beforeRouteUpdate 组件参数更新的时候触发
beforeRouteLeave 离开组件的时候触发的钩子函数
to 即将要进入页面的路由信息
from 离开页面路由信息
next 是否继续进入进入路由 next(false)阻止进入 next()继续进入路由地址
十六 生命周期函数
-
1.创建
beforeCreate() 创建前的阶段,这个时候data中的数据,还未定义,所以不能使用
created() 最早开始使用 data和methods中数据的钩子函数 -
2.挂载
beforeMount() 指令已经解析完毕内存中已经生成dom树,还没有渲染到本地
mounted() dom已经渲染完毕,最早可以操作DOM元素钩子函数 -
3.更新
beforeUpdate() 当data的数据发生改变会执行这个钩子 内存更新,但是DOM节点还未更新
updated() 数据更新完成以后触发的方法,DOM节点已经更新 -
4.销毁
beforeDestroy()即将销毁 data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作
destroyed()已经销毁完毕 -
9.activated(组件激活时)和上面的beforeDstroy和destroyed用一样,但是如果我们需要一个实例,在销毁后再次出现的话,用beforeDestroy和destroyed的话,就太浪费性能,实例被激活时使用,用于重复激活一个实例的时候。
10.deactivated(组件未激活时):实例没有被激活的。
11.errorcaptured(错误调用):当捕获一个来自后台组件错误是被调用。
-
keep-alive 方法
actived() 组件加上keep-alive,进入组件触发的方法
deactived 离开组件的时候触发的方法。 -
errorCaptured() 组件内发生错误的时候的触发的方法
十七 常见的状态码
200 请求成功
201 创建成功
204 删除成功
400 请求的地址不存在或者包含不支持的参数
401 未授权
403 被禁用访问
404 请求的资源不存在
422 当创建一个对象时,发生一个验证错误
500 内部错误
十八 输入url到页面出现发生了什么
- 通过DNS服务器:url=>ip地址;
- 到达ip地址对应的服务器;
- 服务器接收用户的请求;
- 把处理后的结果返回给客户端;
- 客户端把结果渲染到浏览器即可,最后页面显示出来 输入了一个域名,域名要通过DNS解析找到这个域名对应的服务器地址(ip),通过TCP请求链接服务,通过 WEB服务器(apache)返回数据,浏览器根据返回数据构建DOM树,通过css渲染引擎及js解析引擎将页面渲 染出来,关闭tcp连接
十九 跨域
-
为什么会出现跨域问题
-
出于浏览器的同源策略限制,同源策略 是由NetScape提出的一个著名的安全策略,它是浏览器最核心也最基本的安 全功能
所谓的同源,指的是协议,域名,端口相同。浏览器处于安全方面的考虑,只允许本域 名下的接口交互,不同源的客户端脚本,在没有明确授权的情况下,不能读写对方的资源
-
-
什么是跨域
- 当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
-
jsonp解决跨域
-
JSONP 是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,兼容性好(兼容低版本IE),缺点是只支持get请求,不支持post请求。
核心思想:网页通过添加一个
<script>元素
,向服务器请求 JSON 数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。this.$http.jsonp('http://www.domain2.com:8080/login', { params: {}, jsonp: 'handleCallback' }).then((res) => { console.log(res);
-
-
vue中解决跨域
-
在项目根目录新建vue.config.js文件
module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:4000', //对应自己的接口 changeOrigin: true, ws: true, pathRewrite: { '^/api': '' } } } } }
-
在main.js文件,配置一下axios.defaults.baseURL = ‘/api’ 这样就可以保证动态的匹配生产和开发环境的定义前缀了
-
重启项目即可
-
二十 项目开发流程
P7小实训
一 javascript原型与原型链
- 每个函数都有一个prototype属性,被称为显示原型
- 每个实例对象都会有
_ _proto_ _
属性,其被称为隐式原型,每一个实例对象的隐式原型_ _proto_ _
属性指向自身构造函数的显式原型prototype - 每个prototype原型都有一个constructor属性,指向它关联的构造函数
- 原型链:获取对象属性时,如果对象本身没有这个属性,那就会去他的原型
__proto__
上去找,如果还查不到,就去找原型的原型,一直找到最顶层(Object.prototype
)为止。Object.prototype对象也有__proto__属性值为null。
二 作用域和自由变量
1.作用域:变量作用域:就是一个变量可以使用的范围。
2.作用域种类:
-
js中首先有一个最外层的作用域,全局作用域
-
s中可以通过函数来创建一个独立作用域称为
函数作用域
,函数可以嵌套,所以作用域也可以嵌套; -
es6新增了块级作用域
{}
比如if{} for{}
-
es6作用域,只适用于const,let
3.自由变量:当前作用域没有定义的变量
-
一个变量在当前作用域没有定义,但被使用了
-
向上级作用域,一层一层依次寻找,直达找到为止
-
如果全局作用域都没找到,则报错 xx is not defined
-
作用域链:自由变量向上级作用域一层一层查找,直到找到为止,最高找到全局作用域,这就是作用域链
-
变量提升(预解析)
**var声明的变量,function声明的函数存在变量提升 let const 不会变量提升 **
- javascript中声明并定义一个变量时,会把声明提前
- 函数声明也会把整个函数提升到作用域的最上面
- 函数表达式不能变量提升,只会把声明的 var fn 提升到作用域的最顶端,
三 闭包
- 什么是闭包?
- 要理解闭包,首先理解javascript特殊的变量作用域,变量的作用于无非就是两种:全局变量,局部变量。
- javascript语言的特殊处就是函数内部可以读取外部作用域中的变量。
- 我们有时候需要得到函数内的局部变量,但是在正常情况下,这是不能读取到的,这时候就需要用到闭包。在javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。闭包是指有权访问另一个函数作用域中的变量的函数。其本质是函数的作用域链中保存着外部函数变量对象的引用。
- (当一个函数的返回值是另外一个函数,而返回的那个函数如果调用其父函数的内部变量,且返回的那个函数在外部执行,就产生闭包)
2.闭包的应用场景
-
函数作为参数被传递
-
函数作为返回值被返回
-
实际应用(隐藏数据):为什么说隐藏数据了呢,因为普通用户只能通过get、set等api对数据进行查看和更改等操作,没法对data直接更改,达到所谓隐藏数据的效果;jquery就利用了这一特性,必须调用$.ajax()才能访问内部属性方法。
封装功能时(需要使用私有的属性和方法),
函数防抖、函数节流
单例模式3.闭包的优点
-
变量长期驻扎在内存中
-
另一个就是可以重复使用变量,并且不会造成变量污染
①全局变量可以重复使用,但是容易造成变量污染。不同的地方定义了相同的全局变量,这样就会产生混乱。”
②局部变量仅在局部作用域内有效,不可以重复使用,不会造成变量污染。
③闭包结合了全局变量和局部变量的优点。可以重复使用变量,并且不会造成变量污染
-
闭包的缺点
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
5.闭包的三个特性
1.函数嵌套函数 2.内部的函数可以访问外部函数的内部变量或参数 3.变量或参数不会被垃圾回收机制回收。
**闭包的两种写法:
1:
function a () { var num=1; function b () { alert(num) } return b; //把函数 b 返回给函数 a; } alert(a())//弹出函数 a, 值是函数 b;
2:
function a () { var num=1; return function b () { //把函数 b 返回给函数 a; alert(num=num+2) } } alert(a());//弹出函数 a, 值是函数 b;
调用方式:
//1:直接调用
a()()//内部函数的执行
//2:通过赋值在调用var f = a();
f();
四 继承
-
原型链继承
- 父类的实例作为子类的原型
- 可以使用父类原型上的方法,不可以传递参数
-
构造函数继承
- 在子类内使用
call()
调用父类方法,将父类this的指向修改为子类的this,相当于把实列属性复制一份给子类 - 可以父类实例中的方法,可以传递参数。不能使用父类原型的方法
- 在子类内使用
-
组合继承
- 即在子类中使用
call()
方法,再把父类的实例作为子类的原型 - 既能调用父类实例的方法,又能调用父类原型的方法,还可以传递参数
- 即在子类中使用
-
Es6 class 继承
- 使用class来创建一个子类,使用extends关键字来继承,使用super来调用父类的方法
- Class在语法上更加贴合面向对象的写法
- Class在实现继承上更加易读、易理解
- 本质上还是prototype
五 深拷贝
-
浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用
-
深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”
-
手写
var arr=[100,[{a:'hello',b:'world'}],{data:[1,2,3,4]}]; //如何深拷贝 function deepClone(obj={}){ if(typeof obj !=='object' ||obj==null){ return obj; } let result; if(obj instanceof Array) { result=[]; }else{ result={}; } for(var item in obj){ //不拷贝原型上属性 if(obj.hasOwnProperty(item){ result [item]=deepClone(obj[item]) } } return result; } let arr1=deepClone(arr); arr1[1][0].a='123456789' console.log(arr1); console.log(arr);
六 Promise
-
什么是Promise?
- Promise简单来说就是一个容器,里面存放着未来才会结束的事件(一个异步操作的结果)从语法上来说promise是一个对象
- 他可以获取异步操作的最终状态Promise是一个构造函数,对外提供统一的API,自己身上有all,reject,resolve等方法,原型上有then,catch方法
-
Promise特点?
- 状态:pending 初始 fufiled 成功 rejected 失败
- promise对象的状态不受外界影响,只有异步操作的结果可以决定当前是哪一种状态,其他任何操作无法改变
- Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可逆,只能由pending变成fufiled或者由pending变成rejected
-
Promise有哪些API
- then
- 把原来的回调分离出来,用链式调用的方式回调,then有两个回调函数,第一个成功,第二个失败
- catch
- 和then的参数一样,用来指定错误的reject的回调,在执行then方法时,如果报错会执行catch方法
- all
- 并行执行异步操作,在所有异步操作完成后回调
- racel
- 用法和all一样,只有一个异步操作完成后回调,其他没有执行完成的异步操作会继续执行
- then
-
Promise的应用场景
- Ajax,axios的get和post的封装
- 微信小程序中封装wx.requset()
- uniapp开发 uni.requser()
Promise的链式调用,解决了地狱回调
七 async/await
- async:异步的简写,用于声明一个异步的函数
- await:用于等待一个异步方法执行完成
- 特点
- async 用法它作为一个关键字放到函数前面,这个普通函数就变成了异步函数
- 异步async函数调用,跟普通函数的使用方式一样
- 异步async函数返回一个Promise
- async配合await关键字使用(阻塞代码往下执行)是异步的方式,但是是阻塞式的
- async和await优点
- 方便级联调用
- 同步代码的编写方式
- 多个参数传递
- 同步代码和异步代码一起编写
- async和await是对promise的优化
- 使用场景
- async主要处理异步操作
- 简化Promise的链式回调 最终版处理地狱回调
八 数据双向绑定
vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图。
- 具体分为四部
- 需要
observer
的数据对象进行递归遍历
,包括子属性对象的属性,都加上 setter和getter
这样的话,给这个对象的某个值赋值
,就会触发setter
,那么就能监听到了数据变化 - compile`解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
Watcher
订阅者是Observer
和Compile
之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep
)里面添加自己
2、自身必须有一个update
()方法
3、待属性变动dep.notice()
通知时,能调用自身的update()方法
,并触发Compile中绑定的回调
,则功成身退。MVVM
作为数据绑定的入口,整合Observer、Compile和Watcher三者,
通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
- 需要
九 虚拟DOM和diff算法
- 虚拟dom
用js来模拟DOM中的节点。传说中的虚拟DOM。
virtual DOM 虚拟DOM,用普通js对象来描述DOM结构,因为不是真实DOM,所以称之为虚拟DOM。
- diff算法
- diff算法就是进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方,最后用patch记录的消息去局部更新Dom。
十 组件通信
- 父传子
- 在父组件的子组件标签上绑定一个属性,挂载要传输的变量
- 在子组件中通过props来接受数据,props可以是数组也可以是对象,接受的数据可以直接使用 props:[“属性 名”] props:{属性名:数据类型}
- 子传父
- 在父组件的子组件标签上自定义一个事件,然后调用需要的方法
- 在子组件的方法中通过 this.$emit(“事件”)来触发在父组件中定义的事件,数据是以参数的形式进行传递的
- 兄弟组件通信
- 在src中新建一个Bus.js的文件,然后导出一个空的vue实例
- 在传输数据的一方引入Bus.js 然后通过Bus. e m i t ( “ 事 件 名 ” , " 参 数 " ) 来 来 派 发 事 件 , 数 据 是 以 emit(“事件名”,"参数")来来派发事件,数据是以 emit(“事件名”,"参数")来来派发事件,数据是以emit()的参数形式来传递
- 在接受的数据的一方 引入 Bus.js 然后通过 Bus.$on(“事件名”,(data)=>{data是接受的数据})
十一 vuex
概念:是一个专为vue.js开发的状态管理器,采用集中式存储的所有组件状态
-
基本使用
-
新建store.js文件,最后在main.js中引入,并挂载到实列上
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const state = {} const getters = {} const mutations = {} const actions = {} export default new Vuex.Store({ state, getters, mutations, actions })
-
-
五大属性
- state属性: 存放状态,例如你要存放的数据
- getters: 类似于共享属性,可以通过this.$store.getters来获取存放在- state里面的数据
- mutations: 唯一能改变state的状态就是通过提交mutations来改变,this.$store.commit()
- actions: 一步的mutations,可以通过dispatch来分发从而改变state
- module: 模块化
-
vue持久化
- vuex里面存放的数据,页面一经刷新会丢失:
解决办法: 存放在localStorage或者sessionStorage里面,进入页面时判断是否丢失,丢失再去localStorage或者sessionStorage里面取;
在app.vue根组件的created里面判断是否丢失,在进行上面的操作; - vuex-persistedstate 插件
- vuex里面存放的数据,页面一经刷新会丢失:
vuex的映射
state,getters需要映射在computed实例而mutations,action等需要在methods实例中。
#vuex运行机制
vuex提供数据来驱动视图,通过dispath派发actions,在其中可以做一些异步操作,然后通过commit来提交mutations,
最后mutations来更改state。
十二 keep-alive
概念:是Vue的内置组件,能在组件切换过程中将状态保留在内存中,取消组件的销毁函数,防止重复渲染DOM。
-
我们在切换路由的时候,想保存组件的状态,比如列表页面进入详情,我们想保存列表滚动的位置,我们就可以使用keep-alive保存列表页面的滚动位置。
-
组件使用keep-alive以后会新增两个生命周期 actived() deactived()
-
keep-alive用法
- 全局配置
全局保存在App.vue中 <keep-alive>把<routerView/>包裹起来
-
router.js中配置
{ path: '/child1', name: 'Child1', component: Child1, meta:{ keepAlive:true,//保存keep-alive状态 } }
-
用v-if来显示router-view是否在keep-alive中出现
<keep-alive> <router-view v-if="$route.meta.keepAlive"></router-view> </keep-alive> <router-view v-if="!$route.meta.keepAlive"></router-view>
-
使用keep-alive的标签属性, include() exclude()
<keep-alive inclue="list,detail" ></keep-alive> //include 包含标签名字被缓存 exclude 包含的标签不被缓存 //缓存名字组件中有个name属性进行定义即可
十三 自定义指令
很多时候我们需要直接操作 dom 元素,如果只是个别需要操作 dom 元素,我们可以通过 ref 获取当前 dom 元素,并对其进行操作,但是如果
特别多的时候,我们不可能每次都去写一遍 ref 还有方法,所以这时候自定义指令就可以帮你轻松解决这个问题
分为全局和局部;
-
自定义指令分为全局自定义指令和局部自定义指令
- 使用
Vue.directive('focus',{bind(el,binding){},inserted(){}})
进行全局自定义指令 - 参数1 :指令的名称
- 参数2: 是一个对象,这个对象身上,有钩子函数.
- 使用
-
钩子函数
- bind(){} 只调用一次,指令第一次绑定到元素时调用
- inserted(){}被绑定元素插入父节点时调用
- update(){}被绑定元素所在的模板更新时调用,而不论绑定值是否变化
- componentUpdated(){}被绑定元素所在模板完成一次更新周期时调用
- unbind(){}只调用一次, 指令与元素解绑时调用
实际应用
// 注册一个全局自定义指令 `v-focus` Vue.directive('focus', { // 当被绑定的元素插入到 DOM 中时 inserted: function (el) { // 聚焦元素 el.focus() } }) <input v-focus>
十四 自定义组件(组件封装)
我用vue开发的所有项目,都是采用组件化的思想开发的。一般我在搭建项目的时候,会创建一个views目录和一个commen目录和一个feature目录,views目录中放页面级的组件,commen中放公共组件(如:head(公共头组件),foot(公共底部组件)等),feature目录内放功能组件(如:swiper(轮播功能组件),tabbar(切换功能组件)、list(上拉加载更多功能组件))
首先,组件可以提升整个项目的开发效率。能够把页面抽象成多个相对独立的模块,解决了我们传统项目开发:效率低、难维护、复用性低等问题。
使用Vue.extend方法创建一个组件,然后使用Vue.component方法注册组件。但是我们一般用脚手架开发项目,每个 .vue单文件就是一个组件。在另一组件import 导入,并在components中注册,子组件需要数据,可以在props中接受定义。而子组件修改好数据后,想把数据传递给父组件。可以采用emit方法。
1.命名要用驼峰命名法
2.引入用i没import来引入,然后注册
3.页面写入标签
十五 路由守卫
router.beforeEach() 全局路由守卫的钩子函数,可以写到main.js中
beforeRouteEnter 进入组件之前触发方法
beforeRouteUpdate 组件参数更新的时候触发
beforeRouteLeave 离开组件的时候触发的钩子函数
to 即将要进入页面的路由信息
from 离开页面路由信息
next 是否继续进入进入路由 next(false)阻止进入 next()继续进入路由地址
十六 生命周期函数
-
1.创建
beforeCreate() 创建前的阶段,这个时候data中的数据,还未定义,所以不能使用
created() 最早开始使用 data和methods中数据的钩子函数 -
2.挂载
beforeMount() 指令已经解析完毕内存中已经生成dom树,还没有渲染到本地
mounted() dom已经渲染完毕,最早可以操作DOM元素钩子函数 -
3.更新
beforeUpdate() 当data的数据发生改变会执行这个钩子 内存更新,但是DOM节点还未更新
updated() 数据更新完成以后触发的方法,DOM节点已经更新 -
4.销毁
beforeDestroy()即将销毁 data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作
destroyed()已经销毁完毕 -
9.activated(组件激活时)和上面的beforeDstroy和destroyed用一样,但是如果我们需要一个实例,在销毁后再次出现的话,用beforeDestroy和destroyed的话,就太浪费性能,实例被激活时使用,用于重复激活一个实例的时候。
10.deactivated(组件未激活时):实例没有被激活的。
11.errorcaptured(错误调用):当捕获一个来自后台组件错误是被调用。
-
keep-alive 方法
actived() 组件加上keep-alive,进入组件触发的方法
deactived 离开组件的时候触发的方法。 -
errorCaptured() 组件内发生错误的时候的触发的方法
十七 常见的状态码
200 请求成功
201 创建成功
204 删除成功
400 请求的地址不存在或者包含不支持的参数
401 未授权
403 被禁用访问
404 请求的资源不存在
422 当创建一个对象时,发生一个验证错误
500 内部错误
十八 输入url到页面出现发生了什么
- 通过DNS服务器:url=>ip地址;
- 到达ip地址对应的服务器;
- 服务器接收用户的请求;
- 把处理后的结果返回给客户端;
- 客户端把结果渲染到浏览器即可,最后页面显示出来 输入了一个域名,域名要通过DNS解析找到这个域名对应的服务器地址(ip),通过TCP请求链接服务,通过 WEB服务器(apache)返回数据,浏览器根据返回数据构建DOM树,通过css渲染引擎及js解析引擎将页面渲 染出来,关闭tcp连接
十九 跨域
-
为什么会出现跨域问题
-
出于浏览器的同源策略限制,同源策略 是由NetScape提出的一个著名的安全策略,它是浏览器最核心也最基本的安 全功能
所谓的同源,指的是协议,域名,端口相同。浏览器处于安全方面的考虑,只允许本域 名下的接口交互,不同源的客户端脚本,在没有明确授权的情况下,不能读写对方的资源
-
-
什么是跨域
- 当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
-
jsonp解决跨域
-
JSONP 是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,兼容性好(兼容低版本IE),缺点是只支持get请求,不支持post请求。
核心思想:网页通过添加一个
<script>元素
,向服务器请求 JSON 数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。this.$http.jsonp('http://www.domain2.com:8080/login', { params: {}, jsonp: 'handleCallback' }).then((res) => { console.log(res);
-
-
vue中解决跨域
-
在项目根目录新建vue.config.js文件
module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:4000', //对应自己的接口 changeOrigin: true, ws: true, pathRewrite: { '^/api': '' } } } } }
-
在main.js文件,配置一下axios.defaults.baseURL = ‘/api’ 这样就可以保证动态的匹配生产和开发环境的定义前缀了
-
重启项目即可
-
二十 项目开发流程
P7小实训
一 javascript原型与原型链
- 每个函数都有一个prototype属性,被称为显示原型
- 每个实例对象都会有
_ _proto_ _
属性,其被称为隐式原型,每一个实例对象的隐式原型_ _proto_ _
属性指向自身构造函数的显式原型prototype - 每个prototype原型都有一个constructor属性,指向它关联的构造函数
- 原型链:获取对象属性时,如果对象本身没有这个属性,那就会去他的原型
__proto__
上去找,如果还查不到,就去找原型的原型,一直找到最顶层(Object.prototype
)为止。Object.prototype对象也有__proto__属性值为null。
二 作用域和自由变量
1.作用域:变量作用域:就是一个变量可以使用的范围。
2.作用域种类:
-
js中首先有一个最外层的作用域,全局作用域
-
s中可以通过函数来创建一个独立作用域称为
函数作用域
,函数可以嵌套,所以作用域也可以嵌套; -
es6新增了块级作用域
{}
比如if{} for{}
-
es6作用域,只适用于const,let
3.自由变量:当前作用域没有定义的变量
-
一个变量在当前作用域没有定义,但被使用了
-
向上级作用域,一层一层依次寻找,直达找到为止
-
如果全局作用域都没找到,则报错 xx is not defined
-
作用域链:自由变量向上级作用域一层一层查找,直到找到为止,最高找到全局作用域,这就是作用域链
-
变量提升(预解析)
**var声明的变量,function声明的函数存在变量提升 let const 不会变量提升 **
- javascript中声明并定义一个变量时,会把声明提前
- 函数声明也会把整个函数提升到作用域的最上面
- 函数表达式不能变量提升,只会把声明的 var fn 提升到作用域的最顶端,
三 闭包
- 什么是闭包?
- 要理解闭包,首先理解javascript特殊的变量作用域,变量的作用于无非就是两种:全局变量,局部变量。
- javascript语言的特殊处就是函数内部可以读取外部作用域中的变量。
- 我们有时候需要得到函数内的局部变量,但是在正常情况下,这是不能读取到的,这时候就需要用到闭包。在javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。闭包是指有权访问另一个函数作用域中的变量的函数。其本质是函数的作用域链中保存着外部函数变量对象的引用。
- (当一个函数的返回值是另外一个函数,而返回的那个函数如果调用其父函数的内部变量,且返回的那个函数在外部执行,就产生闭包)
2.闭包的应用场景
-
函数作为参数被传递
-
函数作为返回值被返回
-
实际应用(隐藏数据):为什么说隐藏数据了呢,因为普通用户只能通过get、set等api对数据进行查看和更改等操作,没法对data直接更改,达到所谓隐藏数据的效果;jquery就利用了这一特性,必须调用$.ajax()才能访问内部属性方法。
封装功能时(需要使用私有的属性和方法),
函数防抖、函数节流
单例模式3.闭包的优点
-
变量长期驻扎在内存中
-
另一个就是可以重复使用变量,并且不会造成变量污染
①全局变量可以重复使用,但是容易造成变量污染。不同的地方定义了相同的全局变量,这样就会产生混乱。”
②局部变量仅在局部作用域内有效,不可以重复使用,不会造成变量污染。
③闭包结合了全局变量和局部变量的优点。可以重复使用变量,并且不会造成变量污染
-
闭包的缺点
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
5.闭包的三个特性
1.函数嵌套函数 2.内部的函数可以访问外部函数的内部变量或参数 3.变量或参数不会被垃圾回收机制回收。
**闭包的两种写法:
1:
function a () { var num=1; function b () { alert(num) } return b; //把函数 b 返回给函数 a; } alert(a())//弹出函数 a, 值是函数 b;
2:
function a () { var num=1; return function b () { //把函数 b 返回给函数 a; alert(num=num+2) } } alert(a());//弹出函数 a, 值是函数 b;
调用方式:
//1:直接调用
a()()//内部函数的执行
//2:通过赋值在调用var f = a();
f();
四 继承
-
原型链继承
- 父类的实例作为子类的原型
- 可以使用父类原型上的方法,不可以传递参数
-
构造函数继承
- 在子类内使用
call()
调用父类方法,将父类this的指向修改为子类的this,相当于把实列属性复制一份给子类 - 可以父类实例中的方法,可以传递参数。不能使用父类原型的方法
- 在子类内使用
-
组合继承
- 即在子类中使用
call()
方法,再把父类的实例作为子类的原型 - 既能调用父类实例的方法,又能调用父类原型的方法,还可以传递参数
- 即在子类中使用
-
Es6 class 继承
- 使用class来创建一个子类,使用extends关键字来继承,使用super来调用父类的方法
- Class在语法上更加贴合面向对象的写法
- Class在实现继承上更加易读、易理解
- 本质上还是prototype
五 深拷贝
-
浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用
-
深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”
-
手写
var arr=[100,[{a:'hello',b:'world'}],{data:[1,2,3,4]}]; //如何深拷贝 function deepClone(obj={}){ if(typeof obj !=='object' ||obj==null){ return obj; } let result; if(obj instanceof Array) { result=[]; }else{ result={}; } for(var item in obj){ //不拷贝原型上属性 if(obj.hasOwnProperty(item){ result [item]=deepClone(obj[item]) } } return result; } let arr1=deepClone(arr); arr1[1][0].a='123456789' console.log(arr1); console.log(arr);
六 Promise
-
什么是Promise?
- Promise简单来说就是一个容器,里面存放着未来才会结束的事件(一个异步操作的结果)从语法上来说promise是一个对象
- 他可以获取异步操作的最终状态Promise是一个构造函数,对外提供统一的API,自己身上有all,reject,resolve等方法,原型上有then,catch方法
-
Promise特点?
- 状态:pending 初始 fufiled 成功 rejected 失败
- promise对象的状态不受外界影响,只有异步操作的结果可以决定当前是哪一种状态,其他任何操作无法改变
- Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可逆,只能由pending变成fufiled或者由pending变成rejected
-
Promise有哪些API
- then
- 把原来的回调分离出来,用链式调用的方式回调,then有两个回调函数,第一个成功,第二个失败
- catch
- 和then的参数一样,用来指定错误的reject的回调,在执行then方法时,如果报错会执行catch方法
- all
- 并行执行异步操作,在所有异步操作完成后回调
- racel
- 用法和all一样,只有一个异步操作完成后回调,其他没有执行完成的异步操作会继续执行
- then
-
Promise的应用场景
- Ajax,axios的get和post的封装
- 微信小程序中封装wx.requset()
- uniapp开发 uni.requser()
Promise的链式调用,解决了地狱回调
七 async/await
- async:异步的简写,用于声明一个异步的函数
- await:用于等待一个异步方法执行完成
- 特点
- async 用法它作为一个关键字放到函数前面,这个普通函数就变成了异步函数
- 异步async函数调用,跟普通函数的使用方式一样
- 异步async函数返回一个Promise
- async配合await关键字使用(阻塞代码往下执行)是异步的方式,但是是阻塞式的
- async和await优点
- 方便级联调用
- 同步代码的编写方式
- 多个参数传递
- 同步代码和异步代码一起编写
- async和await是对promise的优化
- 使用场景
- async主要处理异步操作
- 简化Promise的链式回调 最终版处理地狱回调
八 数据双向绑定
``vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图。
- 具体分为四部
- 需要`observer`的数据对象进行`递归遍历`,包括子属性对象的属性,都`加上 setter和getter`
这样的话,给这个对象的某个值`赋值`,就会触发`setter`,那么就能监听到了数据变化
- compile`解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
- `Watcher`订阅者是`Observer`和`Compile`之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(`dep`)里面添加自己
2、自身必须有一个`update`()方法
3、待属性变动`dep.notice()`通知时,能调用自身的`update()方法`,并触发`Compile中绑定的回调`,则功成身退。
- `MVVM`作为数据绑定的入口,`整合Observer、Compile和Watcher三者,`通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
###### 九 虚拟DOM和diff算法
- 虚拟dom
用js来模拟DOM中的节点。传说中的虚拟DOM。
virtual DOM 虚拟DOM,用普通js对象来描述DOM结构,因为不是真实DOM,所以称之为虚拟DOM。
- diff算法
- diff算法就是进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方,最后用patch记录的消息去局部更新Dom。
###### 十 组件通信
- 父传子
- 在父组件的子组件标签上绑定一个属性,挂载要传输的变量
- 在子组件中通过props来接受数据,props可以是数组也可以是对象,接受的数据可以直接使用 props:["属性 名"] props:{属性名:数据类型}
- 子传父
- 在父组件的子组件标签上自定义一个事件,然后调用需要的方法
- 在子组件的方法中通过 this.$emit("事件")来触发在父组件中定义的事件,数据是以参数的形式进行传递的
- 兄弟组件通信
- 在src中新建一个Bus.js的文件,然后导出一个空的vue实例
- 在传输数据的一方引入Bus.js 然后通过Bus.$emit(“事件名”,"参数")来来派发事件,数据是以$emit()的参数形式来传递
- 在接受的数据的一方 引入 Bus.js 然后通过 Bus.$on("事件名",(data)=>{data是接受的数据})
###### 十一 vuex
`概念:是一个专为vue.js开发的状态管理器,采用集中式存储的所有组件状态
-
基本使用
-
新建store.js文件,最后在main.js中引入,并挂载到实列上
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const state = {} const getters = {} const mutations = {} const actions = {} export default new Vuex.Store({ state, getters, mutations, actions })
-
-
五大属性
- state属性: 存放状态,例如你要存放的数据
- getters: 类似于共享属性,可以通过this.$store.getters来获取存放在- state里面的数据
- mutations: 唯一能改变state的状态就是通过提交mutations来改变,this.$store.commit()
- actions: 一步的mutations,可以通过dispatch来分发从而改变state
- module: 模块化
-
vue持久化
- vuex里面存放的数据,页面一经刷新会丢失:
解决办法: 存放在localStorage或者sessionStorage里面,进入页面时判断是否丢失,丢失再去localStorage或者sessionStorage里面取;
在app.vue根组件的created里面判断是否丢失,在进行上面的操作; - vuex-persistedstate 插件
- vuex里面存放的数据,页面一经刷新会丢失:
vuex的映射
state,getters需要映射在computed实例而mutations,action等需要在methods实例中。
#vuex运行机制
vuex提供数据来驱动视图,通过dispath派发actions,在其中可以做一些异步操作,然后通过commit来提交mutations,
最后mutations来更改state。
十二 keep-alive
概念:是Vue的内置组件,能在组件切换过程中将状态保留在内存中,取消组件的销毁函数,防止重复渲染DOM。
-
我们在切换路由的时候,想保存组件的状态,比如列表页面进入详情,我们想保存列表滚动的位置,我们就可以使用keep-alive保存列表页面的滚动位置。
-
组件使用keep-alive以后会新增两个生命周期 actived() deactived()
-
keep-alive用法
- 全局配置
全局保存在App.vue中 <keep-alive>把<routerView/>包裹起来
-
router.js中配置
{ path: '/child1', name: 'Child1', component: Child1, meta:{ keepAlive:true,//保存keep-alive状态 } }
-
用v-if来显示router-view是否在keep-alive中出现
<keep-alive> <router-view v-if="$route.meta.keepAlive"></router-view> </keep-alive> <router-view v-if="!$route.meta.keepAlive"></router-view>
-
使用keep-alive的标签属性, include() exclude()
<keep-alive inclue="list,detail" ></keep-alive> //include 包含标签名字被缓存 exclude 包含的标签不被缓存 //缓存名字组件中有个name属性进行定义即可
十三 自定义指令
很多时候我们需要直接操作 dom 元素,如果只是个别需要操作 dom 元素,我们可以通过 ref 获取当前 dom 元素,并对其进行操作,但是如果
特别多的时候,我们不可能每次都去写一遍 ref 还有方法,所以这时候自定义指令就可以帮你轻松解决这个问题
分为全局和局部;
-
自定义指令分为全局自定义指令和局部自定义指令
- 使用
Vue.directive('focus',{bind(el,binding){},inserted(){}})
进行全局自定义指令 - 参数1 :指令的名称
- 参数2: 是一个对象,这个对象身上,有钩子函数.
- 使用
-
钩子函数
- bind(){} 只调用一次,指令第一次绑定到元素时调用
- inserted(){}被绑定元素插入父节点时调用
- update(){}被绑定元素所在的模板更新时调用,而不论绑定值是否变化
- componentUpdated(){}被绑定元素所在模板完成一次更新周期时调用
- unbind(){}只调用一次, 指令与元素解绑时调用
实际应用
// 注册一个全局自定义指令 `v-focus` Vue.directive('focus', { // 当被绑定的元素插入到 DOM 中时 inserted: function (el) { // 聚焦元素 el.focus() } }) <input v-focus>
十四 自定义组件(组件封装)
我用vue开发的所有项目,都是采用组件化的思想开发的。一般我在搭建项目的时候,会创建一个views目录和一个commen目录和一个feature目录,views目录中放页面级的组件,commen中放公共组件(如:head(公共头组件),foot(公共底部组件)等),feature目录内放功能组件(如:swiper(轮播功能组件),tabbar(切换功能组件)、list(上拉加载更多功能组件))
首先,组件可以提升整个项目的开发效率。能够把页面抽象成多个相对独立的模块,解决了我们传统项目开发:效率低、难维护、复用性低等问题。
使用Vue.extend方法创建一个组件,然后使用Vue.component方法注册组件。但是我们一般用脚手架开发项目,每个 .vue单文件就是一个组件。在另一组件import 导入,并在components中注册,子组件需要数据,可以在props中接受定义。而子组件修改好数据后,想把数据传递给父组件。可以采用emit方法。
1.命名要用驼峰命名法
2.引入用i没import来引入,然后注册
3.页面写入标签
十五 路由守卫
``router.beforeEach() 全局路由守卫的钩子函数,可以写到main.js中
beforeRouteEnter 进入组件之前触发方法
beforeRouteUpdate 组件参数更新的时候触发
beforeRouteLeave 离开组件的时候触发的钩子函数
to 即将要进入页面的路由信息
from 离开页面路由信息
next 是否继续进入进入路由 next(false)阻止进入 next()继续进入路由地址
###### 十六 生命周期函数
- 1.创建
beforeCreate() 创建前的阶段,这个时候data中的数据,还未定义,所以不能使用
created() 最早开始使用 data和methods中数据的钩子函数
- 2.挂载
beforeMount() 指令已经解析完毕内存中已经生成dom树,还没有渲染到本地
mounted() dom已经渲染完毕,最早可以操作DOM元素钩子函数
- 3.更新
beforeUpdate() 当data的数据发生改变会执行这个钩子 内存更新,但是DOM节点还未更新
updated() 数据更新完成以后触发的方法,DOM节点已经更新
- 4.销毁
beforeDestroy()即将销毁 data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作
destroyed()已经销毁完毕
- 9.activated(组件激活时)和上面的beforeDstroy和destroyed用一样,但是如果我们需要一个实例,在销毁后再次出现的话,用beforeDestroy和destroyed的话,就太浪费性能,实例被激活时使用,用于重复激活一个实例的时候。
10.deactivated(组件未激活时):实例没有被激活的。
11.errorcaptured(错误调用):当捕获一个来自后台组件错误是被调用。
- keep-alive 方法
actived() 组件加上keep-alive,进入组件触发的方法
deactived 离开组件的时候触发的方法。
- errorCaptured() 组件内发生错误的时候的触发的方法
###### 十七 常见的状态码
200 请求成功
201 创建成功
204 删除成功
400 请求的地址不存在或者包含不支持的参数
401 未授权
403 被禁用访问
404 请求的资源不存在
422 当创建一个对象时,发生一个验证错误
500 内部错误
###### 十八 输入url到页面出现发生了什么
1. 通过DNS服务器:url=>ip地址;
2. 到达ip地址对应的服务器;
3. 服务器接收用户的请求;
4. 把处理后的结果返回给客户端;
5. 客户端把结果渲染到浏览器即可,最后页面显示出来 输入了一个域名,域名要通过DNS解析找到这个域名对应的服务器地址(ip),通过TCP请求链接服务,通过 WEB服务器(apache)返回数据,浏览器根据返回数据构建DOM树,通过css渲染引擎及js解析引擎将页面渲 染出来,关闭tcp连接
###### 十九 跨域
- 为什么会出现跨域问题
- 出于浏览器的同源策略限制,同源策略 是由NetScape提出的一个著名的安全策略,它是浏览器最核心也最基本的安 全功能
所谓的同源,指的是协议,域名,端口相同。浏览器处于安全方面的考虑,只允许本域 名下的接口交互,不同源的客户端脚本,在没有明确授权的情况下,不能读写对方的资源
- 什么是跨域
- 当一个请求url的**协议、域名、端口**三者之间任意一个与当前页面url不同即为跨域
- jsonp解决跨域
- JSONP 是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,兼容性好(兼容低版本IE),缺点是只支持get请求,不支持post请求。
核心思想:网页通过添加一个`<script>元素`,向服务器请求 JSON 数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。
```
this.$http.jsonp('http://www.domain2.com:8080/login', {
params: {},
jsonp: 'handleCallback'
}).then((res) => {
console.log(res);
```
- vue中解决跨域
- 在项目根目录新建vue.config.js文件
```
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:4000', //对应自己的接口
changeOrigin: true,
ws: true,
pathRewrite: {
'^/api': ''
}
}
}
}
}
```
- 在main.js文件,配置一下axios.defaults.baseURL = '/api' 这样就可以保证动态的匹配生产和开发环境的定义前缀了
- 重启项目即可
v