vueの$on,$emit,v-onの3つの関係

49599 ワード

$on,$emit,v-onの3つの関係
各Vueインスタンスには、イベントインタフェースが実装されています.
$on(eventName)を使用してイベントをリスニング$emit(eventName)を使用してイベントをトリガーVueを1つの家庭(単独のcomponentsに相当)と見なすと、女主人はずっと家で($emit)男を割り当てて仕事をしていたが、男は($on)女の割り当て($emit)でeventNameがトリガーしたイベントメッセージをリスニングしていた.$emitイベントがトリガーされると、$onは$emitが配布したイベントを傍受し,配布したコマンドと実行派が命令を実行するためにしなければならないことは一つ一つ対応している.
Apiの説明:
vm.$emit( event, […args] )
パラメータ:
{string}event[...args]は、現在のインスタンス上のイベントをトリガーします.追加のパラメータは、リスナーコールバックに渡されます.
vm.$on( event, callback )
パラメータ:
{string|Array}event(配列は2.2.0+でのみサポート){Function}callback
使用方法:
現在のインスタンスのカスタムイベントをリスニングします.イベントはvm.$Emitトリガ.コールバック関数は、すべての受信イベントトリガ関数の追加パラメータを受信します.
<template>
  <div>
      <p @click='emit'>{{msg}}</p>
  </div>
</template>

<script>
export default {
  name: 'demo',
  data () {
      return {
         msg : '       '
      }
  },
  created () {
      this.$on('wash_Goods',(arg)=> {
          console.log(arg)
      })
  },
  methods : {
      emit () {
         this.$emit('wash_Goods',['fish',true,{name:'vue',verison:'2.4'}])
      }
  }
}
</script>
<template>
  <div>
      <p @click='emit'>{{msg}}</p>
      <p @click='emitOther'>{{msg2}}</p>
  </div>
</template>

<script>
export default {
  name: 'demo',
  data () {
      return {
         msg : '       ',
         msg2 : '       2',
      }
  },
  created () {

      this.$on(['wash_Goods','drive_Car'],(arg)=> {
          console.log('   ')
      })
      this.$on('wash_Goods',(arg)=> {
          console.log(arg)
      })
      this.$on('drive_Car',(...arg)=> {
          console.log(BMW,Ferrari)
      })
  },
  methods : {
      emit () {
         this.$emit('wash_Goods','fish')
      },
      emitOther () {
         this.$emit('drive_Car',['BMW','Ferrari'])
      }
  }
}
</script>

