Vue2九:浏览器本地存储、组件自定义事件、TodoList自定义事件

一、浏览器本地存储(WebStorage)

存储内容大小一般支持5MB左右(不同浏览器可能还不一样)
浏览器端通过 Window.sessionStorageWindow.localStorage 属性来实现本地存储机制。

1.相关API

(1) xxxxxStorage.setItem('key', 'value');该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。
(2) xxxxxStorage.getItem('person');该方法接受一个键名作为参数,返回键名对应的值。
(3) xxxxxStorage.removeItem('key');该方法接受一个键名作为参数,并把该键名从存储中删除。
(4)xxxxxStorage.clear()该方法会清空存储中的所有数据。

2.一些注意点

(1)SessionStorage存储的内容会随着浏览器窗口关闭而消失。
(2) LocalStorage存储的内容,需要手动清除才会消失(调用clear或者清除缓存)。
(3) xxxxxStorage.getItem(xxx)如果xxx对应的value获取不到,那么getItem的返回值是null
(4)JSON.parse(null)的结果依然是null

3.TodoList中的本地存储

碉堡了兄弟们,这里面的几个细节:
1、用watch监视todos数据的变化,如果数据改变那么浏览器本地存储就存个缓存,名字还叫todos,值是更新后的数组(要转化为JSON字符串浏览器才能显示)

2、只监视是没用的,如果只监视不读取,那么数据会缓存到浏览器,但是页面刷新网页不会同步,所以一定要在data中读取浏览器中的数据,当然页面一上来可能没有缓存(也没添加任何数据),那么这时候JSON.parse(localStorage.getItem('todos'))就是null(这样会报错的),所以再来个逻辑或,如果是null那么就todos初始化为空数组呗,然后再自己往里儿加数据,后面再刷新就会直接读浏览器了(总结:初始化时如果有就读,没有就初始值为空数组)

3、还有,watch中要配置深度监视deep,否则页面刷新已经勾选的就重置了,这是因为watch监视todos只会监视todos里面的元素,也就是每个对象的地址,但是对象属性的变化监测不到,但是加了deep就监视到了

data() {
        return {
            // JSON.parse将格式完好的json字符串转换为json对象
            //如果有就读,没有就初始值为空数组
            todos: JSON.parse(localStorage.getItem('todos')) || []
        };
    },

JSON.stringify将Js对象或值转换为JSON格式化的字符串
JSON.parse将格式完好的json字符串转换为json对象

watch: {
        todos: {
            deep: true,   //深度监视不加,那么todos里面的东西改了是监测不到的
            handler(newVal) {
                // JSON.parse将格式完好的json字符串转换为json对象
                // JSON.stringify将Js对象或值转换为JSON格式化的字符串
                localStorage.setItem('todos', JSON.stringify(newVal));
            }
        }
    }

二、组件自定义事件

1、一种组件间通信的方式,适用于:子组件 ===> 父组件
2、使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B的标签绑定自定义事件(事件的回调在A中,用来接收数据)。
3、绑定自定义事件:
(1) 第一种方式,在父组件中:

<Demo @atguigu="test"/><Demo v-on:atguigu="test"/>

(2)第二种方式,在父组件中:

<Demo ref="demo"/>
 ...... 
mounted(){ this.$refs.xxx.$on('atguigu',this.test) }

(3)若想让自定义事件只能触发一次,可以使用.once修饰符,或$once方法。

