单向数据流
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,一般采用父子组件引用或通过事件来变更和同步状态的多份拷贝
- 以上的办法都十分脆弱复杂,且使代码难以阅读和维护
- 综上所述,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暂时还没用到过,没有搞太清楚,就先放下了