数据传递是框架的核心要素之一,也是在业务开发中极其重要的技术.熟练掌握所有的通信方法,是开发者必须具备的技能。
这篇文章我将会把vue2所有的通信的方法都形成简单易懂的demo。
在我的分类中,通信方法有两种大类型:
1.vue框架提供的通信方法
2.插件及其他通信方法
props通信方法可以实现父组件向子组件传递参数,也可以实现子组件给父组件传递参数.
父传子:传递常规变量
子传父:传递函数
- <template>
- <div>
- <p>父组件数字值1:{{ numValue1 }} <el-button @click="addNum">增加el-button>p>
- <p>获取子组件的值:{{ numValue2 }}el-button>p>
- <hr />
- <PropsChild :numValue1="numValue1" :numValue2="getChildValue">PropsChild>
- div>
- template>
- <script>
- import PropsChild from './child.vue'
- export default {
- name: 'propsTest',
- components: {
- PropsChild
- },
- data() {
- return {
- numValue1: 0,
- numValue2: '父组件默认的值'
- }
- },
- methods: {
- addNum() {
- this.numValue1++
- },
- getChildValue(childValue) {
- console.log(childValue, '???子组件的数值')
- this.numValue2 = childValue
-
- },
- getChildValueFun() {
-
- }
- }
- }
- script>
- <style lang="less">style>
- <template>
- <div>
- 子组件
- <el-input v-model="value" @input="changeValue">el-input>
- div>
- template>
- <script>
- export default{
- name:'emitChild',
- data(){
- return{
- value:'子组件默认的值'
- }
- },
- methods:{
- changeValue(){
- this.$emit('getChildValue',this.value)
- }
- }
- }
- script>
- <style lang="less">
-
- style>

- <template>
- <div>
- 父组件
- <el-input v-model="value">el-input>
- <hr>
- <EmitChild @getChildValue="getChildValue">EmitChild>
- div>
- template>
- <script>
- import EmitChild from './child.vue'
- export default{
- name:'emitTest',
- data(){
- return{
- value:'父组件默认的值'
- }
- },
- components:{
- EmitChild
- },
- methods:{
- getChildValue(childValue){
- this.value = childValue
- }
- }
- }
- script>
- <style lang="less">
-
- style>
- <template>
- <div>
- 子组件
- <el-input v-model="value" @input="changeValue">el-input>
- div>
- template>
- <script>
- export default{
- name:'emitChild',
- data(){
- return{
- value:'子组件默认的值'
- }
- },
- methods:{
- changeValue(){
- this.$emit('getChildValue',this.value)
- }
- }
- }
- script>
- <style lang="less">
-
- style>

main.js安装事件总线
- new Vue({
- router,
- store,
- axios,
- //配置事件总线
- beforeCreate(){
- Vue.prototype.$bus = this
- },
- render: h => h(App),
- }).$mount('#app')
- <template>
- <div>
- <p>子组件1p>
- <p>子组件1的值:{{ value1 }} <el-button @click="addNum">增加el-button>p>
- <p>来自子组件2的值:{{ value2 }}p>
- div>
- template>
- <script>
- export default{
- name:'child1',
- data(){
- return{
- value1:0,
- value2:100
- }
- },
- created(){
- this.$eventBus.$on('bus_deleteNum',this.changeValue2)
- },
- methods:{
- addNum(){
- this.value1++
- this.$eventBus.$emit('bus_addNum',this.value1)
- },
- changeValue2(val){
- this.value2 = val
- }
- },
- destroyed(){
- this.$eventBus.$off('bus_deleteNum')
- }
- }
- script>
- <template>
- <div>
- 子组件2
- <p>来自子组件1的值:{{ value1 }}p>
- <p>子组件2的值:{{ value2 }} <el-button @click="deleteNum">减少el-button> p>
- div>
- template>
- <script>
- export default{
- name:'child2',
- data(){
- return{
- value1:0,
- value2:100
- }
- },
- created(){
- this.$eventBus.$on('bus_addNum',this.changeValue1)
- },
- methods:{
- changeValue1(value){
- this.value1 = value
- },
- deleteNum(){
- this.value2--
- this.$eventBus.$emit('bus_deleteNum',this.value2)
- }
- },
- destroyed(){
- this.$eventBus.$off('bus_addNum')
- }
- }
- script>

