vue组件通信

133 阅读3分钟

prps和$emit

props

父传子

父组件用自定义属性传值,子组件通过props接收并使用

父组件

<Child :msg="data"/>
data() {
  return {
    data: 'Welcome to  Vue'
  }
}

子组件

<h1>{{ msg }}</h1>
props: {
  msg: {
    type: String,
      default: ''
  },
}

$emit

组件绑定自定义事件名=“自定义事件函数”

组件通过 $emit('自定义事件名',传值) ,触发父级进行传值

eventBug事件总线

兄弟传值

1、创建一个空白Vue对象 ---eventBug.js新建(

2、兄弟组件分别引入空白对象文件

3、兄弟组件1通过 $emit(‘事件名’,值)进行触发

4、兄弟组件2 通过$on(‘事件名’,函数体)接收

 

vue空白对象---eventBus.js

import Vue from 'vue'
export default new Vue()

父组件

<child1></child1>
<child2></child2>
import child1 from './communication/child.vue'
import child2 from './communication/grandson.vue'
 components: {
    child1,
    child2
  }

兄弟组件child1

 <button @click="btnSub">点我就减1:{{ message }}</button>
 import bus from './eventBus.js'
export default {
  name: 'child1',
  data() {
    return {
      message: 100,
    }
  },
  methods: {
    btnSub() {
      --this.message
      bus.$emit('sendBybus', this.message)
    },
  },
}

兄弟组件child2

<button @click="btnSubtwo">点我就减2:{{ message }}</button>
export default {
  name: 'child2',
  data() {
    return {
      message: 100,
    }
  },
  mounted() {
    //  接受oen组件传递过来的值,,sendbus标识需要跟oen保持一致
    bus.$on('sendBybus', (data) => {
      this.message = data
    })
  },
  methods: {
    btnSubtwo() {},
  },
}

注意:兄弟传值,是单向数据流

parentparent children $refs

$children

父访问子

返回的是一个组件集合,若不清楚子组件顺序,可使用索引操作

注意: 不建议使用,若动态插入标签元素,索引则不唯一,无法具体访问某一个指定元素

缺点: 利用$children获取到的数组类型,访问其中的组件必须通过索引值。

当子组件过多时,往往不能确定他的索引值,所以引进了新的父访子的方式$refs

父组件

<child ref="child1"></child>
  mounted() {
    console.log(this.$children)
    const children = this.$children[0]
     //判断子组件是否等于child1
     //$vnode.data.ref是$children上固定写法
    if (children.$vnode.data.ref === 'child1') {
      console.log(children.msg)//hello vue
      children.message('hello')
    }
  },

子组件

<div>
    儿子
  </div>
data() {
    return {
      msg: 'hello vue',
      imgs: 100,
    }
  },
  methods: {
    message(value) {
      console.log(value)//hello
    },
  }

$parent

子组件中,this.$parent指向父组件

this.$parent.xxx=200

this.$parent.fn()

子组件1

 <button @click="sendDataToChild2">发送</button> 
name: 'child1',
methods: {
    sendDataToChild2() {
      this.$parent.$emit('send', '我是子组件1')
    },
  },

子组件2

 <div>儿子2</div>
export default {
  name: 'child2',
  mounted() {
    this.$parent.$on('send', (value) => {
      console.log(value)
    })
  },
}

父组件

<child1></child1>
    <child2></child2>
  components: {
    child1,
    child2,
  },
  mounted() {
    console.log(this.$parent)//Vue
  },
}

provide inject

父传孙

组件通过provide传值,

组件通过inject接收数据

父传孙、父传子是同样用法

父组件

<child ></child>
export default {
  components: {
    child,
  },
   provide() {
    return { msg: "hello vue" };
  },
}

子组件

 <grandson ></grandson>

孙组件

 

<div>{{ msg }}</div>//hello vue
export default {
  inject: ['msg'],
}

父传子

父组件

<child ></child>
export default {
  components: {
    child,
  },
   provide() {
    return { msg: "hello vue" };
  },
}

 

子组件

