• Vue-组件通信6种方式



    不熟悉组件通信,写分页器组件时太难受了…

    b站视频链接

    组件通信6种方式

    1.props

    适用场景:父子组件通信

    2.自定义事件

    适用场景:子组件给父组件通信
    $on$emit

    3.全局事件总线 $bus

    适用场景:万能
    Vue.prototype.$bus=this;
    $emit发布事件,$on监听事件
    详情参考这篇

    4.pubsub-js

    适用场景:万能
    React框架中使用比较多,套路:发布与订阅

    5.Vuex

    适用场景:万能

    6.插槽

    适用场景:父子组件通信
    三种:默认插槽、具名插槽、作用域插槽

    自定义事件深入

    event:事件对象

    • 事件分为系统事件(click、双击、鼠标系列…)和自定义事件
    • 无论是系统事件还是自定义事件,都要注意三点:事件源(事件是给谁绑定的)、事件类型(单机还是双击等等)、事件回调
    • 原生DOM绑定系统事件(原生事件):比如button可以绑定click单击事件等
    • 对于组件标签,也可以绑定系统事件,但会不起作用:比如给Event组件绑定click事件,在此click事件就不是原生事件,而属于自定义事件。若想给组件标签绑定原生事件,加个时间修饰符.native即可。也就是 当前原生DOM click事件,其实是给组件的根标签绑定了点击事件,此处利用了事件委派
      注:.natve在vue3中已被废弃
    • 给原生DOM绑定自定义事件没任何意义,因为没办法触发$emit函数

    v-model深入

    v-model是Vue框架中的指令,主要结合表单元素(比如文本框、复选、单选按钮等)一起使用,主要作用是收集表单元素,它也是组件通信方式的一种,可以实现数据的双向绑定

    v-model基本使用:收集表单数据

    <template>
      <div>
        <h2>深入v-model</h2>
        <input type="text" v-model="msg">
        <span>{{msg}}</span>
        <br>
      </div>
    </template>
    
    <script type="text/ecmascript-6">
     // import CustomInput from './CustomInput.vue'
      export default {
        name: 'ModelTest',
        components: {
          // CustomInput
        },
        data(){
          return {
            msg:'赵丽颖'
          }
        }
    
      }
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    v-model实现原理::value + @input

    <input type="text" :value="msg" @input="msg = $event.target.value">
    
    • 1

    Vue2可通过value与input事件实现v-mdel功能:原生DOM中有oninput事件,它经常结合表单元素一起使用,当表单元素文本内容发生变化时就会触发一次回调。

    深入学习v-model,实现父子组件数据同步(父子组件通信)

    <input type="text" :value="msg" @input="msg = $event.target.value">
    
    • 1

    👆此处的:value是给原生DOMinput绑定一个响应式属性

    <CustomInput :message="msg" @input="msg = $event"></CustomInput>
    
    • 1

    👆此处的:valueprops,父子组件通信

    子组件如下:

    <template>
      <div style="background: #ccc; height: 50px;">
        <h2>input包装组件</h2>
        <input type="text" :value="message" @input="$emit('input',$event.target.value)">
      </div>
    </template>
    
    <script type="text/ecmascript-6">
      export default {
        name: 'CustomInput',
        props:['message']
      }
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    属性修饰符sync

    效果图👇

    • 不使用sync修饰符
    <!-- 	  :money 父组件给子组件传递props
              @update:money  给子组件绑定的自定义事件  名字是update:money
              这种操作其实和v-model很相似,可以实现父子组件数据同步
     -->
     
        <Child :money="money" @update:money="money = $event"></Child>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 使用sync修饰符
    <!--  :money.sync 含义:
          第一,父组件给子组件传递props --money
          第二,给当前子组件绑定了一个自定义事件  而且事件名称即为update:money
        -->
    <Child :money.sync="money"></Child>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    注:.syncv-model用在组件标签上,都可以达到父子组件数据同步
    区别:
    .sync达到数据同步: 子组件内部不是表单类元素
    v-model达到数据同步:子组件内部一定是表单类元素

    $attrs与$listeners

    组件实例自身的$attrs$listeners属性:
    $attrs 属于组件的一个属性,可以获取到父组件传递过来的props数据。 对于子组件而言,父组件给的数据可以利用props接收,但要注意,子组件通过props接收的属性在$attrs属性当中是获取不到的。

    $listeners可以获取到父组件给子组件传递的自定义事件

    el-button进行二次封装:自定义带Hover提示的按钮(利用a标签的title属性)

    子组件如下:
    :type="$attrs.type"这种写法是一个一个绑定,用v-bind="$attrs"可以把$attrs接收到的所有属性绑定到元素上

    <template>
      <a href="javascript:;" :title="title" style="margin-right:10px">
      <!-- 此处v-bind不能用 : 代替  v-on不能用@代替 -->
        <el-button v-bind="$attrs" v-on="$listeners"></el-button>
      </a>
    </template>
    
    <script>
    export default {
      name: '',
      props:['title'],
      mounted(){
        //this.$attrs 就是父组件传递过来的所有属性(除了props接收的以及style和class)组成的对象
        //this.$listeners 就是父组件给子组件绑定的所有事件监听组成的对象
        //通常使用他们就是为了对一个组件进行二次封装
        console.log(this.$attrs,this.$listeners)
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    $children与$parent

    效果图👇

    ref

    ref实现BABA找儿子借钱,ref可以获取真实DOM节点,当然也可以获取子组件标签(操作子组件的数据与方法):

    <button @click="borrowMoneyFromXM(100)">找小明借钱100</button><br>
    
    <Son ref="son" />
    
    • 1
    • 2
    • 3
        borrowMoneyFromXM(sonmoney){
          //父亲的钱要加 + 100
          this.money += sonmoney
          //儿子小明的钱要 - 100
          this.$refs.son.money -= sonmoney
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    用同样的方法可以实现向女儿借钱

    $children

    当同时向儿子和女儿借钱时:

    <button @click="borrowMoneyFromALL(200)">找所有孩子借钱200</button><br>
    
    • 1
    borrowMoneyFromALL(money){
          this.money += money * 2
          //儿子和女儿都要减去200
          // 组件实例自身拥有一个属性$children 可以获取当前组件当中的所有子组件
          console.log(this.$children)
          this.$children.forEach(item => item.money -= money)
          // this.$children[0]  不一定是谁,因此官方建议尽量不使用$children和$parent
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    $parent

    当儿子女儿给BABA钱时,也就是子组件操作父组件的数据时:
    需要在子组件内部,获取到父组件,让父组件的数据发生变化。可以通过$parent属性获取到某一个组件的父组件,然后操作父组件的数据和方法

    <button @click="giveMoney(50)">BABA: 50</button>
    
    • 1
    giveMoney(money){
           this.money -= money
           // this.$parent可以拿到父组件对象,操作父组件对象的数据
           this.$parent.money += money
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ref与$children区别

    ref可以获取到当前组件的子组件
    $children可以获取到当前组件的全部子组件(以数组形式,但其元素顺序不确定)

    mixin

    项目中出现很多结构类似的地方:想到组件复用
    项目中很多组件的JS业务逻辑相似:想到mixin(可以把多个组件JS重复的部分封装成一个mixin
    比如把儿子女儿给BABA钱这个操作封装在myMixin.js中👇
    (除了methods,还可以封装mountedcomputed等)

    //定义混入
    export default {
      methods: {
        giveMoney(money){
          this.money -= money
          // this.$parent可以拿到父组件对象,操作父组件对象的数据
          this.$parent.money += money
        },
      },
      mounted(){
        console.log(111234)
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    子组件👇

    <template>
      <div style="background: #ccc; height: 50px;">
        <h3>儿子小明: 有存款: {{money}}</h3>
        <button @click="giveMoney(50)">BABA: 50</button>
      </div>
    </template>
    
    <script>
    import myMixin from '@/pages/Communication/ChildrenParentTest/myMixin'
    export default {
      name: 'Son',
      mixins:[myMixin],
      data () {
        return {
          money: 30000
        }
      },
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    插槽

    可以实现父子组件通信
    默认插槽
    具名插槽
    作用域插槽:子组件的数据来源于父组件,且子组件决定不了自身的结构与样式

    作用域插槽完成的事情:

      父子之间通信
    
      1\ 数据是在父组件当中的
      2\ 数据最终传递给了子组件进行展示v-for
      3\ 子组件在展示数据的过程中,数据的结构是由父组件说了算的
    
    • 1
    • 2
    • 3
    • 4
    • 5

    父组件👇

        <h2>效果一: 显示TODO列表时, 已完成的TODO为绿色</h2>
        <List :todos="todos">
          <template slot-scope="scopeProps"> 
            <!--  scopeProps最终是一个对象,接收子组件作用域插槽回传给父组件的数据组成的对象-->
           <span :style="{color:scopeProps.todo.isComplete?'green':'black'}">{{scopeProps.todo.text}}</span>
          </template> 
        </List> 
        <hr>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
        <h2>效果二: 显示TODO列表时, 带序号, TODO的颜色为蓝绿搭配</h2>
        <List :todos="todos">
          <template slot-scope="{todo,index}">
            <h2 :style="{color:index % 2===0?'blue':'green'}"><span>{{index+1}}</span>{{todo.text}}</h2>
          </template>
        </List>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    子组件👇

    <template>
      <ul>
        <li v-for="(todo, index) in todos" :key="index">
          <!-- :todo="todo" 不是props组件通信,作用域插槽通信 :把数据回传给父组件-->
          <slot :todo="todo" :index="index">{{todo.text}}</slot>
        </li>
      </ul>
    </template>
    
    <script>
    export default {
      name: 'List',
      props: {
        todos: Array
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    插槽在使用第三方组件库时会经常用到

  • 相关阅读:
    文件讲解—【C语言】
    换个姿势做运维!GOPS 2022 · 深圳站精彩内容抢先看
    【网络攻击】XSS和CSRF
    记录--Vue中前端导出word文件
    基于卷积神经网络(CNN)的深度迁移学习在声发射(AE)监测螺栓连接状况的应用
    CVE-2021-44228 Apache Log4j2远程代码执行漏洞复现
    基于ZYNQ的PCIE高速数据采集卡的设计(三)硬件设计
    国内用ChatGPT可以吗
    Oracle Exadata换盘操作-Replacing a Hard Disk Proactively
    Html5+Css3第一讲:html5+Css3基础(1)
  • 原文地址:https://blog.csdn.net/weixin_44286392/article/details/126336627