VUE中数据通信方式

准备

目录结构
在这里插入图片描述
cli服务 npm i @vue/cli-service-global -g

入口文件main.js

import Vue from "vue";
import App from "./App"

new Vue({
    el:"#app",
    render:h=>h(App)
})

根组件APP.Vue.js

<template>
    <div>
        <parent></parent>
    </div>
</template>

<script>
import parent from "./components/parent"
export default{
    components: {
        parent
    }
}
</script>

组件通信

1. props

父组件通过props的方式向子组件传递数据,而通过$emit 子组件可以向父组件通信。

  • 父传子

parent.vue

<template>
  <div>
    parent--->{{number}}
    <hr />
    <son :number = number @changeInParent="changeInParent"></son>
  </div>
</template>

<script>
import son from "./son";
export default {
  data() {
    return {
      number: 100
    };
  },
  methods: {
    changeInParent(newValue){
      this.number = newValue
    }
    
  },
  components: {
    son
  }
};
</script>

son.vue

<template>
  <div>
    <p>son--->{{number}}</p>
    <button @click ="changeInSon()" >change</button>
    <hr>
  </div>
</template>

<script>
export default {
  props: {
    number: Number
  },
  methods: {
    changeInSon() {
        this.$emit("changeInParent",200)
    }
  },
};
</script>

在这里插入图片描述
2. $emit

  • 父传子,子传孙
    在上面的基础上加上grandson.vue组件,parent.vue不做修改

son.vue

<template>
  <div>
    <p>son--->{{number}}</p>
    <button @click ="changeInSon()" >change</button>
    <hr>
    <grandson :number = "number" @change="change"></grandson>
  </div>
</template>

<script>
import grandson from "./grandson"
export default {
  props: {
    number: Number
  },
  methods: {
    changeInSon() {
        this.$emit("changeInParent",200)
    },
    change(newValue){
        this.$emit("changeInParent",newValue)
    }
  },
  components:{
      grandson
  }
};
</script>

grandson.vue

<template>
  <div>
    <p>grandson--->{{number}}</p>
    <button @click="changeInGrandson()">change</button>
  </div>
</template>

<script>
export default {
  props: {
    number: Number
  },
  methods: {
      changeInGrandson(){
          this.$emit("change",300)
      }
  }
};
</script>

在这里插入图片描述
同步父子组件的数据=>语法糖的写法
2.1. .sync/update

parent.vue

<template>
  <div>
    parent--->{{number}}
    <hr />
    <son :number = number @update:number="changeInParent"></son>  
  </div>
</template>

<script>
import son from "./son";
export default {
  data() {
    return {
      number: 100
    };
  },
  methods: {
     changeInParent(newValue){
       this.number = newValue
     }
  },
  components: {
    son
  }
};
</script>
</script>

以上还可以简化为:

parent.vue

<template>
  <div>
    parent--->{{number}}
    <hr />
    <!-- <son :number = number @update:number="newValue=>number = newValue"></son> -->
    <son :number.sync = number></son>
  </div>
</template>

<script>
import son from "./son";
export default {
  data() {
    return {
      number: 100
    };
  },
  components: {
    son
  }
};
</script>

son.vue

<template>
  <div>
    <p>son--->{{number}}</p>
    <button @click ="changeInSon()" >change</button>
    <hr>
  </div>
</template>

<script>
export default {
  props: {
    number:Number,
  },
  methods: {
    changeInSon() {
        this.$emit("update:number",600)
    },
  },
};
</script>

在这里插入图片描述
2.2 .v-model/input/value

v-mode只能给子组件传递一个属性

parent.vue

<template>
  <div>
    parent--->{{number}}
    <hr />
    <!-- <son :value = number @input="newValue => number = newValue"></son> -->
    <son v-model="number"></son>
  </div>
</template>

<script>
import son from "./son";
export default {
  data() {
    return {
      number: 100
    };
  },
  components: {
    son
  }
};
</script>

son.vue

<template>
  <div>
    <p>son--->{{value}}</p>
    <button @click ="changeInSon()" >change</button>
    <hr>
  </div>
</template>

<script>
export default {
  props: {
    value: Number
  },
  methods: {
    changeInSon() {
        this.$emit("input",700)
    },
  },
};
</script>

在这里插入图片描述
3. $children/$parent

使用 this.$parent查找当前组件的父组件,可直接触发父组件的父组件的方法
使用 this.$children查找当前组件的直接子组件,可以遍历全部子组件,但$children 并不保证顺序,也不是响应式的。

parent.vue

<template>
  <div>
    parent--->{{number}}
    <hr />
    <son :number = number @changeInParent="changeInParent"></son>
  </div>
</template>

<script>
import son from "./son";
export default {
  data() {
    return {
      number: 100
    };
  },
  methods: {
    changeInParent(newValue){
      this.number = newValue
    }
    
  },
  components: {
    son
  }
};
</script>

son.vue

<template>
  <div>
    <p>son--->{{number}}</p>
    <button @click ="changeInSon()" >change</button>
    <hr>
    <grandson :number = "number"></grandson>
  </div>
</template>

<script>
import grandson from "./grandson"
export default {
  props: {
    number: Number
  },
  methods: {
    changeInSon() {
        this.$emit("changeInParent",200)
    },
  },
  components:{
      grandson
  }
};
</script>