以上のケースは何を言いましたか.文章の初めに$emit(eventName)は$on(eventName)と1つ対応していると述べ、以上の2人を結びつけて家族を構成する前に、女性は男性に$(emit)のことを配布し、男性は家族を構成する前に$on(eventName)の後にどのようにすべきかを教えてくれるマニュアルを並べた.
以上の説明で公式Apiの意味をさらに説明します.
vm.$emit( event, […args] )
パラメータ:
{string} event
最初のパラメータは、送信するイベント名であり、Stringタイプでなければなりません.
物語の中では、男に実行しなければならないことを伝えることです.
[…args]
2番目のパラメータは任意のデータ型です.複数の異なるデータ型を転送する必要がある場合は、配列に書き込むことができます.このように[object,Boolean,function,string,...]パラメータを1つ送信すれば、this.$emit(‘wash_Goods’,‘fish’)
物語の中では、男に物をどこに置くか、どんな道具が必要かなどを教えるマニュアルです.
vm.$on( event, callback )
パラメータ:
{string|Array}event(配列は2.2.0+でのみサポートされています)
最初のパラメータは$emit(eventName)に対して1つ1つ対応する$on(eventName)であり、両者は共存し、Stringタイプでなければならない.
(配列は2.2.0+でのみサポートされている)またはArray配列にはString項が含まれている必要がありますが、後で具体的に説明します.
物語の中では、男性が1つの家庭(components)を構成している間に傍受した事件名である.
{Function} callback
2番目のパラメータはfunctionであり、前コールバック関数とも呼ばれ、$emitによってトリガーされたときに入力されたパラメータ(単一のパラメータであれば)を受信することができます.
物語の中では、男が女から配布されたことを受け取って、そんなことをしなければならない.
{string|Array}event(配列は2.2.0+でのみサポートされている)は2.2にこのApiを追加することは別の方法であり、この他の独特な使い方も存在する.
物語を続けていくと、女の人が配ることが多くなって、男としてもうんざりしていると信じています.一度事件を聞いたら、きっとイライラして、文句を言っています.
もし女の人が家庭を作る前に、男の人にそれらのことを傍受すると言ったら、一つのことをすると文句を言って、啓はこれ以上のことではありません.だから、私たちはArray eventを通じて事件名を配列に書いて、配列にあなたが傍受したい事件を書き込んで、共有の原則を使っていくつかの配布事件を実行することができます.以上の例では、女性がdriveを配布してもカールかwashGoodsイベントは、多くのイベントが印刷され、リスニングに対応するイベントが実行されます.
通常、以上の使い方は意味がありません.通常のビジネスでは、このような使い方は使えません.通常、コンポーネントを書くときに、$emitを親の役割ドメインでトリガーし、サブコンポーネントの実行を通知します.次に、親コンポーネントでサブコンポーネントのインスタンスを取得してイベントを送信するが、サブコンポーネントで事前にイベント傍受を送信する準備を行い、対応するイベントを1つ1つ受信してコールバックを行うことを見ることができ、同様にパッケージコンポーネントが親コンポーネントに露出するインタフェースと呼ぶこともできる.
DEMOドロップダウンinfinite-scroll
<template>
    <div>
        <slot name="list"></slot>

        <div class="list-donetip" v-show="!isLoading && isDone">
            <slot>       </slot>
        </div>

        <div class="list-loading" v-show="isLoading">
            <slot>   </slot>
        </div>
    </div>
</template>

<script type="text/babel">

    export default {
        data() {
            return {
                isLoading: false,
                isDone: false,
            }
        },
        props: {
            onInfinite: {
                type: Function,
                required: true
            },
            distance : {
                type : Number,
                default100
            }
        },
        methods: {
            init() {
                this.$on('loadedDone', () => {
                    this.isLoading = false;
                    this.isDone = true;
                });

                this.$on('finishLoad', () => {
                    this.isLoading = false;
                });
            },
            scrollHandler() {
                if (this.isLoading || this.isDone) return;
                let baseHeight = this.scrollview == window ? document.body.offsetHeight : this.scrollview.offsetHeight
                let moreHeight = this.scrollview == window ? document.body.scrollHeight : this.scrollview.scrollHeight;
                let scrollTop = this.scrollview == window ? document.body.scrollTop : this.scrollview.scrollTop

                if (baseHeight + scrollTop + this.distance > moreHeight) {
                    this.isLoading = true;
                    this.onInfinite()
                }
            }
        },
        mounted() {
            this.scrollview = window
            this.scrollview.addEventListener('scroll', this.scrollHandler, false);
            this.$nextTick(this.init);
        },
    }
</script>

