2020-12-03

P7小实训

一 javascript原型与原型链
  1. 每个函数都有一个prototype属性,被称为显示原型
  2. 每个实例对象都会有_ _proto_ _属性,其被称为隐式原型,每一个实例对象的隐式原型_ _proto_ _属性指向自身构造函数的显式原型prototype
  3. 每个prototype原型都有一个constructor属性,指向它关联的构造函数
  4. 原型链:获取对象属性时,如果对象本身没有这个属性,那就会去他的原型__proto__上去找,如果还查不到,就去找原型的原型,一直找到最顶层(Object.prototype)为止。Object.prototype对象也有__proto__属性值为null。
二 作用域和自由变量

1.作用域:变量作用域:就是一个变量可以使用的范围。

2.作用域种类:

  • js中首先有一个最外层的作用域,全局作用域

  • s中可以通过函数来创建一个独立作用域称为函数作用域,函数可以嵌套,所以作用域也可以嵌套;

  • es6新增了块级作用域{} 比如if{} for{}

  • es6作用域,只适用于const,let

3.自由变量:当前作用域没有定义的变量

  • 一个变量在当前作用域没有定义,但被使用了

  • 向上级作用域,一层一层依次寻找,直达找到为止

  • 如果全局作用域都没找到,则报错 xx is not defined

  1. 作用域链:自由变量向上级作用域一层一层查找,直到找到为止,最高找到全局作用域,这就是作用域链

  2. 变量提升(预解析)

    **var声明的变量,function声明的函数存在变量提升 let const 不会变量提升 **

    • javascript中声明并定义一个变量时,会把声明提前
    • 函数声明也会把整个函数提升到作用域的最上面
    • 函数表达式不能变量提升,只会把声明的 var fn 提升到作用域的最顶端,
三 闭包
  1. 什么是闭包?
  • 要理解闭包,首先理解javascript特殊的变量作用域,变量的作用于无非就是两种:全局变量,局部变量。
  • javascript语言的特殊处就是函数内部可以读取外部作用域中的变量。
  • 我们有时候需要得到函数内的局部变量,但是在正常情况下,这是不能读取到的,这时候就需要用到闭包。在javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。闭包是指有权访问另一个函数作用域中的变量的函数。其本质是函数的作用域链中保存着外部函数变量对象的引用。
  • (当一个函数的返回值是另外一个函数,而返回的那个函数如果调用其父函数的内部变量,且返回的那个函数在外部执行,就产生闭包)

2.闭包的应用场景

  • 函数作为参数被传递

  • 函数作为返回值被返回

  • 实际应用(隐藏数据):为什么说隐藏数据了呢,因为普通用户只能通过get、set等api对数据进行查看和更改等操作,没法对data直接更改,达到所谓隐藏数据的效果;jquery就利用了这一特性,必须调用$.ajax()才能访问内部属性方法。
    封装功能时(需要使用私有的属性和方法),
    函数防抖、函数节流
    单例模式

    3.闭包的优点

  • 变量长期驻扎在内存中

  • 另一个就是可以重复使用变量,并且不会造成变量污染
    ①全局变量可以重复使用,但是容易造成变量污染。不同的地方定义了相同的全局变量,这样就会产生混乱。”
    ②局部变量仅在局部作用域内有效,不可以重复使用,不会造成变量污染。
    ③闭包结合了全局变量和局部变量的优点。可以重复使用变量,并且不会造成变量污染

  1. 闭包的缺点

    由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在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();

四 继承
  1. 原型链继承

    • 父类的实例作为子类的原型
    • 可以使用父类原型上的方法,不可以传递参数
  2. 构造函数继承

    • 在子类内使用call()调用父类方法,将父类this的指向修改为子类的this,相当于把实列属性复制一份给子类
    • 可以父类实例中的方法,可以传递参数。不能使用父类原型的方法
  3. 组合继承

    • 即在子类中使用call()方法,再把父类的实例作为子类的原型
    • 既能调用父类实例的方法,又能调用父类原型的方法,还可以传递参数
  4. Es6 class 继承

    • 使用class来创建一个子类,使用extends关键字来继承,使用super来调用父类的方法
    • Class在语法上更加贴合面向对象的写法
    • Class在实现继承上更加易读、易理解
    • 本质上还是prototype
