VueJs之组件通信总结

348 阅读5分钟

组件通信

1.组件间通信props

  1. props属性子组件声明接收有三种写法

    props: ['msg'],  // 数组写法,不严谨,不推荐使用
    props: {
    	msg: String,  //对象简单写法,严谨度一般,不推荐使用
    	   },
    props: {
    msg: {           // 对象复杂写法,推荐使用
        type: String,
        default: '我是默认数据',
        },
    },
    
  2. props用于父子之间传递函数数据,非函数数据,传递非函数数据是父给子传递,传递函数数据本质是子给父传递

    如果子组件向父组件传输数据,使用函数,利用调用函数参数模式把数据传递回来

  3. props的特殊用法,在router(路由)中使用,属性值为true是则默认返回params参数,属性值为对象是,则返回这个对象的数据(没意义),属性为函数时则可以自定义返回值

2.自定义事件

要先知道什么是自定义事件,什么是DOM 事件

  1. 原生Dom事件

    事件类型 回调函数 谁调用 默认传递的实参是什么

    1. 事件类型 固定的那几个
    2. 回调函数,自己去定义的
    3. 谁掉了这个回调**(系统调用,浏览器调用)**
    4. 默认传递的参数是什么?event对象
  2. 自定义事件

    事件类型 回调函数 谁调用 默认传递的实参是什么

    1. 事件类型无数个
    2. 回调函数,自己定义的
    3. 谁调用了这个回调**(自己调用)**
    4. 默认传递的参数是什么? 默认传递的是自己给的参数(有就有,没有就是undefined)

原生Dom事件绑在HTML标签上,如果绑在组件标签上,那么就是自定义事件,如果想绑在组件标签上还想用原生Dom事件,那么可以使用修饰符给native

 <Event1 @click.native="test2"></Event1>

3.全局事件总线

适用于所有场合

什么玩意能当全局事件总线?

全局事件总线的角色标准

  1. 全局所有的地方都可以看到
  2. 必须有$on$emit方法

怎么添加事件总线

  1. Vue的圆形中添加方法(我们通常教bus)他的值为自己也就是this(我们的vm)对象

     beforeCreate() {
        Vue.prototype.$bus = this//vm  
        //在Vue的原型上添加了一个属性  $bus   $bus指向了一个对象 这个对象就是我们vm对象
        //1、为什么要在Vue原型上添加   
        //(让所有的组件对象都能看到它,找到它)
        // 组件对象原型的原型就是vm的原型
        //2、事件总线对象必须能够使用$on和$emit,$on和$emit 两个是在Vue的原型当中
      },
    

怎么使用事件总线

  1. 在要接收数据的组件中找到bus,在bus身上添加一个事件,回调就留在这个组件中
    1. 也就是说在哪里$on了,他的回调必定留在这里,当然他也是接收数据的地方
  2. 在要发送的数据组件中找到bus,触发bus身上添加的对应的事件,通过实参来传递数据
    1. 也就是说在哪里$emit了,哪里必定是调用这个事件的地方,通过实参进行把数据传递回去

4.v-model深入

  1. html input v-model的本质
    1. :value = "data"读取数据
    2. @input = "data = $event.target.value" 写数据
  2. 组件标签上的v-model本质
    1. :value = 'data'父组件传递数据给子组件,子组件需要就收props
    2. @input = "data=$event"
    3. 数据在父组件中
    4. 子组件中必须这样写
      1. 先接收props:['value']
      2. 子组件表单类元素
        1. :value='value'
        2. @input = "$emit('input',$event.target.value)"'
  3. 干了两件事
    1. 显示数据
    2. 绑定修改数据的事件
    3. html和组件标签上绑定的@input事件不同,一个是原生的一个是自定义的
  4. 实现了父子双向数据绑定(数据同步)

5..sync修饰符

  1. 实现父子组件双向数据同步问题,和v-model实现效果几乎一样,只不过v-model一般用域表单项组件sync属性修饰符一般用于不带表单项的组件
  2. 父组件给子组件属性传递数据后门加.sync,子组件修改数据,需要分发事件,@click = $emit("update:属性名",要更新的数据)
  3. 本质上还是自定义事件

