Vue组件之间通信
vue组件传值有以下几种情况: 父组件向子组件传值、子组件向父组件传值、兄弟组件之间传值等
一、父组件向子组件传值:
传值方式: props
<father> // 动态传递值 <son :data="msg"></son> // 子组件son // 静态传值 <son2 data="这是传递静态值"></son2> </father> // 父组件 <script> export default { data() { msg: '向子组件传值' } } </script> // 子组件 -- son <script> export default { props: { msg: { type: String, // 基础类型检查 required: true // 是否必传值 } }, data() { str: this.msg // 也可以将传递过来的值定义在data中 } } </script>
1:prop的大小写: HTML中的attribute名对大小写不敏感,所以prop中的驼峰值需要等价于短横线命名;如果使用字符模板,就没有这个问题了
// 在HTML中 <component :my-data="data"></component> // 在props与之对应的为驼峰命名 props: ['myData']
2:prop的类型:
// 官方给的例子 props: ['title', 'likes', 'isPublished', 'commentIds', 'author'] // 但是,通常希望每个prop都有指定的类型,这时,可以使用对象形式列出prop,这些property的名称和值分别是prop各自的名称和类型; props: { title: String, likes: Number, isPublished: Boolean, comments: Array, author: Object, callback: Function, contractPromise: Promise }
3: 单项数据流
所有的prop都使得其父子之间形成一个单行向下行绑定:父组件的更新会向下流动到子组件中,但是反过来不行;当父组件更新时,子组件中所有的props都是最新值,所以不应该在子组件中更新props;
两种常见的试图更改一个prop的情形:
#这个prop用来传递一个初始值;这个子组件接下来希望将其作为一个本地的prop数据来使用:这种情况下,最好定义一个本地data property并将这个prop用做其初始值;
props: ['data'], data() { return { msg: this.data } }
#这个prop以一种原始的值传入且需要进行转换:在这种情况下,最好使用这个prop的值来定义一个计算属性:
props:['size'], // 计算属性 computed: { normalizedSize: function() { return this.size.trim().toLowerCase() } }
注意:js中对象和数组是通过应用传入的,所以对于一个数组或者对象类型的prop来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的值
4: 其他详情参考官方文档
二、子组件向父组件传值:
通过自定义事件传值;
// 通过 this.$emit()自定义事件触发 // ====== 子组件 <template> <div> <button @click="emitToFather">点击向父组件传值</button> </div> </template> <script> export default { name: 'Son', data() { return { msg: '向父组件传的值' } }, methods: { emitToFather() { // getDataFromSon 是自定义事件名 this.$emit('getDataFromSon', this.msg) } } } </script> // ====== 父组件 <template> <div> // 事件名需要完全匹配才可以 <son @getDataFromSon="getDataFromSon"><son> </div> </template> <script> export default { name: 'Father', data() {}, methods: { getDataFromSon(val) { // val 就是从子组件传递过来的值 } } } </script>
三、兄弟之间组件传值:
通过eventBus或者vuex进行传值;
vue没有直接子传子的方法,如果一定需要兄弟之间传参,可以先传到父组件,再传到子组件。
// 通过eventBus(即通过on监听,emit触发的方式) // eventBus.js 定义一个新的vue实例,专门用于传递数据,并导出 import Vue from 'vue' export default new Vue() // 定义传递的方法名和传输内容,点击事件或钩子函数eventBus.emit事件 // componentA.vue <template> <div> <button @click="emitToB">点击传递数据给兄弟组件B</button> </div> </template> <script> import eventBus from 'common/js/eventBus.js' export default { methods: { emitToB() { // 也可以在全局挂载eventBus即vue实例。通过this调用 eventBus.$emit('eventFromA', 'A传递给B组件的值') // 定义方法名和要传输的数据 } } } </script> // componentB <template> <div>{{ title }}</div> </template> <script> import eventBus from 'common/eventBus.js' export default { data() { return { title: '' } }, mounted() { this.getEventData }, // 可以在created或者mounted钩子函数中调用 methods: { getEventData() { // 区分this指向那个vue实例 const that = this // eventFromA是自定义的事件名和传递时保持一致 eventBus.$on('eventFromA', function(val) { that.title = val // val 就是A组件传递过来的值 // this.title = val 此处this指向eventBus的vue实例 }) } } } </script>
# 大项目时使用vuex进行数据传递:详情: https://baijiahao.baidu.com/s?id=1618794879569468435&wfr=spider&for=pc
四、1:通过路由带参数进行传值
A组件传值写法:this.$router.push({ path: '/componentB', query: { id: 2 } }) // 跳转到B
B组件取值写法: this.$route.query.id
注意:
1:Vue路由导航有两种方法:声明式导航<router-link :to="...">和编程式导航 router.push(...)
2:页面跳转有push和replace两种方式
# this.$router.push(): 描述:跳转到不同的url这个方法会向history栈添加一个记录,点击后退会返回上一个页面
#this.$touter.replace() 描述:同样是跳转到指定的url,但是这个方法不会向history栈中添加新的记录,点击返回,会跳转到上上一个页面,上一个记录是不会存在的。
#this.$touter.go(n) 相对于当前页面向前或者向后跳转多少个页面,类似于window.history.go(n)
3:传参的方式又分为查询参数query(+path) 和命名路由params(+name)两种方式:
#命名路由搭配params,刷新页面会参数丢失;
#查询参数搭配query,刷新页面数据不会丢失;
接收参数使用this.$router后面就是搭配路由的名称就能获得取到的参数
2:通过设置session Stroage缓存的形式进行传递
两个组件A和B,在组件中设置缓存orderData
const orderData = { 'orderData': 123 }
sessionStorage.setItem('缓存名称', JSON.stringify(orderData))
B组件就可以获取在A中设置的缓存了
const dataB = JSON.parse(sessionStorage.getItem(‘缓存名称’))
五、.sync修饰符
在有些情况下,我们可能需要对一个prop进行双向数据绑定,推荐使用update:myPropName的模式进行触发事件取而代之。
// 举个例子 在一个包含title prop的假设的组件中,我们可以用以下方法表达对其赋值的意图 this.$emit('update:title', newTitle) // 为了方便起见,我们为这中模式提供一个缩写,即.sync修饰符 <text-document :title.sync='title'></text-document>