五 深拷贝
  1. 浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用

  2. 深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”

  3. 手写

    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
  1. 什么是Promise?

    • Promise简单来说就是一个容器,里面存放着未来才会结束的事件(一个异步操作的结果)从语法上来说promise是一个对象
    • 他可以获取异步操作的最终状态Promise是一个构造函数,对外提供统一的API,自己身上有all,reject,resolve等方法,原型上有then,catch方法
  2. Promise特点?

    • 状态:pending 初始 fufiled 成功 rejected 失败
  • promise对象的状态不受外界影响,只有异步操作的结果可以决定当前是哪一种状态,其他任何操作无法改变
    • Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可逆,只能由pending变成fufiled或者由pending变成rejected
  1. Promise有哪些API

    • then
      • 把原来的回调分离出来,用链式调用的方式回调,then有两个回调函数,第一个成功,第二个失败
    • catch
      • 和then的参数一样,用来指定错误的reject的回调,在执行then方法时,如果报错会执行catch方法
    • all
      • 并行执行异步操作,在所有异步操作完成后回调
    • racel
      • 用法和all一样,只有一个异步操作完成后回调,其他没有执行完成的异步操作会继续执行
  2. 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订阅者是ObserverCompile之间通信的桥梁,主要做的事情是:
      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的映射

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’ 这样就可以保证动态的匹配生产和开发环境的定义前缀了

    • 重启项目即可

二十 项目开发流程

P7小实训

一 javascript原型与原型链
  1. 每个函数都有一个prototype属性,被称为显示原型
  2. 每个实例对象都会有_ _proto_ _属性,其被称为隐式原型,每一个实例对象的隐式原型_ _proto_ _属性指向自身构造函数的显式原型prototype
  3. 每个prototype原型都有一个constructor属性,指向它关联的构造函数
  4. 原型链:获取对象属性时,如果对象本身没有这个属性,那就会去他的原型__proto__上去找,如果还查不到,就去找原型的原型,一直找到最顶层(Object.prototype)为止。Object.prototype对象也有__proto__属性值为null。
二 作用域和自由变量

1.作用域:变量作用域:就是一个变量可以使用的范围。

2.作用域种类:

  • js中首先有一个最外层的作用域,全局作用域

  • s中可以通过函数来创建一个独立作用域称为函数作用域,函数可以嵌套,所以作用域也可以嵌套;

  • es6新增了块级作用域{} 比如if{} for{}

  • es6作用域,只适用于const,let

3.自由变量:当前作用域没有定义的变量

  • 一个变量在当前作用域没有定义,但被使用了

  • 向上级作用域,一层一层依次寻找,直达找到为止

  • 如果全局作用域都没找到,则报错 xx is not defined

  1. 作用域链:自由变量向上级作用域一层一层查找,直到找到为止,最高找到全局作用域,这就是作用域链

  2. 变量提升(预解析)

    **var声明的变量,function声明的函数存在变量提升 let const 不会变量提升 **

    • javascript中声明并定义一个变量时,会把声明提前
    • 函数声明也会把整个函数提升到作用域的最上面
    • 函数表达式不能变量提升,只会把声明的 var fn 提升到作用域的最顶端,
三 闭包
  1. 什么是闭包?
  • 要理解闭包,首先理解javascript特殊的变量作用域,变量的作用于无非就是两种:全局变量,局部变量。
  • javascript语言的特殊处就是函数内部可以读取外部作用域中的变量。
  • 我们有时候需要得到函数内的局部变量,但是在正常情况下,这是不能读取到的,这时候就需要用到闭包。在javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。闭包是指有权访问另一个函数作用域中的变量的函数。其本质是函数的作用域链中保存着外部函数变量对象的引用。
  • (当一个函数的返回值是另外一个函数,而返回的那个函数如果调用其父函数的内部变量,且返回的那个函数在外部执行,就产生闭包)

2.闭包的应用场景

  • 函数作为参数被传递

  • 函数作为返回值被返回

  • 实际应用(隐藏数据):为什么说隐藏数据了呢,因为普通用户只能通过get、set等api对数据进行查看和更改等操作,没法对data直接更改,达到所谓隐藏数据的效果;jquery就利用了这一特性,必须调用$.ajax()才能访问内部属性方法。
    封装功能时(需要使用私有的属性和方法),
    函数防抖、函数节流
    单例模式

    3.闭包的优点

  • 变量长期驻扎在内存中

  • 另一个就是可以重复使用变量,并且不会造成变量污染
    ①全局变量可以重复使用,但是容易造成变量污染。不同的地方定义了相同的全局变量,这样就会产生混乱。”
    ②局部变量仅在局部作用域内有效,不可以重复使用,不会造成变量污染。
    ③闭包结合了全局变量和局部变量的优点。可以重复使用变量,并且不会造成变量污染

  1. 闭包的缺点

    由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在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();

