Vue 組件通訊的多種方式(props、$ref、$emit、$attr、 $listeners)

prop和$ref之間的區別:

prop 着重於數據的傳遞,它並不能調用子組件裏的屬性和方法。像建立文章組件時,自定義標題和內容這樣的使用場景,最適合使用prop。javascript

$ref 着重於索引,主要用來調用子組件裏的屬性和方法,其實並不擅長數據傳遞。並且ref用在dom元素的時候,能使到選擇器的做用,這個功能比做爲索引更常有用到。css

props   父組件傳值子組件

父組件傳值html

//props示例(vue)
<template>
    <div id="app">
      <child :message="message"></child> 動態傳遞
    <child message="傳遞的內容"></child> 靜態傳遞
    </div>
</template>

<script>
    import Child from "./Child";
    export default {
      components: {Child},
      name: "main-page",
      data() {
          return {
            message:{
              type:1,
              name:'Admin',
            },
            a:2,
            b:4,
            c:'lalal'+Math.random(),
            title:'',
            info:'我是來自父組件',
            msg:'默認'
          }
      },
      created() {},
      mounted(){},
      methods: {}
    }

</script>

<style lang="scss" scoped>

</style>

子組件接收父組件傳值vue

<template>
<div>
{{message}}
<!--<slot></slot>-->
</div>
</template>

<script>
export default {
  name: "child",
  props:['message'],
  data() {
    return {
      title:''
    }
  },
  mounted() {},
  methods:{}
}
</script>

<style lang="scss" scoped>
</style>

父組件code引用子組件,經過props能夠實現傳值。能夠傳遞string , number , object,表達式。對於子組件接受父組件props,能夠直接使用props:[‘xxxx’]格式,爲了更嚴謹,能夠使用以下方式:java

<script>
    export default {
      name: "child",
     // props:['message'],
      props:{
        message:{
          type:Object,
          default:function () {
            return {} } } },
      data() {
         return {
            title:''
         }
      },
      mounted() {
         // this.$emit('showMessage','我是來自子組件')
      },
      methods:{
      }
    }
</script>

 

 


 

 

$emit 子組件向父組件傳值

props、ref 實現的都是父組件=>子組件之間的通訊,而$emit則可實現子組件向父組件的通訊, $emit應用的範圍較爲普遍。vuex

子組件傳值給父組件app

template>
    <div>
     <input ref="myBtn"></input>
    </div>
</template>
<script>
  export default {
      name: "index",
      data() {
         return {
            info:'ref能夠獲取到元素哦~'
         }
      },
      mounted() {
          this.$emit('showMessage','我是來自子組件')
      },
      methods:{
      }
    }
</script>

 

父組件接收子組件傳值less

<template>
    <div id="app">
         <child @showMessage="showMessage"></child>
    </div>
</template>

<script>
    import Child from "./Child";
    export default {
      components: { Child},
      name: "main-page",
      data() {
          return {
            message:{
              type:1,
              name:'Admin',
            },
            fromchildinfo :'我是來自父組件',
            msg:'默認'
          }
      },
      created() {

      },
      mounted(){
      },
      methods: {
        showMessage (data) { this.fromchildinfo = data },
      }
    }
</script>

 


 

 

$ref  的使用

說明:vm.$refs 一個對象,持有已註冊過 ref 的全部子組件(或HTML元素)
使用:在 HTML元素 中,添加ref屬性,而後在JS中經過vm.$refs.屬性來獲取
注意:若是獲取的是一個子組件,那麼經過ref就能獲取到子組件中的data和methods
添加ref屬性dom

<div id="app">
  <h1 ref="h1Ele">這是H1</h1>
  <hello ref="ho"></hello>
  <button @click="getref">獲取H1元素</button>
</div>
 獲取註冊過 ref 的全部組件或元素
methods: {
  getref() {
    // 表示從 $refs對象 中, 獲取 ref 屬性值爲: h1ele DOM元素或組件
    console.log(this.$refs.h1Ele.innerText);
    this.$refs.h1ele.style.color = 'red';// 修改html樣式

    console.log(this.$refs.ho.msg);// 獲取組件數據
    console.log(this.$refs.ho.test);// 獲取組件的方法
  }
}
<input ref="count" type="text" v-model="active.name" required name="name" value=""> 

  這樣在vue中咱們能夠使用$ref來獲取dom節點,進行一些dom的操做ui

  下面示例:控制input輸入框的文字個數

