Vue组件通信(data,props,单向数据流)

本文探讨Vue组件间的通信方式,包括父传子、子传父及非父子组件间的通信。强调组件数据独立性和单向数据流原则,避免直接修改props中来自父组件的数据,以保证应用状态的可控性。文中详细介绍了不同通信方式的实践方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

组件的数据是独立的, 有些功能需要组件通信才能做
常见的组件通信:

  • 父传子
  • 子传父
  • 非父子

**注意: 组件的数据来源:
    1. data 自己提供的数据, 可以随便改
    2. props 父组件传递过来的数据, 不要改
 不要改父组件传递过来的值, 是在遵循一个开发规范 => 单向数据流
 单向数据流: 父组件的数据如果修改了, 会自动向下流动, 影响到子组件,触发子组件的更新

一,父传子

// 1. 给子组件, 以添加属性的方式, 传值 ( 以添加html属性的方式, 传值)
//     规范: 添加的属性名全小写
// 2. 在子组件中, 通过props进行接收, 传递的参数列表

//  父传子复杂类型的说明
     // 1. 如果传递的是简单数据类型, 修改了, vue会直接报错
     // 2. 如果传递的是复杂数据类型, 不要不修改地址, 就不会报错 (虽然不报错, 但是也避免)
     //    没有遵循单向数据流
 <div id="app">
      <h3>我是父组件</h3>
      <son :msg="msg" :obj="obj"></son>
  </div>


      Vue.component('son', {
        template: `
          <div class="son">
            <h3>我是son组件 <button @click="fn">改值</button></h3>
            <p>{{ msg }}</p>
            <p>{{ obj.name }}</p>
            <p>{{ obj.age }}</p>
          </div>
        `,
        props: ['msg', 'obj'],
        methods: {
          fn () {
            // this.msg = '嘿嘿'
            this.obj.name = '老花'
          }
        }
      })


      const vm = new Vue({
        el: '#app',
        data: {
          msg: 'hello vue',
          obj: {
            name: '小花',
            age: 18
          }
        }
      })

二,子传父

// 		1. 在子组件中, 通过触发事件的同时, 传值
//   			this.$emit(事件名, 参数1, 参数2, .....)
// 		2. 在父组件中, 给子组件注册对应的事件
// <!-- 模板在谁的管理范围内, 用的就是谁的变量 -->
    <div id="app">
      <h3>我是父组件</h3>
      <son @sb="fatherFn"></son>
    </div>

 Vue.component('son', {
        template: `
          <div class="son">
            我是son组件 <button @click="fn">传值给父组件</button>
          </div>
        `,
        data () {
          return {
            money: '100块'
          }
        },
        methods: {
          fn () {
            this.$emit('sb', this.money, '小车车')
          }
        }
      })

      const vm = new Vue({
        el: '#app',
        data: {
          msg: 'hello vue'
        },
        methods: {
          fatherFn (money, str) {
            console.log(1111)
            console.log(money, str)
          }
        }
      })
      
// 子传父:
  // 1. 在子组件中, 通过触发事件的同时传值
  //    this.$emit('事件名', 参数1, ...)

  // 2. 在父组件中, 给子组件去注册 对应的 事件
  //    @事件名 = 'fatherFn'

三,非父子

//非父子通信
    // (1) 先创建一个 都能访问到的 事件总线(event bus)   
    //		实际就是一个空的vue实例
    // (2) 在 A 组件中, 触发 bus 的事件, 触发事件的同时传值
    //     	bus.$emit(事件名, 参数1, 参数2, ....)
    // (3) 在 B 组件中, 给 bus 注册对应的事件, 接收参数
    //     	bus.$on(事件名, 事件处理函数)
  <div id="app">
      <jack></jack>
      <rose></rose>
    </div>
    
    const bus = new Vue()

      Vue.component('jack', {
        template: `
          <div class="jack">
            <h3>我是jack</h3>
            <button @click="fn">对rose说</button>
            <p>{{ info }}</p>
          </div>
        `,
        data () {
          return {
            msg: 'you jump, i look look',
            info: ''
          }
        },
        created () {
          bus.$on('rose-reply', (info) => {
            this.info = info
          })
        },
        methods: {
          fn () {
            // console.log('希望给rose传参')
            bus.$emit('jack-say', this.msg)
          }
        }
      })


      Vue.component('rose', {
        template: `
          <div class="rose">
            <h3>我是rose</h3>
            <button @click="fn">rose回答</button>
            <p>{{ info }}</p>
          </div>
        `,
        data () {
          return {
            info: ''
          }
        },
        // bus的事件注册的越早越好, 因为只有注册了事件, 将来才能触发到
        created () {
          bus.$on('jack-say', (msg) => {
            this.info = msg
          })
        },
        methods: {
          fn () {
            // 触发bus的事件的同时, 传值
            bus.$emit('rose-reply', 'get out!! 你个渣男~')
          }
        }
      })

      const vm = new Vue({
        el: '#app',
        data: {
          msg: 'hello vue'
        }
      })

非父子开关灯案例:

//css
 <style>
    .light {
      width: 100px;
      height: 100px;
      border-radius: 50%;
      text-align: center;
      line-height: 100px;
      margin: 0 auto;
      color: #fff;
      background-color: rgb(17, 4, 4);
    }

    /* 灯座 */
    .bottom {
      width: 150px;
      height: 50px;
      margin-top: 10px;
      line-height: 50px;
      text-align: center;
      color: #fff;
      background-color: #000;
    }

    .container {
      width: 150px;
    }

    .active {
      background-color: #ff0;
      color: #000;
    }
  </style>
  
  //body
   <div id="app" class="container">
    <div class="light" class="active">我是一盏灯</div>
     <div class="bottom">
          <button>开灯</button>
          <button>关灯</button>
     </div>
  </div>

案例完成:

 <div id="app" class="container">
    <light-pao></light-pao>
    <light-zuo></light-zuo>
  </div>
  
   const bus = new Vue()

    // 灯泡组件
    Vue.component('light-pao', {
      template: `
        <div class="light" :class="{ active: isOn }">我是一盏灯</div>
      `,
      data () {
        return {
          isOn: false
        }
      },
      created () {
        bus.$on('turn', (flag) => {
          this.isOn = flag
        })
      }
    })

    // 灯座组件
    Vue.component('light-zuo', {
      template: `
        <div class="bottom">
          <button @click="turn(true)">开灯</button>
          <button @click="turn(false)">关灯</button>
        </div>
      `,
      methods: {
        turn (flag) {
          // console.log(flag)
          bus.$emit('turn', flag)
        }
      }
    })

    const vm = new Vue({
      el: '#app',
      data: {}
    })
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值