- <template>
- <div>
- <p>父组件的值:{{ value }} <el-button @click="addNum">增加el-button> p>
- <hr>
- <Child ref="child">Child>
- div>
- template>
- <script>
- import Child from './child.vue'
- export default{
- name:'refTest',
- components:{
- Child
- },
- data(){
- return{
- value:0
- }
- },
- methods:{
- addNum(){
- this.value++
- this.$refs.child.getValue(this.value)
- }
- }
-
- }
- script>
- <template>
- <div>
- 子组件的值{{ value }}
- div>
- template>
- <script>
- export default{
- name:'refTest',
- data(){
- return{
- value:'子组件初始化的值'
- }
- },
- methods:{
- getValue(val){
- this.value = val
- }
- }
- }
- script>

v-model不仅可以在输入类型标签上实现双向数据绑定,也可以在组件上实现父子组件数据通信
- <template>
- <div>
- <el-input v-model="value">el-input>
- <hr />
- <Child v-model="value" @changeValue="changeValue">Child>
- div>
- template>
- <script>
- import Child from "./child.vue";
- export default {
- name: "vModel",
- components: {
- Child,
- },
- data() {
- return {
- value: "父组件默认的值",
- };
- },
- methods: {
- changeValue(data) {
- this.value = data;
- },
- },
- };
- script>
- <template>
- <div>
- 子组件
- <el-input v-model="inputvalue" @input="changeValue">el-input>
- div>
- template>
- <script>
- export default {
- name: "child",
- props: ["value"],
- model: {
- prop: "value",
- event: "changeValue",
- },
- data() {
- return {
- inputvalue: "子组件默认的值",
- };
- },
- create() {
- //子组件初始化同步,注释掉则为默认值
- // this.inputvalue = this.value;
- },
- methods: {
- changeValue(val) {
- this.$emit("changeValue", val);
- },
- },
- watch: {
- value: function (newVal) {
- this.inputvalue = newVal;
- },
- },
- };
- script>
父子组件数据同步

sync修饰符也是一种语法糖,也可以实现父子通信
- <template>
- <div>
- <div>sync模块div>
- <el-input v-model="value">el-input>
- <hr />
- <Child :value.sync="value" @changeVal="changeVal">Child>
- div>
- template>
-
- <script>
- import Child from "./child.vue";
- export default {
- name: "sync",
- components: {
- Child,
- },
- data() {
- return {
- value: "父组件默认的值",
- };
- },
- methods: {
- changeVal(val) {
- this.value = val;
- },
- },
- };
- script>
-
- <style lang="less" scoped>
- style>
- <template>
- <div>
- <p>子组件p>
- <el-input v-model="childValue" @input="changeVal">el-input>
- div>
- template>
-
- <script>
- export default {
- name: "child",
- props: ["value"],
- data() {
- return {
- childValue: "子组件默认的值",
- };
- },
- methods: {
- changeVal() {
- this.$emit("changeVal", this.childValue);
- },
- },
- watch: {
- value: function (newVal) {
- this.childValue = newVal;
- },
- },
- };
- script>
-
- <style lang="less" scoped>
- style>

