Vue组件传值

210 阅读2分钟

父传子

父级通过类似list='datalist'的形式将值传给子组件,子组件通过props接受

//父
<Home :list='list'></Home>
//子
 props:['list']

子传父

子传父使用this.$emit将值传给父级

//父
<Home :list='list' @getData='num($event)'></Home>
methods: {
    num(e){
      console.log(e)
    }
  },
//子
 created() {
    this.$emit('getData','xixixi')
  },

祖孙之间

祖孙之间使用依赖注入provide/inject,但是父组件不会会响应子组件的变化,除非父组件传对象,或者也可将this传过去

//祖
  provide(){
    return {obj:this.obj}
  },
  data() {
    return {
      obj:{count:2}
    }
  },
//子引入孙组件
//孙
//template
<div>
    <button @click="obj.count--">-</button>
    <input type="text" v-model="obj.count">
    <button @click="obj.count++">+</button>
</div>
//script
inject:['obj']

兄弟同级

兄弟同级之间使用$on监听当前实例上的自定义事件,由vm.$emit触发。
在Vue的原型上造一个对象$bus,通过$bus上的$on监听当前实例上的自定义事件

//index.js
Vue.prototype.$bus=new Vue()
//组件A
methods: {
    submit(){
        this.$bus.$emit('change',++this.mycount)
    }
},
//组件B
mounted() {
    this.$bus.$on("change",e=>{
      console.log(e)
    })
},

vuex

  • 大型应用中,使用vuex,创建store统一管理state,使用getters包装state,使用Mutations修改state,组件中使用this.$store.state.xxxx/this.$store.getters.xxx/this.$store.commit()访问store
  • 组件中可以使用computed来简化state/getters写法
computed:{
    myName(){
       return this.$store.getters.fullName
    }
},
  • 一般我们会在src文件夹中单独建一个store的文件夹,将store存储在index.js文件中
//store/index.js
import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex)
import user from './modules/user'
let store =new Vuex.Store({})
export default store

main.js引入store

//main.js
import Vue from 'vue'
import App from './App'
import store from '@/store'
new Vue({
  render: h => h(App),
  store,//解构
}).$mount('#app')

state

state类似于vue中的data存储数据源,页面中通过this.$store.state访问store

 state:{firstName:'zhang',lastName:'hao'},
 //访问
console.log(this.$store.state.lastName)

mutations

mutations类似于methods存储方法,state 作为第一个参数,你可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload):

mutations:{
    changeFirstName(state,payload){
            state.firstName=payload
            // console.log('my name is'+payload+ state.firstName)
        },
},
 //访问
 methods: {
    submit(){
       this.$store.commit('changeFirstName','he')
   }
}

Getter

getter 类似computed,包装state,它的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算,state 作为第一个参数

getters:{
    fullName(state){
        return state.firstName+state.lastName
    }
}
//访问
console.log(this.$store.getters.fullName)

actions

需要注意的是action和mutation的不同点:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。
  • 调用context.commit提交一个 mutation,或者通过 context.statecontext.getters 来获取 state 和 getters。通过store.dispatch方法触发
mutations:{
    sayHi(state){
        console.log('my name is'+ state.firstName)
    }
},
actions:{
    changeName(context){
        context.commit('sayHi')
    }
}
//访问
this.$store.dispatch('changeName')

若是异步操作,

  1. action存放异步操作,触发mutation,变更state中的变量
state:{
    subjectList:[]
},
mutations:{
    getSubjectList(state,payload){
        state.subjectList = payload
    }
},
actions:{
    async getSubject(context){
        let res = await fetch('/subject.json').then(res=>res.json())
        context.commit('getSubjectList',res)
    }
}
//访问
computed: {
    list(){
      this.$store.dispatch('getSubject')
      return this.$store.state.subjectList
    }
  },
  1. action存放异步操作,访问时通过异步访问
actions:{
    async getSubject(){
        let res = await fetch('/subject.json').then(res=>res.json())
        return res
    }
}
//访问
async created() {
    let res = await this.$store.dispatch('getSubject')
    console.log(res)
},

获取多个状态

当一个组件要获取多个状态时,将这些状态都声明为计算属性会有些重复和冗余,VueX创造了mapState,mapGetters,mapMutations

mapState

computed:{
    firstName(){
       return this.$store.state.firstName
    },
     LastName(){
       return this.$store.state.LastName
    },
     age(){
       return this.$store.state.age
    }
}
//可以简写为
...mapState(['firstName','LastName','age']),
//当然别忘了引入mapState哦
import {mapState} from 'vuex'

mapGetters

fullName(){
    return this.$store.getters.fullName
}
//可以写成
...mapGetters(['fullName'])

mapMutations

//template
 <button @click="changeFirstName('aaaaaaaaaa')">更新</button>
 methods: {
    changeFirstName(val){
        this.$store.commit('changeFirstName',val)
    }
},
//可以写成
 methods: {
    ...mapMutations(['changeFirstName'])
},

mapActions

//类似mutations
...mapActions(['changeName']),

原理

function mapState1(array){
    let obj={}
    array.forEach(key=>{
        obj[key]=function(){
            return this.$store.state[key]
        }
    })
    return obj
}

模块module

  • 当应用非常复杂时,如果都放在store中会显得很臃肿,vue提供了module可以分类存放,这样在store内部只需要modules对象即可
//moduleA.js
export default {
    state:{
    firstName:'simba',
    LastName:'wang',
    age:18
},
mutations:{
    changeFirstName(state,payload){
        state.firstName=payload
    }
},
getters:{
    fullName(state){
       return state.firstName+state.LastName
    }
},
actions:{
    changeName(context,val){
        context.state.firstName=val
    }
}}

//index.js
import moduleA from './modules/moduleA'
let store =new Vuex.Store({
    modules:{
        moduleA
    }
})
  • 默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应,因此页面访问时只有state是通过模块得到,而其他不变(如果需访问moduleA中的state变量,需this.$store.state.moduleA.age)
age(){
    return this.$store.state.moduleA.age
},
fullName(){
    return this.$store.getters.fullName
}
  • 如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块,getters/actions/mutations通过this.$store.getters['moduleA/fullName']的形式访问
computed:{
    fullName(){
        return this.$store.getters['moduleA/fullName']
    }
},
methods: {
    changeFirstName(val){
        this.$store.commit('moduleA/changeFirstName',val)
    }
},
  • 用mapGetters等的形式
computed:{
    ...mapState('moduleA',['firstName','LastName','age']),
    ...mapGetters('moduleA',['fullName'])
    },
methods: {
        ...mapMutations('moduleA',['changeFirstName'])
    },
  • 你可以通过使用 createNamespacedHelpers 创建基于某个命名空间辅助函数。它返回一个对象,对象里有新的绑定在给定命名空间值上的组件绑定辅助函数,这样访问时就不需写明哪个模块
import {createNamespacedHelpers} from 'vuex'
const {mapState,mapGetters,mapMutations,mapActions} = createNamespacedHelpers('moduleA')