<div>
   子组件
    <hr />
    {{ msg }}//hello vue
    <grandson></grandson>
  </div>
import grandson from './grandson.vue'
export default {
  components: {
    grandson,
  },
  inject: ['msg'],
}

attrsattrs listeners

父传孙

子组件通v-bind=" $attrs " 搭桥,孙组件通过props接收并使用;

父组件

子组件

孙组件

孙传父

父组件绑定"自定义这函数名=自定义事件函数",

子组件通过v-on=“ $listeners 搭桥,

孙组件通过 $emit ('父组件自定义函数名',传值)

孙组件

<button @click="send">点我呀</button>
 methods: {
    send() {
      this.$emit('event', '快点我呀')
    },
  },

子组件

 <grandson  v-on="$listeners"></grandson>

父组件

 <child @event="test"></child>
 test(value) {
      console.log(value)//快点我呀
    },

子传父

通过 $listeners进行传值

组件通过this.$listeners.父组件自定义函数名(传值

父组件绑定自定义函数名=“自定义事件处理函数” 接收值并使用

子组件

<button @click="send">发送</button>
send() {
      this.$listeners.cc('hello vue')
    },

父组件

 

<child @cc="message"></child>
 message(value) {
      console.log(value)//hello vue
    },

Vuex

uex :全局状态管理库,用来进行全局数据流的管理

//1 导入vuex
import Vuex from 'vuex'
//2 注册vuex
Vue.use(Vuex)
//3 实例化一个Vuex
const store = new Vuex.Store({
state:{},
mutations:{},
actions:{},
getters:{},
modules:{}
})
//4 sotre共享数据对象挂载到vue实例
new Vue({
  render: (h) => h(App),
  // 将创建的共享数据对象,挂载到 Vue 实例中
  // 所有的组件,就可以直接从 store 中获取
  store,
}).$mount('#app')

state

存储数据

 state: {
    // 存储状态
    count: 0
  },

原始方式

用法:this.$store.state.数据名

this.$store.state.count

辅助函数形式

用法:

1、从vuex中导入

import { mapState } from 'vuex'

2、在计算属性中映射到当前页面

...mapState(['数据名'])

import { mapState } from 'vuex'
 computed: {
    // 2.1 监听count变化
    // count() {
    //   return this.$store.state.count
    // },
    // 3.2 利用扩展运算符把sotre 中的count映射到计算属性中
    ...mapState(['count']),
  },

mutations

mutations: 修改state数据,多用于同步操作

mutations: {
   // updateStae(state) {
    //   state.count += 1
    // },
    // 传参,
    updateStae(state, payload) {
      console.log(state)
      state.count += payload
    },
  }

原始方式

用法:

1、 mutations中自定义函数

2、通过this.$store.commit ("触发自定义函数",传值)

 <button @click="test">+1(原始形式)</button>
methods: {
    test() {
      // 调用mutation方法,提交mutation
      // commit(mutation函数名称)
      this.$store.commit('updateStae', 5)
    }
}

辅助函数形式

1、、从vuex中导入mapMutations

import { mapMutations} from 'vuex'

 2、在方法中映射到当前组件

...mapMutations(['updateStae']),

<button @click="updateStae(50)">+100(辅助函数形式)</button>
import { mapMutations} from 'vuex'
methods: {
    // 方式二、把state中的updateStae函数映射到这个组件中
    ...mapMutations(['updateStae']),
}

actions

actions:不可直接修改state数据,需提交mutations函数,进而让mutations修改state数据,存放异步操作

actions: {
    // 存放的也是一个个的方法
    // 第一个参数 执行的上下文对象
    // context相当于组件中的this.$store store的运行实例
    getAsyancCount(context, parmas) {
      //做异步请求,模拟异步请
      setTimeout(() => {
   //接收dispath数据,并提交给mutations中的updateStae函数,进行修改数据
        context.commit('updateStae', parmas)
      }, 1000)
    }

原始方式

用法:

1、actions中自定义函数

2、通过this.$store. dispatch("触发自定义函数",传值)

<button @click="test1">异步调用(原始形式)</button>
  methods:{
test1() {
      this.$store.dispatch('getAsyancCount', 111)
    },
}

 

辅助函数形式

1、、从vuex中导入mapMutations

import { mapMuta tion s} from 'vuex'

 2、在方法中映射到当前组件,绑定的函数上传值

... mapMutations (['updateStae'])

<button @click="getAsyancCount(333)">异步调用(辅助函数形式)</button>
import { mapActions} from 'vuex'
 methods:{
...mapActions(['getAsyancCount']),
}

getters

getters:存放基于state计算出来的一些值(计算属性)

state: {
    // 存储状态
    count: 0,
    list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
  }

原始方式

1、查看基于state存放的数据,进行数据查找

2、用 $store.getters.数据名查看

 getters: {
    // 拿到相应的vuex的计算属性
    filterList(state) {
      return state.list.filter((item) => item > 5)
    }
 //第二种简化写法
 //filterList: (state) => tate.list.filter((item) => item > 5)
}

 

<p>原始形式getters:{{ $store.getters.filterList }}</p>

辅助函数方式

1、导入mapGetters

import {mapGetters } from 'vuex'

2、计算属性中映射到当前页面

...mapGetters(['数据名']

<p>辅助形式getters:{{ filterList }}</p>
import {mapGetters } from 'vuex'
computed: {
    // 导入计算属性名
    // 将getters中的计算属性导入到组件的计算属性中
    ...mapGetters(['filterList']),
  }

modules

modules:分模块,大型项目使用

注意点:

分模块时,默认mutations、actions、getters注册全局,一般会开启命名空间

namespaced:true

若想进行分模块,则需要在为每个moduls起个模块名,在分别将state、mutations、actions放进对应模块,需为每个模块加上命名空间,防止被全局或者其他模块任意访问没有隐私

ps----下文中的user、setting即是自定义取的模块名

modules: {
    // 设置模块的子属性
    user: {
      namespaced: true,
      state: {
        token: '12345',
      },
      mutations: {
        updateToken(state) {
          state.token = '67890'
        },
      },
    },
    setting: {
      namespaced: true,
      state: {
        name: 'vuex实例',
      },
    },
  }

原始方式

1、 $store.state.模块名.模块中state里的值

 <p>用户的token:{{ $store.state.user.token }}</p>
 <p>网站名称:{{ $store.state.setting.name }}</p>

getter快捷访问方式

1、getter监听模块state中的数据

2、用箭头函数形式

<p>快捷访问方式:{{ token }}</p>
<p>快捷访问方式:{{ name }}</p>
import { mapGetters } from 'vuex'
 computed: {
    ...mapGetters(['token', 'name']),
  },

 

 getters: {
    // 监听user/setting模块下state中的值
    token: (state) => state.user.token,
    name: (state) => state.setting.name,
  },

更新值

原始方式

user/updateToken路径,表示user模块下的updateToken函数

传参用法跟非模块一样,只不过多了一个模块名/模块下的某个函数名, 用来触发或者提交数据,进而修改相应模块中state的值

 <button @click="updateToken">更新子模块的token</button>
 methods: {
    updateToken() {
      // 解决方案,采用路径方式,表示user模块下的updateToken函数
      this.$store.commit('user/updateToken')
    }
}

辅助函数形式

<button @click="updateToken">辅助函数形式token</button>
metods:{
...mapMutations(['user/updateToken']),
}

调用createNamespacedHelpers方式

<button @click="text">调用子模块的mapMutations</button>
import {createNamespacedHelpers } from 'vuex'
//mapMutations这个是 user中的
const { mapMutations } = createNamespacedHelpers('user')
methods:{
   // 解决方式3:采用关联数组形式
    text() {
     this['user/updateToken']()
    }
}

sync

父传子时,子组件想要修改父组件传过来的值,需给父组件添加sync修饰符,而子组件通过 $emit("update:变量名",值) 触发父组件对其赋新值。

注意: $emit("update:flag",false),除变量名及值外,其他都是固定写法