ドロップダウン・コンポーネントに追加されたコンポーネントを簡単にカプセル化しました.
dataパラメータの解釈:
isLoading falseはドロップダウン・ロードを実行してより多くのデータを取得していることを表し、trueはデータのロードが完了したことを表し、isDone falseはデータが完全にロードされていないことを表し、trueはデータがすべてロードされたことを表し、propsパラメータの解釈:
onInfinite親コンポーネントから子コンポーネントへの転入底部スクロール時にロードデータを実行する関数distance距離スクロール底部の設定値このコンポーネントから各ステップの解析を行う
mountedの時、windowに対して像に対して1つのスクロールリスニングを行って、リスニングの関数はscrollHandlerですisLoading、isDoneのいずれかがtrueの時isloadingをtrueに退出する時何度も同じロードを防止して、必ずロードが完了するisDoneがtrueの時にすべてのデータがすでにロードが完成したことを説明しなければならなくて、scrollHandlerを再実行する必要はありません$nexttickでloadedDoneコンポーネントインスタンス$emit(‘loadedDone’)イベントが発生したらコールバックを実行し、ロード権限finishLoadを解放コンポーネントインスタンス$emit(‘finishLoad’)イベントが発生したらコールバックを実行します.ロード権限を解除してscrollHandler関数でif(this.isLoading‖this.isDone)returnが発生していることを確認します.一方がtrueであると、mountedでif(baseHeight+scrollTop+this.distance>moreHeight)について述べたため、mountedは終了する.windowオブジェクト上でscrollイベントを傍受するとき、最後までスクロールするときにthisを実行する.isLoading = true;これを繰り返し傍受することを防止する.onInfinite()データ関数のロードを実行する親コンポーネントからinfinite-scrollコンポーネントを呼び出す
<template>
      <div>
          <infinite-scroll :on-infinite='loadData' ref='infinite'>
               <ul slot='list'>
                  <li v-for='n in Number'></li>
               </ul>
          </infinite-scroll>
      </div>
</template>

<script type="text/babel">
import 'InfiniteScroll' from '.......' //  infinitescroll.vue  
    export default {
         data () {
           return {
              Number : 10
           }
         },
         methods : {
           loadData () {
             setTimeout(()=>{
                this.Number = 20
                this.$refs.infinite.$emit('loadDone')
             },1000) 
           }
        }
    }
</script>

親コンポーネントにinfinite-scrollコンポーネントを導入する
最後にスライドすると、infinite-scrollコンポーネントの内部で入力が実行されます.on-infinite='loadData'関数は、内部でもLoadingをtrueに設定し、重複実行を防止します.
ここでthis.$refs.infiniteはinfinite-scrollコンポーネントのインスタンスを取得し、同時にイベントの前にコンポーネントの中で$onがすでに傍受していたイベントをトリガーし、1秒後にデータを変更すると同時にloadDoneを発行し、コンポーネント内部にloadDoneの傍受コールを実行するように伝え、データがすべてロードされた後、thisを設定する.isDone = true; isDoneまたはisLoadingの一方がtrueである場合、return終了状態は維持されます.
$emitと$onは、インスタンス上でトリガおよびリスニングを行う必要があります.
v-onカスタムバインドイベントの使用
第1段階の$emitと$onの両者の関係は終わり,次にv-onと$emitの関係について述べる.
さらに、親コンポーネントは、サブコンポーネントの導入テンプレートを使用して、サブコンポーネントがトリガーしたイベントを直接v-onで傍受することができる.
v-onは物語を続けて直観的に言えば、家に電話を入れて、両親はずっと電話を聞いていて、同じようにパンフレットもあって、家庭を構成する前に、それらのことを監視しなければなりません.
Warn
$onでサブコンポーネントが解放されたイベントをリスニングするのではなく、テンプレートに直接v-onでバインドする必要があります.
Warnは、e m i tおよびemitおよびemitおよびonが1つの対応する同じコンポーネントインスタンスにのみ作用し、v−onは親コンポーネントがサブコンポーネントを導入したテンプレートにのみ作用することを意味する.
次のようにします.
公式のこの例で言えば、実は直感的です.
<div id="counter-event-example">
  <p>{{ total }}</p>
  <button-counter v-on:increment="incrementTotal"></button-counter>
  <button-counter v-on:increment="incrementTotal"></button-counter>
</div>
Vue.component('button-counter', {
  template: '',
  data: function () {
    return {
      counter: 0
    }
  },
  methods: {
    incrementCounter: function () {
      this.counter += 1
      this.$emit('increment')
    }
  },
})
new Vue({
  el: '#counter-event-example',
  data: {
    total: 0
  },
  methods: {
    incrementTotal: function () {
      this.total += 1
    }
  }
})

