Vue中的传参方式

101 阅读5分钟

一、父传子(使用props)

父组件

<template>
    <div id="Parent">
        <Child :ChildData="ParentData"></Child>
    </div>
</template>

<script>
    import Child from "../views/Child";
    export default {
      components: { Child },
      data() {
        return {
          ParentData: "我是父组件要传给子组件的数据"
        };
      },
    };
</script>

子组件

<template>
  <div>
    <h2>{{ChildData}}</h2>
  </div>
</template>

<script>
    export default {
      props: ["ChildData"], //此处接收父组件传过来的数据
    }
</script>
//////////////////////////////////////
**扩展**
props接收数据时的使用方法
    第一种 数组形式 props:['***','***','***'] 直接使用
    第二种 对象形式 props:{ ***:String, ***:Number } 指定传输过来的数据类型
    第三种 嵌套对象方式 props:{ ***:{ type: String, default: 0, required: true,  } } 指定传输过来的数据的类型,默认值,以及是否必须传过来

二、子传父(自定义事件)

父组件

<template>
    <div class="wrap">
        <div>我是Father组件</div>
        <Child @func="speak" ></Child>
    </div>
</template>

<script>
    import Child from '../views/Child'
    export default {
        name: "Parent",
        methods:{
           speak(msg){
               console.log(msg); //此处控制台输出子传给父的数据
           }
        },
        components:{
            Child
        }
    }
</script>

子组件

<template>
    <div>
        <div>我是Child组件</div>
    </div>
</template>

<script>
    export default {
        name: "Child",
        mounted() {
            this.$emit('func',"我是子组件发送的消息!");
        }
    }
</script>

三、全局事件总线(EventBus,任意组件之间)

首先,想要实现全局事件总线,就要安装全局事件总线,在main.js中完成全局事件总线的安装配置

new Vue({ 
el:'#app', 
render: h => h(App), 
    beforeCreate(){ 
        Vue.prototype.$bus = this //安装全局事件总线 
    } 
})

接下来,就要对想要接收数据的组件进行自定义事件的绑定,简单来说就是,谁要接收数据,自定义事件就绑定在谁身上

绑定全局事件总线 A.vue:

mounted(){ 
    // 绑定自定义事件 
    this.$bus.$on('自定义事件名', (接收参数)=>{
        console.log('我是TestA组件,收到了数据', 接收参数); 
    }) 
}

最后一步,全局事件总线的触发,事件的触发是在发送数据的组件中完成的,简单来说,谁是数据的发送者,谁就来触发事件

触发全局事件总线 TestB.vue:

methods:{ 
    // 触发事件,事件名不能重复 
    触发事件方法名(){ 
        this.$bus.$emit('自定义事件名', 传递参数); 
    } 
},

// Vue3不再提供`$on``emit`函数,可以使用外部库mitt来代替,使用方法:[mitt](https://blog.csdn.net/qq_42543244/article/details/123806588)

四、vuex传递数据(任意组件之间)

组件中的代码

<template>
  <div>
    <h3 v-for="item in stateData" :key="item.id">{{item.id}}:{{item.title}}</h3>
  </div>
</template>

<script>
import { mapState } from "vuex";
export default {
  computed: {
    ...mapState(["stateData"])
  },
};
</script>

vuex中state的代码

state: {
    stateData:[
      {id:1,title:"我是vuex中来存储数据的"},
      {id:2,title:"所有的数据都存储在state中 state是一个对象"},
      {id:3,title:" Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储和管理程序的所有组件的数据"},
      {id:4,title:"在大型的程序中如果多个组件中用到的数据我们可以存储到vuex,如果小型项目我们可以适当的使用vuex"}
    ]
},

// pinia也是不错的选择,可以代替vuex

五、# attrs和listeners(祖孙之间传参)

祖孙组件之间的传承是以父组件为中间媒介进行的

$attrs就是一个容器对象,这个容器对象会存放:父组件传过来的且子组件未使用props声明接收的数据

使用$listeners可以实现孙组件的数据传递到爷组件中去,逻辑的话,也是用在中间的桥梁父组件上面去,我的理解就是$listeners可以将子组件emit的方法通知到爷组件。

祖传孙

祖组件代码

<template>
  <div id="app">
    我是爷组件
    <fu :msg="msg"></fu>
  </div>
</template>

<script>
import fu from "./views/fu.vue";
export default {
  components: { fu },
  data() {
    return {
      msg: "祖组件的数据,即将传递给孙组件",
    };
  },
};
</script>

父组件代码

<template>
  <div class="fatherClass">
    我是父组件
    <sun v-bind="$attrs"></sun>
  </div>
</template>

<script>
import sun from "./views/sun.vue";
export default {
  components: { sun },
  name: "DemoFather",
};
</script>
//此处祖组件传过来的数据不使用props接受,可以控制台输出this,查看$attrs对象,实际上此时的父组件把自身的$attrs传递给孙组件了

孙组件代码

<template>
  <div class="sunClass">
    我是孙子组件
    <h2>接收爷组件数据:-->{{ msg }}</h2>
  </div>
</template>

<script>
export default {
  // $attrs一般搭配interitAttrs 一块使用 默认会继承在html标签上传递过来的数据,类似href属性的继承
  inheritAttrs: false,
  props: [ 'msg' ],
  name: "DemoSun",
};
</script>
 /*
    孙子组件通过props,就能接收到父组件传递过来的$attrs了,就能拿到里面的数据了,也就是:
    爷传父、父传子。即:祖孙之间的数据传递。
  */

孙传祖

祖组件代码

<template>
  <div id="app">
    我是爷组件
    <fu :msg="msg" @fromSun="fromSun"></fu>
  </div>
</template>

