今天的内容有意思了,朋友们继续对我们之前的案例完善,是这样的我们之前是不是靠props来完成父给子,子给父之间传数据,其实父给子最好的方法就是props但是自给父就不是了,并且今天学下来,不仅如此,组件间任何层级的关系我都可以传数据了,兄弟之间,爷孙之间等等等等

七.浏览器本地存储

1.localStorage

关闭浏览器数据不会丢失

通过它上面的一个api可以存储数据 .setitem()两个参数,前面是键,后面是值,要注意的是都要以加引号以字符串形式进行存储,而且就算你不加引号,最终呈现效果也会强制给你调用toString这个方法

image-20220507122902184

image-20220507122831870

可以看到就算是字符串也变成了字符串类型,那么问题就来了,那如果我传入的是一个对象,也被强制调用了toString那我对象就没了,什么也看不到了

image-20220507123057878

所以如果是要存储对象数据的时候需要将对象用转为json数据在进行存储,我们都知道json本质上还是一个字符串

image-20220507123224972

image-20220507123236808

剩下还有三个api:读取getitem()、删除removeitem()、清空clear()这个不用传数据

image-20220507123519599

注意:读取没有的属性,将会显示null

2.sessionStorage

浏览器一关就没有数据了

他的api跟local一样

3.TodoList案例完善

我们刚才做的案例数据在一刷新,就会回到初始案例,显然这样是不行的,每个人都应该有属于自己的数据,就可以配合localstorage来,通过监视属性来做,监视我们的data数据,当一发生变动就让最新的值setitem到我们的本地存储

image-20220507132539015

我在这里卡了半天啊,我一直在纠结,为什么这个local里面的属性名会给我变成个数组,最终查到了,原来watch监视属性里面的参数本身就是个数组,放的对象的形式,做到这一步当我们敲击回车,已经可以看到localstorage将我们的数据存储下来了,但是呢我们的页面还没有,这个时候需要将我们原来的数据,注意datas本身是一个数组这里就不用再用数组包裹了

image-20220507133713721

这个时候我们我们刷新就能看到我们之前已经添加过的数据了

bug:当我们把local清空准备重新试一下,就会报错

image-20220507133829630

不能够读取null的长度差不多是这个意思,哪里来的null?还记得前面说过当我们本地存储如果读取的是一个不存在的属性那他读取出来就是null,所以问题出现在这里,这个时候localstorage里面还没有这个属性的,主需要采用短路运算,让原始数据,存在就用它否则就为一个空数组

image-20220507134026587

bug:虽然完成了刷新添加的数据不会丢失,但是我们的选择刷新了会丢失,为什么,问题出现在watch这里,我们对watch的监视只是看dataArr有没有整体改动,用了unshift,vue都能检测到,很明显这是一个能够改变自身的方法,但是我们去勾选前面的选择,却是深层次里面的了,所以监视的deep属性就来,只有监测到深层次的改动才又会重新setitem

八.自定义事件

image-20220507143925723

那么这个事件怎么来触发呢,这样来理解,当我们通过组件标签给她绑定了一个自定义事件,那么此时这个组件实例对象vc身上肯定已经有这个事件了,至于怎么来触发就需要回到我们的组件里面去定义

image-20220507144350422

这里先把我们的触发后的事件处理函数定义好,然后关键逻辑 主要是在我们要触发的这个组件里面,想要这个自定义事件要怎么触发其实是听你自己的,同样还是需要在这边生命一个内置的事件,然后在这个事件函数里面用到一个api $emit,他的第一个参数就是你的自定义的事件的名字,第二个参数可以传参给你自定义事件的处理函数

image-20220507144740569

props和自定义事件异同点:

共同:都可以实现子给父传数据,而且都是通过父组件里面的回调来实现的

不同点:props需要接收,而这种方法,直接拿来用都不用调用这个函数,props还需要自己去调用这个函数把参数传进去

8.1解绑自定义事件

8.2注意

8.3TodoList自定义事件

将之前这个案例子传父数据的地方都改成自定义事件,我就直接传几个,比如敲回车放入数组这里直接将原来的动态绑定改为自定义事件,简写形式

image-20220507164142830

然后我们header这边的 props就可以删除了,同时在我们的键盘事件添加上调用api去触发自定义事件的命令

image-20220507164235207

