Vue2和Vue3技术整理3 - 高级篇
阅读原文时间:2022年02月09日阅读:1

3、高级篇

前言

3.1、回顾浏览器本地存储

  • 就是localstorage和sessionstorage这两个( 前者浏览器关闭不会清空,后者关闭浏览器会清空 ),二者常用的API都一模一样,二者里面存的数据都是key-value的形式

    • 存数据 setItem( 'key', 'value' ) 使用:LocalStorage.setItem( 'key' , 'value' )其他的都是差不多的
    • 取数据 getItem( 'key' ) 注:若key不存在,则:此API返回值是null( 若key是对象字符串 那么用JSON.parse()转成对象 返回值也是null )
    • 删除某一个数据 removeItem()
    • 清空所有 clear()
  • 二者存储的内容大小一般为5M的字符串( 不同浏览器可能会不一样 )

3.3、组件的自定义事件

3.3.1、绑定自定义事件
  • 这里实现方式有两种:一种是用v-on搭配VueComponent.$emit实现【 ps:此种方式有点类似子传父 】;另一种是使用ref属性搭配mounted()来实现【 此种方式:复杂一点,但是更灵活 】
  • 两种实现方式都可以,而二者的区别和computed与watch的区别很像【 ps:第二种方式可以实现异步操作,如:等到ajax发送请求得到数据之后,再进行事件绑定 】,接下来看实例,从而了解更明确点,用如下实例做演示【 ps:不用前面玩的子传父啊,但是:自行可以先回顾一下子传父的传统方式:父给子一个函数,子执行,参数即为父要得到的数据 】

3.3.1.1、v-on搭配emit实现

  • v-on是可以简写的啊!!!!
3.3.1.2、ref搭配mounted实现
  • 在前面实现的基础上,子组件代码不变,在父组件中加入如下的代码

  • mounted()中是可以进行异步操作的啊,所以才可以让这种自定义事件更灵活

  • 另外:既然是事件,那么也可以使用事件修饰符:prevent、stop、once

    • 在v-on中,这三者和以前一样的玩法,都是加在事件名后面即可,如:@zixeiqing.once = "xxxxx"
    • 在ref中,是用在this.\(refs.person.\)on('zixieqing',this.demo )中的\(on这里的,once就是使用\)once,替换掉原来的$on
3.3.2、解绑自定义事件
  • 这玩意用的就是VueComponent.$off( ['要解绑的事件名'] )这个内置函数来实现解绑的,

    • 当然:数组[ ]中,如果是解绑单个事件,那么[ ]这个括号不要也行;
    • 如果是解绑多个自定义事件,那么使用 , 逗号隔开即可;
    • 另外:$off()不传递参数时,默认是把组件的所有自定义事件都解绑了【 ps:有一个解绑一个 】
    • 自定义事件的核心话:给谁绑定事件,那么事件就在谁身上;给谁解绑自定义事件,那么就去谁身上解绑

  • 另外:前面玩Vue生命周期的beforeDestroy时有一个小点只是简单提了一下,生命周期图如下

  • 上图中的内容,有最后一点没有验证:

说在beforeDestroy中,会销毁子组件和自定义事件

  • 说此时销毁自定义事件

  • 而所谓的销毁子组件也就好理解了,就是把父组件销毁之后,那么:子组件也活不成了【 ps:要验证的话,可以使用销毁vm,然后看旗下的子组件还能活不?答案肯定是活不成的 】
3.3.3、自定义事件中的两大坑

子组件是如下的样子

1、在ref属性实现的方式中,关于this的指向问题

  • 第一种就是将回调函数放到父组件的methods中

    • 此种方式,会发现this指向的是父组件
  • 第二种:将回调函数直接放到this.\(refs.people.\)on( 'event',xxxx ) ]中的xxxx中

    • 这种情况:会发现,this不再是父组件实例对象,而是子组件的实例对象,但是:可以让它变为子组件实例对象【 ps:把回调的普通函数写成兰姆达表达式就可以了 】

2、组件使用原生DOM事件的坑【 ps:了解native修饰符,学后端的人看源码的时候,对这个修饰符再熟悉不过了 】

3.3.4、自定义事件总结
  • 自定义事件是一种组件间通信的方式,适用于:子组件 ——> 父组件通信

  • 使用场景:想让子组件给父组件传递数据时,就在父组件中给子组件绑定自定义事件【 ps:事件回调在父组件methods / 其他地方 中 】,而要解绑自定义事件就找子组件本身

  • 绑定自定义事件:

    • 1、在父组件中:<Person @zixieqing="demo"/><Person v-on:zixieqing="demo"/>

    • 2、在父组件中:


      • ………
        methods: {
        test(){……}
        }
        ………
        mounted(){
        this.$refs.demo.$on('eventName',this.test)
        }
    • 3、若想让自定义事件只能触发一次,可以使用once修饰符【 ps:使用v-on的方式实现的那种 】 或 $once【 ps:使用ref属性实现方式的那种 】

  • 触发自定义事件: this.$emit('eventName',sendData) 【 ps:给谁绑定自定义事件,就找谁去触发 】

  • 解绑自定义事件:this.$off(['eventName',.......]) 【 ps:给谁绑定自定义事件,就找谁解绑;另:注意解绑事件是单个、多个、全解的写法 】

  • 组件上也可以绑定元素DOM事件,但是:需要使用native修饰符

  • 注意项:通过this.$refs.xxxx.$on('eventName',回调)绑定自定义事件时,回调要么配置在父组件的methods中,要么用兰姆达表达式【 ps:或箭头函数 】,否则:this执行会出现问题