四 继承
  1. 原型链继承

    • 父类的实例作为子类的原型
    • 可以使用父类原型上的方法,不可以传递参数
  2. 构造函数继承

    • 在子类内使用call()调用父类方法,将父类this的指向修改为子类的this,相当于把实列属性复制一份给子类
    • 可以父类实例中的方法,可以传递参数。不能使用父类原型的方法
  3. 组合继承

    • 即在子类中使用call()方法,再把父类的实例作为子类的原型
    • 既能调用父类实例的方法,又能调用父类原型的方法,还可以传递参数
  4. Es6 class 继承

    • 使用class来创建一个子类,使用extends关键字来继承,使用super来调用父类的方法
    • Class在语法上更加贴合面向对象的写法
    • Class在实现继承上更加易读、易理解
    • 本质上还是prototype
五 深拷贝
  1. 浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用

  2. 深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”

  3. 手写

    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
  1. 什么是Promise?

    • Promise简单来说就是一个容器,里面存放着未来才会结束的事件(一个异步操作的结果)从语法上来说promise是一个对象
    • 他可以获取异步操作的最终状态Promise是一个构造函数,对外提供统一的API,自己身上有all,reject,resolve等方法,原型上有then,catch方法
  2. Promise特点?

    • 状态:pending 初始 fufiled 成功 rejected 失败
  • promise对象的状态不受外界影响,只有异步操作的结果可以决定当前是哪一种状态,其他任何操作无法改变
    • Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可逆,只能由pending变成fufiled或者由pending变成rejected
  1. Promise有哪些API

    • then
      • 把原来的回调分离出来,用链式调用的方式回调,then有两个回调函数,第一个成功,第二个失败
    • catch
      • 和then的参数一样,用来指定错误的reject的回调,在执行then方法时,如果报错会执行catch方法
    • all
      • 并行执行异步操作,在所有异步操作完成后回调
    • racel
      • 用法和all一样,只有一个异步操作完成后回调,其他没有执行完成的异步操作会继续执行
  2. 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订阅者是ObserverCompile之间通信的桥梁,主要做的事情是:
      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的映射

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’ 这样就可以保证动态的匹配生产和开发环境的定义前缀了

    • 重启项目即可

二十 项目开发流程

P7小实训

一 javascript原型与原型链
  1. 每个函数都有一个prototype属性,被称为显示原型
  2. 每个实例对象都会有_ _proto_ _属性,其被称为隐式原型,每一个实例对象的隐式原型_ _proto_ _属性指向自身构造函数的显式原型prototype
  3. 每个prototype原型都有一个constructor属性,指向它关联的构造函数
  4. 原型链:获取对象属性时,如果对象本身没有这个属性,那就会去他的原型__proto__上去找,如果还查不到,就去找原型的原型,一直找到最顶层(Object.prototype)为止。Object.prototype对象也有__proto__属性值为null。
二 作用域和自由变量

1.作用域:变量作用域:就是一个变量可以使用的范围。

2.作用域种类:

  • js中首先有一个最外层的作用域,全局作用域

  • s中可以通过函数来创建一个独立作用域称为函数作用域,函数可以嵌套,所以作用域也可以嵌套;

  • es6新增了块级作用域{} 比如if{} for{}

  • es6作用域,只适用于const,let

3.自由变量:当前作用域没有定义的变量

  • 一个变量在当前作用域没有定义,但被使用了

  • 向上级作用域,一层一层依次寻找,直达找到为止

  • 如果全局作用域都没找到,则报错 xx is not defined

  1. 作用域链:自由变量向上级作用域一层一层查找,直到找到为止,最高找到全局作用域,这就是作用域链

  2. 变量提升(预解析)

    **var声明的变量,function声明的函数存在变量提升 let const 不会变量提升 **

    • javascript中声明并定义一个变量时,会把声明提前
    • 函数声明也会把整个函数提升到作用域的最上面
    • 函数表达式不能变量提升,只会把声明的 var fn 提升到作用域的最顶端,
三 闭包
  1. 什么是闭包?
  • 要理解闭包,首先理解javascript特殊的变量作用域,变量的作用于无非就是两种:全局变量,局部变量。
  • javascript语言的特殊处就是函数内部可以读取外部作用域中的变量。
  • 我们有时候需要得到函数内的局部变量,但是在正常情况下,这是不能读取到的,这时候就需要用到闭包。在javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。闭包是指有权访问另一个函数作用域中的变量的函数。其本质是函数的作用域链中保存着外部函数变量对象的引用。
  • (当一个函数的返回值是另外一个函数,而返回的那个函数如果调用其父函数的内部变量,且返回的那个函数在外部执行,就产生闭包)

