拓之

拓之

Vue学习笔记之TodoList案例

2023-11-02

这两天跟着尚硅谷的视频学了一下Vue,到了一个小的案例是做一个todolist,按照我以前的思路,就是要写一堆的js,html,css代码,但是在Vue中,只需要写一点点的代码就可以实现了,并且其中很多数据的处理做的非常的巧妙,我之前是没有接触过前端框架的,之前做的一些小程序,数据都是自己维护,自己监控,自己修改,虽然也做了js的模块化开发,但是还是显得有一些凌乱,每次找一些定义的方法,都要找很久。但是vue的思路,就是谁的孩子谁抱走这种感觉,而且页面还不需要你自己来操作,你只要把数据给我一更新,vue自己就给你把相对应的页面给响应式的更新并且渲染了。这就是Vue的魅力吧。

下面就记录一下TodoList案例的学习过程。其中包含的知识点比较杂,但是包含的思路很重要,除了一些API相关的没有涉及到,其实就是一次完整开发的思路。

TodoList第一版&第二版

为什么叫第一版呢,因为这里的todolist还有相当一部分功能还没有完善,比如数据的永久化存储,比如组件之间的通信等等。永久化存储还好说。这里的组件间通信,说是还感觉是比较麻烦,要一层一层向下传递,应该是有一个方法,可以在组件中发送一个信号出去这样比较合理,随着课程的深入,或许能够更加的感受到vue的魅力。
第二版弄了一下本地存储,就是把数据存在浏览器的loaclstorge中,这样就可以实现数据的永久化存储了,但是这里还是有一个问题,就是数据的类型,因为loaclstorge只能存储字符串,所以这里需要把数据转换成字符串,然后再取出来的时候,再转换成对象,这里就需要用到JSON.stringify()和JSON.parse()这两个方法了。将就,能用。

效果展示

image-20231102195523636

完成的功能:

  1. 在输入框输入数据,按回车,会在下方列表的首位,插入一条数据。

  2. 中间的列表,是响应式的显示每一个todo项,当有删除或者新增或者修改,都会触发重新渲染。其实操作的最多,知识点最密集的就是在这个组件身上。

    每个todo项带一个按钮,这个按钮只有当鼠标悬浮在当前项上才会显示出来,点击这个删除按钮,这条数据就可以删除。

  3. 下方的全选可以动态的判断所有选项是否都选中了。并且点击可以全部选中,或全都不选。

  4. 右边的清楚已完成可以把所有完成的项删除。

组件的划分

这里分为了四个组件,分别是
1. 头部的输入框
1. 中间的列表
1. 列表中的每一项
1. 底部的内容

而其中,列表中的每一项的父组件是中间的列表,其他的组件的父组件都是App组件。

总结

这里是尚硅谷老师给出的一个笔记,再加入一些我自己的想法💡

编码流程

  1. 组件化编码流程:
    ​ (1).拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。
    首先是拆分静态页面为组件,这里的门道也很多,如何拆分,拆分是否合理,这些问题都要考虑清楚,每一个组件,管好自己的事情。

    (2).实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:

    1).一个组件在用:放在组件自身即可。

    2). 一些组件在用:放在他们共同的父组件上(状态提升)。

    (3).实现交互:从绑定事件开始。

  2. props适用于:
    props就是父组件传递给子组件的一个变量,这个变量可以是一个数据,也可以是一个函数,如果是一个函数,那么子组件可以调用这个函数,从而实现子组件向父组件传递数据的目的。其实传递函数这里我一开始是没想到的,非常的巧妙,相当于子组件在操作父组件的数据,但本质上还是父组件自己在操作。
    ​ (1).父组件 ==> 子组件 通信

    (2).子组件 ==> 父组件 通信(要求父先给子一个函数)

  3. 使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的!
    props传过来的值,不能修改,因为这个props不是想参数一样传递过来,就有自己的内存空间,而是直接引用了父组件的数据,所以不能修改,如果修改了,那么父组件的数据也会被修改,这样就会出现问题了。这里是有一个特例,就是可以修改一个对象内部的一个数据,这是因为vue的数据监控,是一个浅层监控,vue会检测不到,所以不会报错,但是不推荐这样做。

  4. props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。

webStorage

补充一个浏览器本地存储的知识点。

  1. 存储内容大小一般支持5MB左右(不同浏览器可能还不一样)

  2. 浏览器端通过 Window.sessionStorage 和 Window.localStorage 属性来实现本地存储机制。

  3. 相关API:

    1. xxxxxStorage.setItem('key', 'value');
      该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。

    2. xxxxxStorage.getItem('person');

      该方法接受一个键名作为参数,返回键名对应的值。

    3. xxxxxStorage.removeItem('key');

      该方法接受一个键名作为参数,并把该键名从存储中删除。

    4. xxxxxStorage.clear()

      该方法会清空存储中的所有数据。

  4. 备注:

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

第三版&组件间通信

这一版的内容比较重要,主要是组件间的通信,就是使用组件的自定义事件,可以用this.$on(demo,fun)或者在组件砂锅直接绑定自定义方法@demo="fun"方法挂载一个方法在某个组件上,这个组件就可以调用this.$emit(demo,fun)方法去调用这个方法。

下面是老师给出的笔记,记得比较详细了。

组件的自定义事件

  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指向会出问题!


全局时间总线的想法非常巧妙,之前的进程间通信,实际兄弟组件之间是没有办法直接进行通信的,但是这个全局时间总线就把所有组件联系在了一起。

全局事件总线(GlobalEventBus)

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

  2. 安装全局事件总线:

    new Vue({
    	......
    	beforeCreate() {
    		Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
    	},
        ......
    }) 
    
  3. 使用事件总线:

    1. 接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。

      methods(){
        demo(data){......}
      }
      ......
      mounted() {
        this.$bus.$on('xxxx',this.demo)
      }
      
    2. 提供数据:this.$bus.$emit('xxxx',数据)

  4. 最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。

看下图,就是组件Vue以及VM的重要关系!也是为什么我们能找一个组件,来充当全局通信角色的原因。

组件间通信

消息订阅与发布(pubsub)

还有一种能够实现任意组件间通信的方法就是消息订阅与发布这个包,是一个第三方的库,发信与收信类似于订阅报纸和送报纸。

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

  2. 使用步骤:

    1. 安装pubsub:npm i pubsub-js

    2. 引入: import pubsub from 'pubsub-js'

    3. 接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。

      methods(){
        demo(data){......}
      }
      ......
      mounted() {
        this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
      }
      
    4. 提供数据:pubsub.publish('xxx',数据)

    5. 最好在beforeDestroy钩子中,用PubSub.unsubscribe(pid)取消订阅。

nextTick

  1. 语法:this.$nextTick(回调函数)
  2. 作用:在下一次 DOM 更新结束后执行其指定的回调。
  3. 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。