Vue2,Vue3组件间的通信

210 阅读2分钟

Vue3中新语法

一, v-model

// 父组件
<van-action-sheet
    v-model:show="showStatus"
	  v-model:name="myName"
    close-on-click-action
    :actions="statusActions"
    :cancel-text="t('cancel')"
  />

// 子组件
{
	emits: ['select', 'cancel', 'update:show', 'update:name'],
	setup(props, {slots, emit}){
	   const updateShow = (show: boolean) => emit('update:show', show);
const updateName = (_name) => emit('update:name', _name);
	}
}

Vue2中的语法

一、props / $emit

Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。

// Demo父组件
<template>
  <div class="father">
   /** 向子组件传值 */
    <Child :age="age"></Child>
  </div>
</template>

<script>
import Child from './child.vue'
export default {
  name: 'child',
  components: { Child },
  data() {
    return {
      age: 12
    }
  }
}
</script>

// 子组件中使用props
<template>
  <div>
    {{age}}
  </div>
</template>

<script>
export default {
  props: {
    age: {
      type: Number
    }
  }
}
</script>

$emit 触发当前实例上的事件。附加参数都会传给监听器回调。

<template><div @click="callFatherListener">
    {{age}}
  </div></template><script>
export default {
  props: {
    age: {
      type: Number
    }
  },
  methods: {
    callFatherListener () {
      // 点击时,调用父组件的方法,前提是该方法已被注册
      this.$emit('fatherEvent', 'msg from son')
    }
  }
}
</script>

//  ---父组件中---
<template><div class="hello"><h1>{{ msg }}</h1><!--    父组件注册这个事件监听器,当被子组件调用后会捕获-->
    <Son :age="1" @fatherEvent="fatherEvent"></Son></div></template><script>
import Son from './Son'
export default {
  components: {Son},
  name: 'Father',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  },
  methods: {
    fatherEvent (msg) {
      console.log(msg)
    }
  }
}
</script>

二、$parent / $children

指定已创建的实例之父实例,在两者之间建立父子关系。子实例可以用this.$parent访问父实例,子实例被推入父实例的 $children数组中。

<!--父组件中-->
<template><div class="hello"><h1 @click="changeSonMsg">点击改变子组件的值</h1><Son></Son></div></template><script>
import Son from './Son'
export default {
  components: {Son},
  name: 'Father',
  data () {
    return {
      msg: '爸爸的msg'
    }
  },
  methods: {
    changeSonMsg () {
      // 改变子组件的值
      this.$children[0].msg = 'change from father'
      // 调用父组件的方法
      this.$children[0].sonFunc('儿子你给我嘿嘿嘿')
    },
    fatherFunc () {
      console.log('爸爸你也嘿嘿嘿')
    }
  }
}
</script><!--子组件中-->
<template><div>
    {{msg}}
    <p @click="callFatherFunc">获取爸爸组件的值为: {{fatherVal}}</p></div></template><script>
export default {
  data () {
    return {
      msg: 'default msg'
 }
  },
  methods: {
    sonFunc (msg) {
      console.log(msg)
    },
    callFatherFunc () {
     //  调用父组件的方法
      this.$parent.fatherFunc()
    }
  },
  computed: {
    fatherVal () {
      // 通过$parent获取父组件的属性
      return this.$parent.msg
    }
  }
}
</script>

要注意边界情况,如在#app上拿$parent得到的是new Vue()的实例,在这实例上再拿$parent得到的是undefined,而在最底层的子组件拿$children是个空数组。也要注意得到$parent$children的值不一样,$children 的值是数组,而$parent是个对象,另外根实例可以通过 $root拿到。

三、provide / inject

<!--父组件中-->
<template><div class="hello"><Son></Son></div></template><script>
import Son from './Son'
export default {
  components: {Son},
  name: 'Father',
  provide: {
    for: 'Father provide msg'
  }
}
</script><!--子组件中-->
<template><div>
   父级获取的属性: {{msg}}
  </div></template><script>
export default {
  data () {
    return {
      msg: this.for
    }
  },
  inject: ['for']
}
</script>

四、ref / refs

ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例。

<!--子组件中-->
<template><div>
    {{msg}}
  </div></template><script>
export default {
  data () {
    return {
      msg: 'son\'s msg'
    }
  }
}
</script><!--父组件中-->
<template><div class="hello"><Son ref="son"></Son><p @click="showSonMsg">点击打印son的msg</p></div></template><script>
import Son from './Son'
export default {
  components: {Son},
  name: 'Father',
  methods: {
    showSonMsg () {
      console.log(this.$refs.son.msg)
    }
  }
}
</script>

五、eventBus又称事件总线, on,on, off, $once

六、vuex上面的几种方法主要是介绍父子组件或者是祖先和后代组件之间的通信。如果是兄弟组件或关联度不高的组件之间的通信,我们就要用到vuex了。

  1. vuex各种模块(套路)的定义
  • state:用于数据的存储,是store中的唯一数据源
  • getters:如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关性计算
  • mutations:类似函数,改变state数据的唯一途径,且不能用于处理异步事件
  • actions:类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步操作
  • mutation-types:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护
// main.js中引入store
import store from './store'

new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
// import * as actions from './actions'
import * as getters from './getters'
import state from './state'
import mutations from './mutations'
import createLogger from 'vuex/dist/logger'

Vue.use(Vuex)

// vuex是否开启debug模式,如果是product则不开启,开启会在控制台打印每次的state变化
const debug = process.env.NODE_ENV !== 'production'
const plugin = debug ? [createLogger()] : []

export default new Vuex.Store({
  // actions,
  getters,
  state,
  mutations,
  strict: debug,
  plugins: plugin
})
// store/getters.js
const tabIndex = state => state.tabIndex
export { tabIndex}
// store/mutation-type.js
// 设置映射常量,这样书写错误能被编辑器检测到
const SET_TAB_INDEX = 'SET_TAB_INDEX'
export {
  SET_TAB_INDEX
}
// store/mutation.js
import * as types from './mutation-types'

const mutations = {
  [types.SET_TAB_INDEX] (state, tabIndex) {
    state.tabIndex = tabIndex
  }
}

export default mutations
// store/state.js
const state = {
  tabIndex
}

export default state

七, localstorage和sessionStorage

应该说不单是vue,凡是前端都可以用这种方式通信,跨页面跨层级的。原生的操作localstorage并不友好,这里有个更好的实现,并已经开源。点击这里xr-storage