2.闭包的应用场景

  • 函数作为参数被传递

  • 函数作为返回值被返回

  • 实际应用(隐藏数据):为什么说隐藏数据了呢,因为普通用户只能通过get、set等api对数据进行查看和更改等操作,没法对data直接更改,达到所谓隐藏数据的效果;jquery就利用了这一特性,必须调用$.ajax()才能访问内部属性方法。
    封装功能时(需要使用私有的属性和方法),
    函数防抖、函数节流
    单例模式

    3.闭包的优点

  • 变量长期驻扎在内存中

  • 另一个就是可以重复使用变量,并且不会造成变量污染
    ①全局变量可以重复使用,但是容易造成变量污染。不同的地方定义了相同的全局变量,这样就会产生混乱。”
    ②局部变量仅在局部作用域内有效,不可以重复使用,不会造成变量污染。
    ③闭包结合了全局变量和局部变量的优点。可以重复使用变量,并且不会造成变量污染

  1. 闭包的缺点

    由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在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();

四 继承
  1. 原型链继承

    • 父类的实例作为子类的原型
    • 可以使用父类原型上的方法,不可以传递参数
  2. 构造函数继承

    • 在子类内使用call()调用父类方法,将父类this的指向修改为子类的this,相当于把实列属性复制一份给子类
    • 可以父类实例中的方法,可以传递参数。不能使用父类原型的方法
  3. 组合继承

    • 即在子类中使用call()方法,再把父类的实例作为子类的原型
    • 既能调用父类实例的方法,又能调用父类原型的方法,还可以传递参数
  4. Es6 class 继承

    • 使用class来创建一个子类,使用extends关键字来继承,使用super来调用父类的方法
    • Class在语法上更加贴合面向对象的写法
    • Class在实现继承上更加易读、易理解
    • 本质上还是prototype
五 深拷贝
  1. 浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用

  2. 深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”

  3. 手写

    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
  1. 什么是Promise?

    • Promise简单来说就是一个容器,里面存放着未来才会结束的事件(一个异步操作的结果)从语法上来说promise是一个对象
    • 他可以获取异步操作的最终状态Promise是一个构造函数,对外提供统一的API,自己身上有all,reject,resolve等方法,原型上有then,catch方法
  2. Promise特点?

    • 状态:pending 初始 fufiled 成功 rejected 失败
  • promise对象的状态不受外界影响,只有异步操作的结果可以决定当前是哪一种状态,其他任何操作无法改变
    • Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可逆,只能由pending变成fufiled或者由pending变成rejected
  1. Promise有哪些API

    • then
      • 把原来的回调分离出来,用链式调用的方式回调,then有两个回调函数,第一个成功,第二个失败
    • catch
      • 和then的参数一样,用来指定错误的reject的回调,在执行then方法时,如果报错会执行catch方法
    • all
      • 并行执行异步操作,在所有异步操作完成后回调
    • racel
      • 用法和all一样,只有一个异步操作完成后回调,其他没有执行完成的异步操作会继续执行
  2. 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订阅者是ObserverCompile之间通信的桥梁,主要做的事情是:
      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的映射

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’ 这样就可以保证动态的匹配生产和开发环境的定义前缀了

    • 重启项目即可

二十 项目开发流程

P7小实训

一 javascript原型与原型链
  1. 每个函数都有一个prototype属性,被称为显示原型
  2. 每个实例对象都会有_ _proto_ _属性,其被称为隐式原型,每一个实例对象的隐式原型_ _proto_ _属性指向自身构造函数的显式原型prototype
  3. 每个prototype原型都有一个constructor属性,指向它关联的构造函数
  4. 原型链:获取对象属性时,如果对象本身没有这个属性,那就会去他的原型__proto__上去找,如果还查不到,就去找原型的原型,一直找到最顶层(Object.prototype)为止。Object.prototype对象也有__proto__属性值为null。
二 作用域和自由变量

1.作用域:变量作用域:就是一个变量可以使用的范围。

2.作用域种类:

  • js中首先有一个最外层的作用域,全局作用域

  • s中可以通过函数来创建一个独立作用域称为函数作用域,函数可以嵌套,所以作用域也可以嵌套;

  • es6新增了块级作用域{} 比如if{} for{}

  • es6作用域,只适用于const,let