このようなメリットはどこにありますか?Vueはデータの一方向ストリームを行うが、サブコンポーネントは親コンポーネントのデータを直接変更することはできない(完全にできないわけではないが、推奨しない).標準的には、親コンポーネントによってサブコンポーネントテンプレート上でv-onのバインドリスニングイベントを行い、リスニング後に実行するコールバックを書き込む.
counter-event-example親コンポーネントでは、2つのbutton-countの実列を宣言し、dataを介して閉パケットの形式で、両方のデータを個別に楽しむことができ、v-onが傍受するeventNameは現在の自分の実列の$emitがトリガーするイベントですが、コールバックは共通のincrementTotal関数です.インスタンスがトリガーされると、アクションが実行されるからです.
親子コンポーネントベースの単一データを簡単に双方向に通信したいだけであれば、テンプレート上でv-onと監視されているテンプレートインスタンス上で$emitトリガイベントを行うのは、少し余計です.通常、v-onによってサブコンポーネントのトリガイベントを傍受すると、いくつかのマルチステップ操作が行われます.サブアセンブリ
<template>
  <div>
      <p @click='emit'>{{msg}}</p>
  </div>
</template>

<script>
export default {
  name: 'demo',
  data () {
      return {
         msg : '       ',
      }
  },
  methods : {
      emit () {
         this.$emit('fromDemo')
      },
  }
}
</script>

親コンポーネント
<template>
  <div class="hello">
     <p>hello {{msg}}</p>
     <demo v-on:fromDemo='Fdemo'></demo>
  </div>
</template>
<script>
import Demo from './Demo.vue'
export default {
  name: 'hello',
  data () {
    return {
       msg: '         '
    }

  },
  methods: {
    waitTime() {
      return new Promise(resolve=>{
        setTimeout(()=> {
            this.msg = '        '
            resolve(1)
        },1000)
      })
    },
    async Fdemo () {
        let a = await this.waitTime();
        console.log(a)
    }
  },
  components : {
     Demo
  }
}
</script>

上のdemoから、サブコンポーネントがfromDemoイベントをトリガーし、親コンポーネントも傍受していることがわかります.
親コンポーネントがサブコンポーネントのイベントトリガを受信すると、asyncの非同期イベントが実行され、msgが1秒の等秒で変更され、コールバック後にpromiseで返される値が印刷される.
次に、この例を説明します.この方法は、通常、サブコンポーネントのイベントを傍受することによって、親コンポーネントにいくつかのマルチステップ操作を実行させます.親コンポーネントが伝達された値を変更することを簡単に示すだけで、この方法では余計です.
サブコンポーネント
<template>
  <div>
      <p @click='emit'>{{msg}}</p>
  </div>
</template>

<script>
export default {
  name: 'demo',
  props: [ 'msg' ],
  methods : {
      emit () {
         this.$emit('fromDemo','     ')
      },
  }
}
</script>

親コンポーネント
<template>
  <div class="hello">
     <demo v-on:fromDemo='Fdemo' :msg='msg'></demo>
  </div>
</template>
<script>
import Demo from './Demo.vue'
export default {
  name: 'hello',
  data () {
    return {
       msg: '      '
    }
  },
  methods: {
    Fdemo (arg) {
      this.msg = arg 
    }
  },
  components : {
     Demo
  }
}
</script>

上のdemo中性子コンポーネントは親コンポーネントからmsgデータを受信するが、ボタンをクリックしたい場合、親コンポーネントのmsgを変更し、親コンポーネントのデータ変更を行い、同時にサブコンポーネントのmsgを再び変更するが、最も簡単な方法はpropのmsgのデータを直接変更することである.しかし、データ駆動はすべて一方向のデータストリームであり、データ伝達の混乱をもたらさないために、Git Chatの転載をいくつかの他の手段で完了するしかない.