父传子
父级通过类似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.state
和context.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')
若是异步操作,
- 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
}
},
- 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')