然后我们在用ref打标识的方法再做一次全选的方式,首先需要在app里面找到footer的子组件,给她打一个标识,然后在我们app这个组建的mounted函数里面来通过ref得到这个组件实例对象通过on这个api将自定义事件绑定上去,同时第二个参数为我们要调用这个事件的回调函数

image-20220507165031575

然后后面基本是一样的,在我们子组件里面这个自定义事件该怎么触发,就写内置事件,写一个事件处理函数,然后在这个处理函数里面,emit这个api来触发自定义事件,同时将我们需要的参数传过来

image-20220507165149931

九.全局事件总线

9.1安装全局事件总线

可实现任意组件间的通信

image-20220507170750378

其实原理是这样的,我们左边这么多组件,要实现任意互相通信,可以由一个中间者实现,比如我们在B里面定义这个x给她通过$on绑定一个自定义事件,同时回调在我们B里面,注意是在B里面,所以当执行这个自定义事件的时候,是在B里面执行,完成了这一步,比如说我们要把A的数据传到B里面来,那么A就可以通过x这个对象用他身上的$emit这个api来触发我们的自定义事件同时把A身上的数据,传过来,这个时候我们B的回调里面就能收到这个数据了

其实原理跟我们前面的自定义事件很像,所以这么一看,这个x是不是要满足两个特性:一个是它能够被所有组件访问到,一个是他身上要有$on、$emit等api,第一个问题它能够被所有组件访问到,放在VueComponent上实现不了,因为我们说过每个VueComponent都是一个全新的构造函数,放在自己vc上更不可能,那就只有你能访问了,那么顺着那条线,是不是答案已经出来了,没错,要让所有组件都访问得到,那就只有Vue的原型对象了

第二个问题,怎么让他身上有这些api,这些api其实都是在vue原型对象上的,所以我们vm、vc都可访问得到,但是将它等于一个vc不太现实,因为我们是将它定义在入口文件的,那就只能为一个vm了,并且还要在vm的beforecreate这个生命周期函数来赋值,为什么要在生命周期函数里来赋值,因为这里讲究一个时间效应,太慢了不行的,前面也已经看过了ref打标识这种方法调用on这个api就是在mounted生命周期函数里面调用的,为什么因为讲mounted的时候就说过这里面是万物的开始,呱呱坠地的时候,什么定义定时器、自定义事件等等都是在这里,而且也只能在这里,不然时间晚了,我触发了你还没绑定好那怎么可以,所以说我们讲究一个时间效应,如果等到vm都定义完了,来一个x=vm,这个时候已经整个都挂载到页面上去了,我们组件里面的mounted也早已经执行完了,你的x都还没有这些api那就会报错,然后还只能写在beforecreate这个生命周期钩子,为什么,也不是说只能嘛,最好写在这里,created感觉也是可以的,因为这里数据挂载这些都还没做,但是也说过vue内置的一些事件、api之类的定义完了,我要这些就够了,我不需要数据

image-20220507174548564

所以最终定义成这样就是最标准的了,而且我们一般x叫做$bus,因为这个东西的作用一是本身有点公交车的感觉,谁都能用,还有一个就是他的中文意思还有总线的意思

有一点必须要清楚,我想把A发送到B,那调用emit发射这个api的就是前者并且参数是数据,而后者就调用on并且参数为回调,你就拿到这个数据了,想干嘛干嘛了

image-20220507181001940

image-20220507181019131

然后就是,定义自定义事件也就是on肯定一挂载就要定义,所以写在mounted里面,而发送数据这边决定触发事件的方式

既然用到了出生mounted,最好也在临别beforeDestroy解绑我们的事件,一定要写事件名

image-20220507181429151

9.2TODOList全局事件总线

又可以继续完善之前的案例了,其实父给子传数据,props是最好的方法,子给父传,用我们原始方法也行(props),自定义事件也好,都差不多的,这里最需要用到全局事件总线的,是孙给爷传,之前一直靠着list这个中间量props,他自己也没用只是给item带过去函数

定义好api

image-20220507182642351

我们是item给app传,那就在item先emit,都是传过去id进行更新我们的数据里面的completed是否勾选和筛选进行删除操作

image-20220507182901518

然后再mounted里面声明事件

image-20220507183024764

十.消息订阅与发布

一种组件间的通信方式,适用于任意组件间通信

如果A需要C的数据,那么A就订阅消息,C就发布消息即可

image-20220507202035240

原生JS无法轻松实现消息订阅与发布,需要第三方库(这里推荐 pubsub-js

,导入时注意 直接pubsub没有js

image-20220507202734103