初心者向けVue.jsレッスン9:カスタムイベント

Vueコースの前のレッスンでは、コンポーネントを作成する方法と、propsメカニズムを使用して親から子にデータを渡す方法を学びました。データを反対方向に転送する必要がある場合はどうなりますか?今日の9番目のレッスンでは、異なるレベルのコンポーネント間で双方向の通信を確立する方法を学習します。







Vue.js初心者レッスン1:インスタンスVue

初心者向けVue.js、レッスン2:バインディング属性

Vue.js初心者レッスン3:条件付きレンダリング

Vue.js初心者レッスン4:リストレンダリング

Vue .js初心者向けレッスン5:イベント処理

Vue.js初心者向けレッスン6:クラスとスタイルのバインド

Vue.js初心者向けレッスン7:計算されたプロパティ

Vue.js初心者向けレッスン8:コンポーネント

Vue。初心者向けjsレッスン9:カスタムイベント



レッスンの目的



コンポーネントproductが、イベントが発生したことを親エンティティであるルートVueインスタンスに通知できるようにする必要があります。この場合、productイベントの発生通知とともに、いくつかのデータを送信する必要があります。



初期コード



index.htmlチュートリアルプロジェクト ファイルには、次のコードが含まれています。



<div id="app">
  <product :premium="premium"></product>
</div>


ファイルの内容は次のmain.jsとおりです



Vue.component('product', {
  props: {
    premium: {
      type: Boolean,
      required: true
    }
  },
  template: `
  <div class="product">
    <div class="product-image">
      <img :src="image" />
    </div>

    <div class="product-info">
      <h1>{{ title }}</h1>
      <p v-if="inStock">In stock</p>
      <p v-else>Out of Stock</p>
      <p>Shipping: {{ shipping }}</p>

      <ul>
        <li v-for="detail in details">{{ detail }}</li>
      </ul>
      <div
        class="color-box"
        v-for="(variant, index) in variants"
        :key="variant.variantId"
        :style="{ backgroundColor: variant.variantColor }"
        @mouseover="updateProduct(index)"
      ></div>

      <button
        v-on:click="addToCart"
        :disabled="!inStock"
        :class="{ disabledButton: !inStock }"
      >
        Add to cart
      </button>

      <div class="cart">
        <p>Cart({{ cart }})</p>
      </div>
    </div>
  </div>
  `,
  data() {
    return {
      product: 'Socks',
      brand: 'Vue Mastery',
      selectedVariant: 0,
      details: ['80% cotton', '20% polyester', 'Gender-neutral'],
      variants: [
        {
          variantId: 2234,
          variantColor: 'green',
          variantImage: './assets/vmSocks-green.jpg',
          variantQuantity: 10
        },
        {
          variantId: 2235,
          variantColor: 'blue',
          variantImage: './assets/vmSocks-blue.jpg',
          variantQuantity: 0
        }
      ],
      cart: 0,
    }
  },
    methods: {
      addToCart() {
        this.cart += 1;
      },
      updateProduct(index) {
        this.selectedVariant = index;
        console.log(index);
      }
    },
    computed: {
      title() {
        return this.brand + ' ' + this.product;
      },
      image() {
        return this.variants[this.selectedVariant].variantImage;
      },
      inStock() {
        return this.variants[this.selectedVariant].variantQuantity;
      },
      shipping() {
        if (this.premium) {
          return "Free";
        } else {
          return 2.99
        }
      }
    }
})

var app = new Vue({
  el: '#app',
  data: {
    premium: true
  }
})


仕事



現在、productスタンドアロンコンポーネントとして提示された場合、ショッピングカートに関連するコードがその中に含まれていることはproduct意味がありません。各製品にステータスを監視する必要のある独自のバスケットがある場合、アプリケーションは大きな混乱になります。代わりに、カートをVueインスタンスのルートに存在させたいと思います。またproduct、カートへのアイテムの追加、つまりボタンのクリックについてルートVueインスタンス通知するコンポーネントも必要Add to cartです。



決定



カートに関連するデータをルートVueインスタンスに戻しましょう。



var app = new Vue({
  el: '#app',
  data: {
    premium: true,
    cart: 0
  }
})


次に、カートテンプレートをに戻しindex.html、そのコードを次のフォームに移動します。



<div id="app">
  <div class="cart">
    <p>Cart({{ cart }})</p>
  </div>

  <product :premium="premium"></product>
</div>


これで、ブラウザでアプリケーションページを開いてボタンをクリックしてAdd to cartも、期待どおりに何も起こりません。





[カートに追加]ボタンをクリックしても、まだ何も表示されません



。このボタンをクリックするとどうなりますか?それをクリックすると、ルートVueインスタンスが、カートを最新の状態にする、つまりに格納されている値を更新するメソッドを呼び出す通知を受信する必要がありますcart



これを実現するために、最初にaddToCartコンポーネントメソッドコードを書き直してみましょうproduct



これで、次のようになります。



addToCart() {
  this.cart += 1;
},


それをこの形に持っていきましょう:



addToCart() {
  this.$emit('add-to-cart');
},


これはどういう意味ですか?