3.4、全局事件总线

  • 这玩意儿吧,不算知识点,是开发中使用的技巧而已,里面包含的只是在前面全都玩过了,只是:把知识做了巧妙的应用,把自定义事件变化一下,然后加上Vue中的一个内置关系VueComponent.prototype._ _proto _ _ === Vue.prototype从而实现出来的一个开发技巧
  • 此技巧:可以实现任意组件间的通信
3.4.1、疏通全局事件总线逻辑

但是:现在把思路换一下来实现它

通过上面的分析图了解之后,就可以分析出:单独选取的那个组件需要具有如下的特性:

  • 1、此组件能够被所有的组件看到
  • 2、此组件可以调用\(on()、\)emit()、$off()

1、那么为了实现第一步:能够让所有的组件都看得到可以怎么做?

  • 1)、使用window对象,可以做到( 但是:不推荐用 )

    • 此种方式不推荐用呢,是因为:本来就是框架,谁还去window上放点东西呀,不是找事吗
  • 2、就是利用Vue中的内置关系VueComponent.prototype._ _proto _ _ === Vue.prototype,即:公共组件选为Vue实例对象vm,这个诶之关系怎么来的,这里不再说明了,在基础篇VueComponent()中已经说明过了,利用此内置关系就是利用:VueComponent可以获取Vue原型上的属性和方法,同时选取了Vue实例对象之后,\(on()、\)emit()、$off()都可以调用了,这些本来就是Vue的内置函数啊,Vue实例对象还没有这些函数吗

3.4.2、全局事件总线实例
  • 实现方式:vm + beforeCreate()【 ps:初始化嘛,让关系在一开始就建立 】 + mounted() + $on() + $emit() + beforeDestroy()【 ps:做收尾工作,解绑自定义事件 】+ $off()

实例演示:

    • 注:上图中的\(bus是自己起的名字,但是开发中一般起的都是这个名字,bus公交车嘛,谁的都可以上,而且还可以载很多人,放到组件中就是:谁都可以访问嘛,加了一个\)是因为迎合Vue的设计,内置函数嘛,假装不是程序员自己设计的【 ps:实际上,bus还有总线的意思 】
3.4.3、全局事件总线总结
  • 全局事件总线又名GlobalEventBus

  • 它是一种组件间的通信方式,可以适用于任何组件间通信

  • 全局事件总线的玩法:

    • 1、安装全局事件总线

      • new Vue({
        …….
        beforeCreate(){
        Vue.prototype.$bus = this
        },
        ……
        })
    • 2、使用事件总线

      • 发送数据:this.$bus.$emit('EventName',sendData)

      • 接收数据:A组件想接收数据,则:在A组件中给$bus绑定自定义事件,把事件的回调放到A组件自身中【 ps:靠回调来得到数据 】

        • // 使用methods也行;不使用,把回调放到$on()中也可以【 ps:推荐使用methods,因为不必考虑$on()中的this问题 】
          methods: {
          sendData(){ …… }
          },
          ……..
          mounted(){
          this.$bus.$on('eventName',receiveData)
          },
          …….
          beforeDestroy(){
          this.$bus.$off([ 'eventName' , ….. ])
          }

3.5、消息订阅与发布

什么是消息订阅与发布?

  • 这个东西每天都见到,就是:关注,关注了人,那别人发了一个通知 / 文章,自己就可以收到,这就是订阅与发布嘛
  • 这里使用pubsub-js这个库来演示( 使用其他库也行,这些玩意儿的思路都一样,这是第三方库啊,不是vue自己的 ),其中:
    • pub 就是publish,推送、发布的意思
    • sub 就是subscribe 订阅的意思
    • 也就是:一方发布、一方订阅嘛,这个东西玩后端的人再熟悉不过了,Redis中就有消息订阅与发布,而且用的指令都是这两个单词,RabbitMQ也是同样的套路,只是更复杂而已
3.5.1、玩一下pubsub-js

基础代码

1、给项目安装pubsub-js库,指令:npm install pubsub-js

2、消息发布方

  • 2.1、引入pubsub-js库

  • 2.2、使用publish( 'msgName' , sendData )这个API进行数据发送

3、消息接收方

  • 3.1、引入pubsub-js库
  • 3.2、使用subscribe( 'msgName' , callback )这个API利用回调进行数据接收
  • 3.3、关闭订阅

4、效果如下

3.5.2、消息订阅与发布总结
  • 它是一种组件间通信的方式,适用于:任意组件间通信

  • 使用步骤:

    • 1、安装pubsub-js 指令:npm install pubsub-js

    • 2、消息接收方、发送方都要引入pubsub 代码;:import pubsub from "pubsub-js"

      • 数据发送方:pubsub.publish('msgName',sendData)

      • 数据接收方:

        • // methods可写可不写【 ps:推荐写,不用考虑this的指向问题,和自定义事件一样的 】
          methods: {
          demo(){…..}
          }
          ……..
          mounted(){
          // 使用this.msgName把每条订阅都绑在组件实例对象vc上,方便取消订阅时获取到这个订阅id
          this.msgName = pubsub.subscribe('msgName', callback) // 如果不写methods,那么回调就写在这里,注意:使用箭头函数
          }
          …….
          beforeDestroy(){
          pubsub.unsubscribe( this.msgName )
          }

3.6、插槽

1、基础代码

3.6.1、默认插槽
  • 此种插槽适合只占用一个位置的时候

需求、让食品分类中显示具体的一张食品图片、让电影分类中电视某一部具体的电影,使用默认插槽改造