vue中非父子组件传值

我们在之前的文章中提到过,父组件向子组件传值时是利用定义属性来传值的,而子组件向父组件传值是通过事件,那么下面的情况,同级组件或是隔代组件,即非父子组件之间的传值是怎么进行的呢(如下图)?
在这里插入图片描述
一般来说我们有两种解决非父子组件传值的问题:

  1. 发布订阅模式/观察者模式/bus/总线机制
  2. vuex

在这里我们主要对总线机制进行一下学习,关于vuex的内容随后学习补充。
– 首先创建一个HTML文件,并创建父子组件,

<html>
<head>
  <meta charset="UTF-8">
  <title>非父子组件传值</title>
  <script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="root">
  <child></child>
  <child></child>
</div>
<script>
  //子组件
  Vue.component('child', {
    template: '<div>child</div>'
  });

  var vm = new Vue({
    el: '#root'
  })
</script>
</body>

</html>

页面效果如下:
在这里插入图片描述
我们希望子组件显示内容是外部传递进来的,这里涉及到了父到子的参数传递:

<div id="root">
  <child content="hello"></child>
  <child content="world"></child>
</div>

– 然后子组件通过props进行接收并做一个参数校验,传来的content的值必须为String类型,接下来我们就可以在子组件中显示content的内容了:

//子组件
  Vue.component('child', {
    props: {
      content: String
    },
    template: '<div>{{content}}</div>'
  });

页面效果:
在这里插入图片描述
– 接下来进一步实现效果点击hello,world也变成hello,反之亦然。这里就涉及到非父子组件之间的传值了,上面的子组件被点击的时候,要将hello传值给下面同级的子组件(兄弟组件),反之亦然。

– 首先我们new一个vue的实例,然后将Vue.prototype上的bus属性指向这个实例,这样我们每次调用Vue或者是创建组件的时候,组件上面都会挂载bus这个属性:

Vue.prototype.bus = new Vue();

– 接下来在子组件中绑定一个点击事件handleClick,并在methods中定义该事件:

Vue.component('child', {
    props: {
      content: String
    },
    template: '<div @click="handleClick">{{content}}</div>',
    methods:{
      handleClick: function () {
        alert(this.content);
      }
    }
  });

在这里插入图片描述
– 接下来要将点击的组件的参数传递给另外一个组件,bus是vue的实例,所以也具有$emit()这个方法,我们可以通过bus来向外派发一个事件,同时携带了参数this.content,就是点击的组件的内容:

handleClick: function () {
        this.bus.$emit('change',this.content)
      }

– 其他组件要对这个事件进行监听,我们借助一个生命周期钩子:

mounted: function () {
      this.bus.$on('change', function (msg) {
        alert(msg);
      })
    }

在这里插入图片描述
该组件的值会弹出两次,这是因为在一个child组件中触发事件的时候,两个child组件都会进行监听,所以两个子组件都会弹出弹框。

– 这个时候我们只需把监听的子组件内容变成msg:

mounted: function () {
      this.bus.$on('change', function (msg) {
        this.content = msg;
      })
    }

但是我们会发现点击根本没有效果,这是因为function中this的作用域发生了变化,需要将this保存:

mounted: function () {
      var that=this;
      this.bus.$on('change', function (msg) {
        that.content = msg;
      })
    }

– 但是点击控制台出现了警告信息:
在这里插入图片描述
我们在之前说过单向数据流的问题,子组件不能对父组件传来的参数直接进行操作,最好创建一个副本:

data:function() {
      return {
        name:this.content  /*定义一个content的副本name,单向数据流*/
      }
    },