new Vue({
  el:'#app',
  data:{
  active:{'name':''}
  },
  watch:{
    active:{
      handler:function(){
        var _this = this;
        var _sum = 4; //字數限制爲4個
        _this.$refs.count.setAttribute("maxlength",_sum);
      },
      deep:true
    }
  },
})

使用在子組件上,能夠用來獲取子組件的屬性值,假設子組件裏面都有一個屬性news
<!-- 父組件 -->

<div id="app">
<hdnews ref="hdnews"></hdnews>
<hdinfo ref="hdinfo"></hdinfo>
</div>
new Vue({
  el:'#app',
  mounted () {
    console.log(this.$refs.hdnews.news); //獲取子組件的值
    console.log(this.$refs.hdinfo.news);

this.$refs.msg.getMessage('我是子組件一!') //調用子組件的方法

  }
})

 

<!-- 子組件 --> <template> <h3>{{message}}</h3> </template> <script> export default { data(){ return{ news:'我是子組件的數據' } }, methods:{ getMessage(m){ this.message=m; } } } </script>

 


 

 

$attr、 $listeners
場景提出:A、B、C三個組件,須要實現A=>B=>C,進行傳遞(結構較爲簡單,無需使用vuex)。固然實現方式也能夠$emit,一層一層傳遞下去,但這樣代碼顯得冗餘。在vue2.4以後,提出 $attr、 $listeners ,能夠實現快速傳遞。
組件A code:

<template>
    <div id="app">
     	<son :info="info" @getData="getData"></son>
     	<div>{{msg}}</div>
    </div>
</template>

<script>
    import Son from "./son";

    export default {
      components: {
        Son,
        Test,
        Child},
      name: "main-page",
      data() {
          return {
            message:{
              type:1,
              name:'Admin',
            },
            a:2,
            b:4,
            c:'lalal'+Math.random(),
            title:'',
            info:'我是來自父組件',
            msg:'默認'
          }
      },
      created() {

      },
      mounted(){
      },
      methods: {
         getData (val) {
           this.msg = val
        },
      }

    }

</script>

<style lang="scss" scoped>
 #app {
   width: 375px;
   height: 100%;
 }
</style>

b組件

<template>
    <temp-son v-bind="$attrs" v-on="$listeners"></temp-son>
</template>

<script>
    import TempSon from "./tempSon";

    export default {
      components: {TempSon},
      name: "son",
      props:[]
    }
</script>

<style scoped>

</style>

c組件

<template>
  <div>
    <h1 class="btn">{{this.$attrs.info}}</h1>
  </div>
</template>

<script>
    export default {
      name: "temp-son",
      mounted() {
        this.$emit('getData','我來自孫子組件')
      }
    }
</script>

<style scoped>

</style>

$attr、 $listeners 的TypeScript寫法

A組件

<template>
  <div class="home">
    <img alt="Vue logo" src="@/assets/images/logo.png" />
    <HelloWorld :info="info" @sunchangedata="getData" :msg="info" />
  </div>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import HelloWorld from "@/components/HelloWorld.vue"; // @ is an alias to /src

@Component({
  components: {
    HelloWorld
  }
})
export default class Home extends Vue {
    info = "你不是好人?";
    getData(val:any){
        this.info = val;
    };
}
</script>

b組件

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <p>hello hello 我是來自子組件</p>
    <Sun v-bind="$attrs" v-on="$listeners"></Sun>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";
import Sun from "./sun.vue"; // @ is an alias to /src

@Component({
    components:{
        Sun
    }
})
export default class HelloWorld extends Vue {
    inheritAttrs = false;
    @Prop() private msg!: string;
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="less">

</style>

c組件

<template>
    <div>
        <p>sun組件</p>
        <p>來自爺爺輩:{{ $attrs.info }}</p>
        <button @click="$emit('sunchangedata','孫子說爺爺是好人')">點擊更改爺爺輩信息</button>
    </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";

export default class Sun extends Vue {
  
}
</script>

<style>
</style>
相關文章
相關標籤/搜索