<script>
import fu from "./views/fu.vue";
export default {
  components: { fu },
  data() {
    return {
      msg: "祖组件的数据,即将传递给孙组件",
    };
  },
  mounted() {
    this.fromSun()
  },
  methods: {
    fromSun(payload) {
      console.log("接收到孙组件的数据-->", );
    },
  }
};
</script>

父组件代码

<template>
  <div class="fatherClass">
    我是父组件
    <sun v-bind="$attrs" v-on="$listeners"></sun>
  </div>
</template>

<script>
import sun from "./views/sun.vue";
export default {
  components: { sun },
  name: "DemoFather",
};
</script>

孙组件代码

<template>
  <div class="sunClass">
    我是孙子组件
    <h2>接收爷组件数据:-->{{ msg }}</h2>
    <el-button @click="sendToZu">孙传祖</el-button>
  </div>
</template>

<script>
export default {
  inheritAttrs: false,
  props: [ 'msg' ],
  name: "DemoSun",
  methods: {
    sendToZu() {
      // 孙组件能够触发爷组件的fromSun方法的原因还是因为父组件中有一个$listeners作为中间人,去转发这个事件的触发
      this.$emit("fromSun", this.data);
    },
  },
};
</script>
 /*
    孙子组件通过props,就能接收到父组件传递过来的$attrs了,就能拿到里面的数据了,也就是:
    爷传父、父传子。即:祖孙之间的数据传递。
  */

六、pubsub传参(任意组件之间传参)

pubsub,即订阅发布,在vue中常常被用于任意组件间的传值

1.在终端进行pubsub的安装

npm i pubsub-js

2.在需要进行传值的位置引入pubsub

import PubSub from 'pubsub-js'

3.订阅操作:

需要接收值的组件中,在mounted钩子函数中进行订阅(subscribe),并将接收到的值作为参数传递到本组件中指定的方法中:

例:下面代码中,subscrib方法e的第一个参数(yyds)为订阅名,第二个(getmes)为接收数据的方法。

这里定义pid是为了方便未来进行取消订阅的操作。

methods(){
    //接收数据的方法,它的参数第一个为接收的订阅名,不需要调用,可直接用_来占位,避免eslint报错。第二个为传来的数据,当传有多个数据时,可用一个对象来传递。
    getmes(_,res){ alert(res) } 
}
......
mounted(){
    //订阅消息,这里定义变量pid是为了方便未来取消订阅
    this.pid=PubSub.subscribe("yyds",this.getmes)		
}

4.传值操作:

在需要传值的组件中,进行信息的发布(publish):

publish方法的第一个参数(yyds)为订阅名,第二个参(Message)为想要传递的变量。

PubSub.publish('yyds','Message') //通过 事件触发 方法发布信息‘Message’

这样,传递过来的message1便能够在订阅的组件中接收并使用了。

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

七、 ref与parent/children父子组件传值:

父传子

//父组件
<Home ref="home"></Home>
<button @click="toValue">点击</button>
methods:{
  toValue(){
          this.msg = "这是父组件的值";
          this.$refs.home.setMsg(this.msg);
   }
}
//子组件
<div class="home">
      {{msg}}
 </div>
    methods:{
        setMsg(val){
            this.msg = val;
        }
    }

子传父

//父组件
<Home ref="home"></Home>
methods:{
  toValue(val){
     this.msg = val
   }
}
//子组件
<div class="home">
<button @click="setMsg">点击</button>
 </div>
    methods:{
        setMsg(val){
             this.$parent.toValue(this.msg);
        }
    }
1. 使用`ref`传递数据:
- 在父组件中,给子组件添加一个`ref`属性,例如`<child ref="childComponent"></child>`- 在父组件中可以通过`this.$refs.childComponent`来访问子组件的实例。
- 父组件可以直接通过`this.$refs.childComponent`来修改子组件的数据或调用子组件的方法。
​
2. 使用`$parent/$children`传递数据:
- 在子组件中,可以使用`this.$parent`来访问父组件的实例。
- 父组件可以通过`this.$children`来访问所有子组件的实例。
- 父组件可以直接通过`this.$children[index]`来修改特定的子组件的数据或调用子组件的方法。
​
需要注意的是,使用`ref``$parent/$children`传递数据会造成父子组件之间的耦合性增加。如果父子组件之间的数据传递较为复杂或需要在多个组件之间传递数据,推荐使用Vuex来进行状态管理。Vuex是Vue.js官方提供的状态管理库,可以方便地在不同组件之间共享数据。

八、provide/inject(祖传后代)

通俗的讲,就是 provide 可以在祖先组件中指定我们想要提供给后代组件的数据或方法,而在任何后代组件中,我们都可以使用 inject 来接收 provide 提供的数据或方法。

// 父级组件提供 'foo'
<template>
  <div>
    <div>{{foo}}</div>
    <son></son>
  </div>
</template>

<script>
import Son from "./Son";
export default {
  name: "parent",
  components: { Son },
  provide() {
    return {
      foo: this.foo
    };
  },
  data() {
    return {
      foo: "测试",
    };
  },
  mounted() {
    console.log(this.foo)
  },
};
</script>

//子级组件,不接收
<template>
  <grandSon></grandSon>
</template>

<script>
import grandSon from "./grandSon";
export default {
  name: "son",
  components: { grandSon },
};
</script>

//孙级组件,接收foo
<template>
  <div>{{foo}}</div>
</template>

<script>
export default {
  name: "grandSon",
  inject: ["foo"],
  mounted() {
    console.log(this.foo)
  },
};
</script>
总结:Vue中组件传参的大致场景分为,父传子,子传父,兄弟之间,祖父之间,任意组件之间,具体使用哪种方式进行传递数据,需要根据业务场景来进行选择。