- <template>
- <div>
- <p>$attrs与$listenersp>
- <p>title的值:<el-input class="inputBox" v-model="title">el-input>p>
- <p>数值1:<el-input class="inputBox" v-model="value1">el-input>p>
- <p>数值2:<el-input class="inputBox" v-model="value2.value">el-input>p>
- <p>数字值:{{ num }}p>
- <hr />
- <Child
- :title="title"
- :value1="value1"
- :value2="value2"
- v-on="$listeners"
- @changeNum="changeNum"
- >Child>
- div>
- template>
-
- <script>
- import Child from "./child.vue";
- export default {
- name: "AttrListen",
- components: {
- Child,
- },
- data() {
- return {
- title: "标题",
- value1: "数值1",
- value2: {
- value: "对象字段2",
- },
- num: 0,
- };
- },
- mounted() {},
- methods: {
- changeNum() {
- this.num++;
- },
- },
- };
- script>
-
- <style lang="less" scoped>
- .inputBox {
- width: 300px;
- }
- style>
- <template>
- <div>
- <p>子组件p>
- <p>title的值:{{ $attrs.title }}p>
- <p>数值1:{{ $attrs.value1 }}p>
- <p>数值2:{{ $attrs.value2.value }}p>
- <el-button @click="changeNum">修改值el-button>
- div>
- template>
-
- <script>
- export default {
- name: "child",
- created() {},
- methods: {
- changeNum() {
- console.log(this.$listeners, "this.$listeners的值子组件");
- // this.$emit("changeNum");
- this.$listeners.changeNum();
- },
- },
- };
- script>
-
- <style lang="less" scoped>
- style>

可以实现上层组件对于后代组件的值传递,相当于穿透传递
- <template>
- <div id="app">
- <router-view>router-view> div>
- template>
-
- <script>
- export default {
- name: 'App',
- provide(){
- return{
- penetrateVal:'穿透的值'
- }
- },
- components: {
- },
- created(){
- },
- methods:{
- }
- }
- script>
-
- <template>
- <div>
- <p>穿透值:{{ penetrateVal }}p>
- div>
- template>
- <script>
- export default {
- name: 'prodvideAndInject',
- inject: ['penetrateVal'],
- methods: {
-
- }
- }
- script>
- <style>style>

- <template>
- <div>
- 父组件
- <hr>
- <Child>
- <template slot-scope="num">
- <span>父组件中使用:{{ num.data }}span>
- template>
- Child>
-
- div>
- template>
- <script>
- import Child from './child.vue'
- export default {
- name: 'slotVal',
- components: {
- Child
- },
- }
- script>
- <template>
- <div>
- <slot :data="num">slot>
- <el-button @click="add">子组件中点击增加el-button>
- div>
- template>
- <script>
- export default{
- name:'Child',
- data(){
- return{
- num:0
- }
- },
- methods:{
- add(){
- this.num ++
- }
- }
- }
- script>

以上都是vue框架自带的通信方法,但是在开发业务中是不够用的,因为还需要有一些全局的通信方法,去实现业务逻辑。
这里的一些方法就不写具体的demo和效果图了,只是做一个简单的介绍
路由传参是实现参数传递的重要途径,想必是个vue开发者肯定都用过吧
this.$router.push({path:'/demo1',query:{id:1}})
console.log(this.$route.query.id)
这里也不细说,绝大多数vue2的项目都用vuex来做全局的一个参数存储,例如用户信息,token等等,都离不开vuex
vuex地址:Vuex 是什么? | Vuex
本质是和vuex是一样的,不过做了优化,在vue3项目中会使用的更多,也可以在vue2中使用
pinia地址:介绍 | Pinia 中文文档
这里是对localStroage和sessionStorage的统称,这两个都是浏览器本身的方法,都具有持久化保存的作用。最具体的就是用户token校验,判断是否登录过的时候,基本都得用Storage。
和Storage差不多的东西,不细说
默认是react的配套插件,虽然没见过什么大神在vue中用redux,但是官方介绍确实可以在vue中使用redux。
我是没有操作过,想看的可以参考引用其他人的文档:Redux vue - 老白网络
镇场子的大哥,任何框架,甚至原生都可以使用的一个经典信息传递插件,设计模式的经典之作,跨越语言的存在,别说前端了,你在redis上也都会遇到pubsub.
在使用上和eventbus像,简单好用。我就不费劲写了,直接参考别人的文档吧:一、PubSub 的Vue使用方式_vue pubsub-CSDN博客
方法有很多,但具体如何使用,看场景,看业务,灵活变通。
其实,不只是props可以实现双向传递参数,$emit和ref都是可以的,你只需要换个思路就可以了,我这里还写了一篇拓展:,使用props,emit和ref实现双向数据通信。