vue爬坑笔记之二(组件传值)

214 阅读2分钟

单向数据流

Vue中的数据是单向的数据流,所有的props都使得其父子prop之间形成了单向下行绑定:父级prop的更新会向下流动到子组件,但反过来则不行。这样可以防止出现从子组件意外改变父级组件的状态,导致应用数据流混乱的情况。
另外,每次父级组件发生更新时,子组件中的所有props都会刷新为最新的值。这也意味着你不应该在子组件内部改变prop。如果你这样做,vue会想你发出警告。
子组件要想修改prop的值,只能通过$emit派发一个事件,父组件接收事件后,由父组件修改.
组件传值的情况简单分为父传子、子传父、非父子.

父组件向子组件传值

  • 在父组件的data中定义变量
  • 在子组件中通过props接收,props可以是一个数组,也可以是对象:
props:['属性','属性']//数组形式
props:{//对象形式
    属性名:{
        type:类型
        required:是否必须
        default:默认值
    }
}

子组件向父组件传值

  • 在子组件中通过this.$emit映射,父组件接收.
<!--子组件的html模板-->
<button @click="fn"></button>
//子组件的script
methods:{
    fn(){
        ...一些操作
        //然后映射出去
        this.$emit('自定义事件名',要传递的参数)
    }
}
  • 然后在父组件中可以直接@事件名使用
<组件 @事件名="函数名"></组件>

非父子组件传值

  • 使用bus总线进行传值,bus总线其实是一个vue实例化对象
    1.在主入口文件(默认是main.js)中实例化一个bus
//main.js
var bus = new Vue()
//放入根组件的data中
data:{
    bus
}
- 传递事件时,`this.$root.bus.$emit('自定义事件',data)`
- 监听事件(接收),`this.$root.bus.$on('事件名',function(传递过来的data))

用vuex进行传值

  • 什么是Vuex?
    • Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.
  • 为什么用Vuex?
    • 数据流一般是单向的,而如果遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏,比如:
      1. 多个视图依赖于同一个状态(比如一个窗口的显示隐藏,在多个页面都需要使用)
      2. 来自多个不同视图的行为要变更同一状态(比如在多个页面都去操作一个状态的显示与否)
    • 对于问题1,像父子组件传值那种传参的方法对于多层嵌套的组件非常非常繁琐(你不会想用的),而且这种方法对兄弟组件传值无能为力
    • 对于问题2,一般采用父子组件引用或通过事件来变更和同步状态的多份拷贝
    • 以上的办法都十分脆弱复杂,且使代码难以阅读和维护
    • 综上所述,Vuex为了解决这些问题诞生了
  • 使用vuex之前,请确保你安装了vuex,并且在store文件夹中的主js文件中引入import vuex from 'vuex',且Vue.use(Vuex),然后在主入口js文件中引入import store from 'store/index',在根实例中注入new Vue({store})
  • 创建store
export default new Vuex.Store({
  state: {
  },
  mutations: {
  },
  getters:{
  },
  actions: {
  },
  modules: {
  }
})

State: 在state中写入变量,在组件中获取后可以直接使用store.state.变量获取

//store中的index.js
state:{
    show:false
}
//组件中
computed:{
    status(){//使用时直接写入status就行
        return this.$store.state.show
    }
}
    //引入mapState后可以这样写
    computed:{
        ...mapState([
        'show'//此时直接使用show即可
        ])
    }

Getters

  • 如果一个状态在很多地方被用到的时候,需要做一些处理才能继续使用,而在这些地方的处理操作都是相同的,那么getters就派上用场了.getters类似于计算属性,它的返回值会根据它的依赖被缓存,只有当这个依赖值变化,它才会重新对其计算
  • 通过属性访问 getter会暴露为store.getters对象,可以以属性的方式访问其中的值
getters:{
    changeShow:(state,gettets) =>{
        return {}
        //getters接收state为第一个参数,也可以接收其他getter作为第二个参数
    }
}
  • 通过方法访问
  • getter可以返回一个函数,来实现给getter传参
 getters:{
    fn:state => id =>{
        return state.person.change(person=>person.id === id)
    }
 }
 //调用
 store.getters.fn(2)
  • mapGetters辅助函数
  • mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性
  • 使用之前记住要引入此方法
    import {mapGetters} from 'vuex'
    export default {
        //....
        computed:{
            ...mapGetters([
                'fn'//直接把fn引用过来
                func:'fn'//把func映射为'this.$store.getters.fn'
            ])
        }
    }

mutation

  • 更改Vuex中store中的状态的唯一方法就是提交mutation, 你可以通过store.commit()提交mutation来调用mutation中的方法,从而改变状态
    //可以传入额外参数,在用commit提交时用`,`隔开,传入参数即可
    mutations:{
        add(state){
            //变更状态
            state.num++
        }
        change(state,newNum){
            state.num += newNum
        }
    }
    
    //在组件中提交mutation实现num++
    this.$store.commit('add')
    this.$store.commit('change',10)
    //可以用对象风格的提交方式
    this.$store.commit({
        type:'change',
        newNum:10
    })
  • mapMutation
import {mapMutations} from 'vuex'

export default {
    //...
    methods:{
        ...mapMutation([
            'add'//将this.add()映射为this.$store.commit('add')
            //mapmutation也支持传参
            'change'//将this.change(num)映射为this.$store.commit('change',10)
        ])
    }
}
  • mutation必须是同步函数

Action

  • action类似于mutation,但有所区别
  • action的操作是提交mutation,它也不能直接变更状态,只有mutation可以操作状态
  • action可以执行异步操作
  • 一个简单的demo:
//设置一个action
actions:{
    add({commit}){
        commit('add')
        //会将mutation中的add拿到action中来
    }
}

//触发action
this.$store.dispatch('add')
  • 如果只执行同步操作,那么并没有必要使用action.
    但是如果需要执行异步操作,就只能使用action了
actions:{
    change({commit}){
        return new Promise( (resolve,reject)=>{
            setTimeout(()=>{
                commit('change')
                resolve()
            },1000)
        })
    }
}
//使用
this.$store.dispatch('change').then(()=>{
    //进行操作..
})
  • 此外,在action中的函数是可以相互使用的.比如
actionA//假设此处的actionA就是上面的change,里面执行的是异步操作

actionB({dispatch,commit}){
    return dispatch('actionA').then(()=>{
        commit('mutation中准备好的其他方法')
    })
}
  • 利用async/await可以如下组合
//假设有getData()和otherData()两个函数,返回的都是promise
actions:{
    async actionA({commit}){
        commit('getData',await getData())
    },
    async actionB({dispatch,commit}){
        await dispatch('actionA')//会等待actionA的完成
        commit('otherData',await otherData())
    }
}

module

  • 额...module暂时还没用到过,没有搞太清楚,就先放下了