4、触发自定义事件:this.$emit('atguigu',数据)给谁绑的就找谁触发
5、解绑自定义事件this.$off('atguigu')
6、组件上也可以绑定原生DOM事件,需要使用native修饰符。
7、注意:通过this.$refs.xxx.$on('atguigu',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!

1.引出组件自定义事件

在之前我们想要实现子组件给父组件传数据,都是通过父组件给子组件传递函数类型的props实现,在App中:

<!-- 通过父组件给子组件传递函数类型的props实现:子给父传数据 -->
<School :getSchoolName="getSchoolName" />
getSchoolName(name) {
    console.log('App收到了学校名:', name);
},

然后在School中使用props接收,然后把name传过来。

<button @click="sendSchoolName(name)">点击把name交给App</button>
 props: ['getSchoolName'],
    methods: {
        sendSchoolName(name) {
            this.getSchoolName(name);
        }
    },

2.怎么给组件绑定?

(1)使用v-on

上面的子给父传数据,如今我们也可以换一种方式实现,那就是通过父组件给子组件绑定一个自定义事件实现。zzy事件被触发,就会调用getStudentName

<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传数据(第一种写法,使用v-on或@) -->
<Student v-on:zzy="getStudentName"></Student>
getStudentName(name, age) {
            console.log('App收到了学生名:', name, age);
        }

然后在Student组件中触发这个事件,使用$emit,第一个参数是事件名,后面的是实参,使用函数可以触发Student中的zzy事件

<button @click="sendStudentName">点我把学生名给App</button>
sendStudentName() {
            //触发Student组件实例身上的zzy事件,并传数据过去
            this.$emit('zzy', this.name, this.age);
        }

(2)使用ref

使用ref也可以让父组件给子组件绑定一个自定义事件

<Student ref="student" />

使用ref获取组件实例,然后使用$on绑定zzy事件,第一个参数是事件名,第二个参数是事件触发后的回调函数。
触发方式和上面一样,用$emit
如果想只触发一次,用$once

methods: {
    getSchoolName(name) {
        console.log('App收到了学校名:', name);
    },
    getStudentName(name, age) {
        console.log('App收到了学生名:', name, age);
    }
},
//挂载完成时,手动把zzy事件绑定到student的vc上
mounted() {
    // this.$refs.student.name???
    setTimeout(() => {
        //挂载完成后,隔3秒再给Student绑定事件
        this.$refs.student.$on('zzy', this.getStudentName);
    }, 3000);

    //挂载完成时,手动把zzy事件绑定到student的vc上(且只能触发一次)
    // this.$refs.student.$once('zzy', this.getStudentName);
}

这种写法更灵活,可以异步诶

3.怎么解绑?

使用$off解绑

<Student v-on:zzy="getStudentName" @ht="getStudentName"></Student>
//解绑一个自定义事件
this.$off('zzy');
//解绑多个自定义事件
this.$off(['zzy', 'ht']);
//解绑所有自定义事件
this.$off();

这里面有个很奇怪的地方,如果父组件写了多个Student标签(建立了多个vc),那么解绑的话只能解绑当前vc的自定义事件,其他vc的碰不到诶

4.几个注意点

1、销毁组件实例或者vm,其下面的自定义事件和原生DOM事件都会失效(老师的版本原生DOM事件不会失效,但是现在好像也会失效了,奇怪)
2、通过this.$refs.xxx.$on('atguigu',回调)绑定自定义事件时,回调要么配置在methods中然后通过this.getStudentName传过来。

this.$refs.student.$on('zzy', this.getStudentName);

要么用箭头函数:

mounted() {
        this.$refs.student.$on('zzy',  (name, ...arr) => {
            console.log(this);  //this指向App组件实例
            this.studentName = name;  //成功,因为this指向的是App组件实例对象
        });
    }

否则this指向会出问题!

mounted() {
        this.$refs.student.$on('zzy', function (name, ...arr) {
            console.log(this);  //this指向Student组件实例
            this.studentName = name;  //失败,因为this指向的是Student组件实例对象
        });
    }

3、组件上写的v-on都会被当成自定义事件,即便是写@click也会当成自定义事件,想要用原生DOM事件的话,需要加native,比如@click.native = "demo"

三、TodoList自定义事件

Header和Footer用到了子传父(Item是孙传父了,自定义事件没发解决)
App里标签写,Header里触发,然后把值传过去

<MyHeader @getAdd="addTodo"></MyHeader>
this.$emit('addTodo',todoObj)

同理,换个写法把,先App中添加自定义事件

<MyFooter ref="footer" :todos="todos" :deleteTodo="deleteTodo"></MyFooter>
mounted() {
    //挂载完成后给MyFooter组件实例添加事件
    this.$refs.footer.$on('getIsdone', this.checkAllTodos);
    this.$refs.footer.$on('deleteDone', this.deleteDone);
}

再去Footer里触发事件(需要传数据的就传过去数据,不需要传就直接触发调用)

methods: {
    handleCheckAll(e) {
        // this.checkAllTodos(!this.isAll);  这么写容易晕
        this.$emit('getIsdone', e.target.checked);  //触发事件,把数据传过去
    },
    clearDone() {
        this.$emit('deleteDone'); //触发App中的事件,调用App中的回调
    }
},

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340