Vue.js入门课程9:自定义事件

在Vue课程的上一课中,您学习了如何创建组件以及如何使用props机制将数据从父级传递到子级。如果数据需要反向传输怎么办?今天,在第九课中,您将学习如何在不同级别的组件之间建立双向通信。







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。初学者第9课js:自定义事件



本课目的



我们希望组件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">,因此,这意味着有关单击的信息到达时Add to cart将调用updateCart位于Vue根实例中的方法



代码@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方法代码中传递的第二个参数addToCartproduct



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


现在,事件传递了variantId用户想要添加到购物车的产品的标识符()。这意味着我们不仅可以增加购物车中的物品数量,还可以走得更远,并在购物车中存储有关添加到购物车中的物品的更多详细信息。为此,我们首先通过将一个空数组写入来将篮子转换为数组cart



cart: []


接下来,让我们重写方法updateCart首先-它现在将接受id-事件中现在传递的相同产品标识符,其次-现在将其接收到的内容放入数组中:



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


单击按钮后,产品标识符将添加到阵列中。阵列显示在页面上。





具有产品ID的阵列显示在页面上。



我们不需要在页面上显示整个阵列。我们将对添加到购物车(即数组)的产品数量的输出感到满意cart因此,我们可以重写标记代码<p>,显示有关添加到购物车的产品数量的信息,如下所示:



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




该页面显示有关添加到购物车中的商品数量的信息,



现在我们只需在页面上显示数组的长度,换句话说就是购物车中的商品数量。从外部看,购物车外观与以前相同,但现在,我们不再只是增加数字属性的值cart,而是在数组中存储cart有关将哪些商品添加到购物车的信息。



作坊



在项目中添加一个按钮,以从阵列中删除cart之前添加产品。通过单击此按钮,应生成一个事件,其中包含有关要从购物车中删除的物品的标识符的信息。



  • 这是您可以用来解决此问题模板。
  • 这是解决问题的方法。


结果



这是您今天学到的:



  • 组件可以使用构造通知父实体发生了某些事情$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。初学者第9课js:自定义事件






All Articles