然后将所有的content都换成name。
最后附上完整的代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>非父子组件传值的问题(Bus/总线/发布订阅模式/观察者模式)</title>
  <script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
  <div id="root">
    <child content="dell"></child>
    <child content="lee"></child>
  </div>
  <script>
    /*需求:点击Dell时会变成Lee,点击Lee时会变成Dell*/
    Vue.prototype.bus=new Vue()  /*每个实例上都会挂载一个bus属性,bus又是一个vue实例*/
    Vue.component('child',{
      data:function() {
        return {
          name:this.content  /*定义一个content的副本name,单向数据流*/
        }
      },
      props:{
        content:String
      },
      template:'<div @click="handleClick">{{name}}</div>',
      methods:{
        handleClick:function () {
          this.bus.$emit('change',this.name)
        }
      },
      mounted:function () {  /*元素挂载到页面上才会执行这个函数*/
        var that=this  /*此时this的作用域发生了变化*/
        this.bus.$on('change',function (msg) {   /*能够监听到bus上发布的事件*/
         /* alert(msg)  /!*会弹出两次,因为在一个child组件上触发事件的时候,
         两个组件都进行了同一事件的监听*!/*/
          that.name=msg
        })
      }
    })

    var vm=new Vue({
      el:"#root",

    })
  </script>
</body>
</html>

这样通过一个bus总线就实现了非父子组件中的传值。

### Vue 3 父子组件教程 在 Vue 3 中,父子组件之间的数据传递主要通过 `props` 和 `emit` 实现。父组件可以通过 `props` 将数据传递给子组件,而子组件则可以通过 `emit` 触发事件将数据回给父组件。 #### 父组件向子组件 父组件可以使用 `props` 向子组件传递数据。以下是一个完整的示例: ```vue <!-- ParentComponent.vue --> <template> <div> <h1>父组件</h1> <p>当前:{{ inputValue }}</p> <ChildComponent :value="inputValue" @update:value="handleInput" /> </div> </template> <script setup> import { ref } from 'vue'; import ChildComponent from './ChildComponent.vue'; // 定义父组件的数据 const inputValue = ref('初始'); // 处理子组件的更新事件 const handleInput = (newValue) => { inputValue.value = newValue; }; </script> ``` 在此示例中,父组件通过 `:value` 将数据传递给子组件,并监听 `update:value` 事件以接收子组件的更新[^1]。 #### 子组件向父组件 子组件可以通过 `emit` 方法将数据发送回父组件。以下是子组件的实现: ```vue <!-- ChildComponent.vue --> <template> <div> <h2>子组件</h2> <input :value="modelValue" @input="updateValue" /> </div> </template> <script setup> defineProps({ modelValue: { type: String, required: true } }); const emit = defineEmits(['update:modelValue']); const updateValue = (event) => { emit('update:modelValue', event.target.value); }; </script> ``` 在这个例子中,子组件通过监听 `input` 事件来捕获用户的输入,并通过 `emit` 方法触发 `update:modelValue` 事件将新传递给父组件。 #### 使用 `v-model` 简化双向绑定 Vue 3 支持通过 `v-model` 实现父子组件之间的双向绑定。以下是如何结合 `v-model` 使用的示例: ```vue <!-- ParentComponent.vue --> <template> <div> <h1>父组件</h1> <p>当前:{{ inputValue }}</p> <ChildComponent v-model="inputValue" /> </div> </template> <script setup> import { ref } from 'vue'; import ChildComponent from './ChildComponent.vue'; const inputValue = ref('初始'); </script> ``` ```vue <!-- ChildComponent.vue --> <template> <div> <h2>子组件</h2> <input :value="modelValue" @input="updateValue" /> </div> </template> <script setup> defineProps({ modelValue: { type: String, required: true } }); const emit = defineEmits(['update:modelValue']); const updateValue = (event) => { emit('update:modelValue', event.target.value); }; </script> ``` 通过 `v-model`,父组件和子组件之间的数据绑定变得更加简洁和直观。 #### 注意事项 - 父组件向子组件传递数据时,确保 `props` 的类型与数据一致。 - 子组件向父组件传递数据时,推荐使用标准化的事件名称(如 `update:modelValue`),以便代码更具可读性[^2]。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值