それがそれです。メソッドが呼び出されるaddToCartと、カスタムの名前付きイベントが生成されadd-to-cartます。つまり、ボタンAdd to cartがクリックされると、ボタンが押されたばかり(つまり、ボタンのクリックによってトリガーされたイベントが発生したばかり)を示すイベントを生成するメソッドが呼び出されます。



しかし、現時点では、アプリケーションでこのイベントが発生するのを待っているものや、それをリッスンしているものはありません。イベントリスナーをindex.htmlの場所に追加しましょう



<product :premium="premium" @add-to-cart="updateCart"></product>


ここでは、構成を使用するの@add-to-cardと同じ方法でビュー構成を使用します:premium。ただし:premium、親から子コンポーネントにデータを送信できる「パイプライン」の場合@add-to-cart、ボタンが押されたという情報を子コンポーネントから受信する親コンポーネントの「無線受信機」と比較できますAdd to cart。 「radio」<product>はにネストされたタグ<div id="app">にあるため、クリックに関する情報が到着すると、ルートVueインスタンスにあるAdd to cartメソッドが呼び出されupdateCartます。通常の言語に翻訳すると、



コード@add-to-cart=«updateCart»は次のようになります。「イベントが発生したと聞いたらadd-to-cart、メソッドを呼び出しますupdateCart。」



このメソッドは、Vueをインスタンス化するときに使用されるoptionsオブジェクトで宣言されるようになりましたが、おそらくどこかで見たことがあるでしょう。



methods: {
  updateCart() {
    this.cart += 1;
  }
}


実際、これは以前に使用された方法とまったく同じproductです。しかし、現在はルートVueインスタンスにあり、ボタンをクリックすると呼び出されますAdd to cart





ボタンが再び機能



するコンポーネント内のボタンをクリックすると、イベントを生成するproductメソッドが呼び出されaddToCartます。「ラジオを聞いている」ルートVueインスタンスは、このイベントが発生したことを学習しupdateCart、に格納されている数をインクリメントするメソッド呼び出しますcart



目標は達成しましたが、実際のアプリケーションでは、イベントが発生したこと、特定の製品がカートに追加されたことを知っていても、あまりメリットはありません。実際には、少なくともどの製品がカートに追加されたかを知る必要があります。これは、ボタンを押したことに応じて生成されたイベントでは、いくつかのデータも転送する必要があることを意味します。



イベントで渡されるデータ$emitは、addToCartコンポーネントメソッドのコードで渡される2番目の引数として説明できます。product



this.$emit('add-to-cart', this.variants[this.selectedVariant].variantId);


これで、イベントは、variantIdユーザーがカートに追加したい製品のID()を渡します。これは、カート内のアイテムの数を増やすだけでなく、さらに進んで、カートに追加されたアイテムに関するより詳細な情報をカートに保存できることを意味します。これを行うには、最初に空の配列をcart次のように書き込んでカートを配列に変換します。



cart: []


次に、メソッドを書き直してみましょうupdateCart1つ目idは、イベントで渡されるのと同じ製品IDを受け入れるようになり、2つ目は、受信したものを配列に入れるようになります。



methods: {
  updateCart(id) {
    this.cart.push(id);
  }
}


ボタンを1回クリックすると、製品IDが配列に追加されます。配列がページに表示されます。





製品IDの配列がページに表示されます



配列全体をページに表示する必要はありません。カート、つまりアレイに追加された製品の数の出力に満足しcartます。したがって、<p>カートに追加された製品の数に関する情報を表示するタグコードを次のように書き直すことができます。



<p>Cart({{ cart.length }})</p>




このページには、カートに追加されたアイテムの数に関する情報が表示されます。



ここでは、ページ上の配列の長さ、つまりカート内のアイテムの数を表示するだけです。外部的には、カートは以前と同じように見えますが、数値プロパティの値を単純に増やすのではなく、カートに追加されたアイテムに関する情報をcart配列にcart格納するようになりました。



ワークショップ



プロジェクトにボタンを追加して、cartそこに以前に追加し製品をアレイから削除します。このボタンをクリックすると、カートから削除するアイテムのIDに関する情報を含むイベントが生成されます。



  • これは、この問題を解決するために使用できるテンプレートです。
  • これが問題解決策です。


結果



今日学んだことは次のとおりです。



  • コンポーネントは、構成を使用して、親エンティティで何かが発生したことを親エンティティに通知でき$emitます。
  • 親コンポーネントは、ディレクティブv-on(またはその短縮バージョン@)を使用して指定されたイベントハンドラーを使用して、子コンポーネントによって生成されたイベントへの応答を整理できます。イベントが発生した場合、親コンポーネントでイベントハンドラーを呼び出すことができます。
  • , , .


コースを勉強していて、このレッスンに来た場合は、Vueをマスターすることで達成したいこと、目的を教えてください。



Vue.js初心者レッスン1:インスタンスVue

初心者向けVue.js、レッスン2:バインディング属性

Vue.js初心者レッスン3:条件付きレンダリング

Vue.js初心者レッスン4:リストレンダリング

Vue .js初心者向けレッスン5:イベント処理

Vue.js初心者向けレッスン6:クラスとスタイルのバインド

Vue.js初心者向けレッスン7:計算されたプロパティ

Vue.js初心者向けレッスン8:コンポーネント

Vue。初心者向けjsレッスン9:カスタムイベント






All Articles