6.$attrs$listeners

  1. 本质就是父组件给子组件传递所有的属性组成对象及自定义事件方法组成的对象

  2. $attrs如果不声名props那么子组件中可以看到,如果声明了哪个属性,那么哪个属性在$attrs当中看不到,他会排除props声明接受的属性 以及class style

    this.$attrs // 子组件中,可以获取传过来的所有没用props接收的属性
    
  3. 可以通过v-bind 一次性把父组件传递过来的属性添加给子组件

  4. 可以通过v-on 一次性把父组件传递过来的方法添加给子组件

  5. 二次封装el-button

    // 子组件
    <template>
      <a href="javascript:;" :title="title">
        <el-button v-bind="$attrs" v-on="$listeners"></el-button> // 一次性添加所有没接受的属性,以及绑定所有没有接受的事件
      </a>
    </template>
    // 父组件
    <HintButton type="primary" icon="el-icon-plus" size="mini" title="添加"></HintButton>
    <HintButton type="danger" icon="el-icon-delete" size="mini" title="删除"></HintButton>
    
  6. 我们发现如果有些棒的事件如果没法使用的话,我们可以强行改绑用native方法强行把自定义事件改成DOM事件,不过要注意,他绑定的是配置对象模板中最大的标签

  7. $attrs获取全部属性,对象方法,用$listeners获取所有绑定的自定义事件返回的是对象

7.$parent$children以及$ref

  1. $children: 所有的组件对象的数组

    1. 不准确(谁先谁后不一定)

      //this.$children拿到的数组内部谁前谁后不确定
      
  2. $parent获取父组件对象

    1. 相对于较准确,但也不常用,因为不一定几个父组件

      this.$parent.money += money  //不要滥用  如果一个儿子多个爹,无法使用
      
  3. $refs 获取指定组件的对象

    1. 准确,拿到的就是指定的对象

      this.$refs.son  拿的就是小明这个组件对象,子组件
      this.$refs.son.money -= 100
      
  4. 如果想要获取子组件,并且指定子组件用$refs但是在组件处必须定义ref,如果子组件想获取父组件的对象,用parent,children尽量不用,太不稳定,

8.作用域插槽

默认插槽和带名字的插槽(具名插槽)是父组件要给子组件传递的数据,带标签版本

  1. 必须要在子组件处留也就是给他留一个后门,就比如router-view

    // 子组件
    <slot>
    	// 给父组件留空
    </slot>
    
  2. 默认插槽和具名插槽

    1. 具名插槽必须在子组件slot标签上添加name属性,好和父组件对应
    // 父组件
    <template slot="yangmi">  // 跟slot标签的name对应
    	<button>按钮2</button>
    </template>
    // 子组件
    <slot name="yangmi">
          我爱你杨幂 // 默认内容
    </slot>
    

    如果父组件传递数据了,那么就是父组件传递过来的数据,如果没有那么就是默认值

  3. 数据在子组件中去展示的,而子组件的数据结构则是父组件决定的,父子组件通信.数据可以符传递给子,让子去展示,子展示数据的时候也可以把组件传递给父,让父根据数据添加结构

    // 子组件
    <slot :todo="todo" :index="index">  // 把属性传递给父,让父进行判断
        <!-- :todo="todo" 写在slot里面就不是props传递属性,而是子给父传递的数据(对象)当中的一个 -->
        {{ todo.text }}
    </slot>
    // 父组件
    <List :todos="todos">
        <template slot-scope="{todo,index}"> // 父组件接收传递过来的数据进行判断
                <span :style="{color:index%2 === 0?'hotpink':'skyblue'}">{{index+1}} {{todo.text}}</span>
        </template>
    </List>
    

9.Vuex

如果有则直接创建文件如果没用 npm i vuex -S

  1. 配置vuex文件

  2. 创建一个store 文件夹 里面放vuex文件

  3. 进行vuex模块化管理一个功能一个子模块方便管理

    • 三步走
      1. state中定义共用数据
        1. state只能存储数据
      2. mutations中修改共用数据
        1. mutations中只能修改数据不可以进行逻辑判断或者异步请求
      3. actions中发送修改数据的结果
        1. actions中可以进行逻辑判断或者异步请求,但是无法直接修改数据
    // 引入请求的api
    import {
      reqBaseCategoryList
    } from '@/Api'
    // 第一步存储数据并初始化
    const state = {
      categoryList: []
    }
    // 第二步修改数据
    const mutations = {
      REVISECATEGORYLIST(state, categoryList) {
        state.categoryList = categoryList
      }
    }
    // 第三步分发(提交)修改数据的结果
    const actions = {
      async getCategoryList({
        commit
      }) {
        const result = await reqBaseCategoryList()
        commit('REVISECATEGORYLIST', result.data)
      }
    }
    const getters = {}
    
    export default {
      state,
      mutations,
      actions,
      getters
    }