3.自由变量:当前作用域没有定义的变量

  • 一个变量在当前作用域没有定义,但被使用了

  • 向上级作用域,一层一层依次寻找,直达找到为止

  • 如果全局作用域都没找到,则报错 xx is not defined

  1. 作用域链:自由变量向上级作用域一层一层查找,直到找到为止,最高找到全局作用域,这就是作用域链

  2. 变量提升(预解析)

    **var声明的变量,function声明的函数存在变量提升 let const 不会变量提升 **

    • javascript中声明并定义一个变量时,会把声明提前
    • 函数声明也会把整个函数提升到作用域的最上面
    • 函数表达式不能变量提升,只会把声明的 var fn 提升到作用域的最顶端,
三 闭包
  1. 什么是闭包?
  • 要理解闭包,首先理解javascript特殊的变量作用域,变量的作用于无非就是两种:全局变量,局部变量。
  • javascript语言的特殊处就是函数内部可以读取外部作用域中的变量。
  • 我们有时候需要得到函数内的局部变量,但是在正常情况下,这是不能读取到的,这时候就需要用到闭包。在javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。闭包是指有权访问另一个函数作用域中的变量的函数。其本质是函数的作用域链中保存着外部函数变量对象的引用。
  • (当一个函数的返回值是另外一个函数,而返回的那个函数如果调用其父函数的内部变量,且返回的那个函数在外部执行,就产生闭包)

2.闭包的应用场景

  • 函数作为参数被传递

  • 函数作为返回值被返回

  • 实际应用(隐藏数据):为什么说隐藏数据了呢,因为普通用户只能通过get、set等api对数据进行查看和更改等操作,没法对data直接更改,达到所谓隐藏数据的效果;jquery就利用了这一特性,必须调用$.ajax()才能访问内部属性方法。
    封装功能时(需要使用私有的属性和方法),
    函数防抖、函数节流
    单例模式

    3.闭包的优点

  • 变量长期驻扎在内存中

  • 另一个就是可以重复使用变量,并且不会造成变量污染
    ①全局变量可以重复使用,但是容易造成变量污染。不同的地方定义了相同的全局变量,这样就会产生混乱。”
    ②局部变量仅在局部作用域内有效,不可以重复使用,不会造成变量污染。
    ③闭包结合了全局变量和局部变量的优点。可以重复使用变量,并且不会造成变量污染

  1. 闭包的缺点

    由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在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();

四 继承
  1. 原型链继承

    • 父类的实例作为子类的原型
    • 可以使用父类原型上的方法,不可以传递参数
  2. 构造函数继承

    • 在子类内使用call()调用父类方法,将父类this的指向修改为子类的this,相当于把实列属性复制一份给子类
    • 可以父类实例中的方法,可以传递参数。不能使用父类原型的方法
  3. 组合继承

    • 即在子类中使用call()方法,再把父类的实例作为子类的原型
    • 既能调用父类实例的方法,又能调用父类原型的方法,还可以传递参数
  4. Es6 class 继承

    • 使用class来创建一个子类,使用extends关键字来继承,使用super来调用父类的方法
    • Class在语法上更加贴合面向对象的写法
    • Class在实现继承上更加易读、易理解
    • 本质上还是prototype
五 深拷贝
  1. 浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用

  2. 深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”

  3. 手写

    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
  1. 什么是Promise?

    • Promise简单来说就是一个容器,里面存放着未来才会结束的事件(一个异步操作的结果)从语法上来说promise是一个对象
    • 他可以获取异步操作的最终状态Promise是一个构造函数,对外提供统一的API,自己身上有all,reject,resolve等方法,原型上有then,catch方法
  2. Promise特点?

    • 状态:pending 初始 fufiled 成功 rejected 失败
  • promise对象的状态不受外界影响,只有异步操作的结果可以决定当前是哪一种状态,其他任何操作无法改变
    • Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可逆,只能由pending变成fufiled或者由pending变成rejected
  1. Promise有哪些API

    • then
      • 把原来的回调分离出来,用链式调用的方式回调,then有两个回调函数,第一个成功,第二个失败
    • catch
      • 和then的参数一样,用来指定错误的reject的回调,在执行then方法时,如果报错会执行catch方法
    • all
      • 并行执行异步操作,在所有异步操作完成后回调
    • racel
      • 用法和all一样,只有一个异步操作完成后回调,其他没有执行完成的异步操作会继续执行
  2. 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的映射

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值