grandson.vue

<template>
  <div>
    <p>grandson--->{{number}}</p>
    <button @click="changeInGrandson()">change</button>
  </div>
</template>

<script>
export default {
  props: {
    number: Number
  },
  methods: {
      changeInGrandson(){
          this.$parent.$emit("changeInParent",400)
      }
  }
};
</script>

在这里插入图片描述
出现多层时使用 :$disptch/broadcast

如果层级很深就会出现$parent.$parent…这里封装一个$dispach方法进行向上派发

parent.vueson.vue较上一个案例不做修改,
main.js中定义一个dispatch方法,$dispatch可以逐级往上找父中的方法,
main.js中定义一个broadcast方法,broadcast可以逐级往上找父中的方法.

main.js

import Vue from "vue";
import App from "./App"

// 自己定义一个disptch方法
Vue.prototype.$dispatch = function(evenName,value){
    let parent = this.$parent;
    while(parent){
        parent.$emit(evenName,value)
        parent = parent.$parent
    }
}

new Vue({
    el:"#app",
    render:h=>h(App)
})

grandson.vue

<template>
  <div>
    <p>grandson--->{{number}}</p>
    <button @click="changeInGrandson()">change</button>
  </div>
</template>

<script>
export default {
  props: {
    number: Number
  },
  methods: {
      changeInGrandson(){
          this.$dispatch("changeInParent",500)
      }
  }
};
</script>

在这里插入图片描述
4.$attrs、 $listeners

$attrs、 $listeners均可跨级传值

$attrs用来接收传过来的多个属性,跨级传用 v-bind
$listeners用来接收传过来的多个方法,跨级传用 v-on

parent.vue

<template>
  <div>
    parent--->{{number}}--->{{sum}}
    <hr />
    <son :number="number" :sum="sum" @click="showclick" @mousedown="showmouse"></son>
  </div>
</template>

<script>
import son from "./son";
export default {
  data() {
    return {
      number: 100,
      sum: 0
    };
  },

  methods: {
    showclick() {
      window.console.log("clickEvent...");
    },
    showmouse(){
      window.console.log("mouseEvent...");
    }
  },
  components: {
    son
  }
};
</script>

son.vue

<template>
  <div>
    <p>son--->{{$attrs.number}}--->{{$attrs.sum}}</p>
    <hr>
    <grandson v-bind="$attrs" v-on = "$listeners" ></grandson>
  </div>
</template>

<script>
import grandson from "./grandson"
export default {
  inheritAttrs: false, //可以把传递过来的属性不作为标签真正的属性
  components:{
      grandson
  },
  
};
</script>

在这里插入图片描述
grandson.vue

<template>
  <div>
    <p>grandson--->{{$attrs}}</p>
    <p>grandson--->number:{{$attrs.number}}--->{{$attrs.sum}}</p>
    <button @click="$listeners.click()">triggerClickEvent</button>
    <br><br>
    <button @click="$listeners.mousedown()">triggerMouseEvent</button>
  </div>
</template>

在这里插入图片描述
5. Provide&Inject

数据比较多的情况下,不建议使用

Provide 在父级中提供数据

<template>
  <div>
    <parent></parent>
  </div>
</template>

<script>
import parent from "./components/parent";
export default {
  provide() {
    return {
      name: "wangcai"
    };
  },
  components: {
    parent
  }
};
</script>

Inject在任意子组件中可以注入父级数据

<template>
  <div>
    {{name}}
  </div>
</template>

<script>
export default {
  inject: ["name"],
};
</script>

6. ref/refs

获取组件实例,在父组件中得到子组件,并且调用子组件的方法
利用ref给子组件起一个name,然后在父组件中利用this.$refs.name.alertINfo()去获取子组件中的alertINfo()方法

parent.vue

<template>
  <div>
    <son ref="sonMethods"></son>
  </div>
</template>

<script>
import son from "./son";
export default {
  mounted() {
    this.$refs.sonMethods.alertINfo()
  },
  components: {
    son
  }
};
</script>

son.vue

<template>
  <div>
  </div>
</template>
<script>
export default {
  methods: {
    alertINfo() {
      window.console.log("this is a methods on son ......");
    }
  }
};
</script>

在这里插入图片描述
7. EventBus

事件总线,用于跨组件通知
在入口文件中将$bus挂载到Vue原型上
然后利用this.$bus.$on("event",function(){ })在父组件注册事件
然后利用this.$bus.$emit("event")在子组件注册事件

main.js

import Vue from "vue";
import App from "./App";
// 将$bus挂载到Vue原型上面的一个vm
Vue.prototype.$bus = new Vue()

new Vue({
  el: "#app",
  render: h => h(App)
});

parent.vue

<template>
  <div>
    <son></son>
  </div>
</template>
<script>
import son from "./son";
export default {
  mounted() {
    this.$bus.$on("change",function(){
       window.console.log("change...");
    })
  },
  components: {
    son
  }
};
</script>

grandson.vue

<template>
  <div>
  </div>
</template>

<script>
export default {
  mounted(){
    this.$nextTick(()=>{
            this.$bus.$emit("change")
        })
  }
};
</script>

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章