可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Check out this simple shopping cart demo:
http://plnkr.co/edit/CHt2iNSRJAJ6OWs7xmiP?p=preview
A user can pick a veggie and a fruit, and it will be added into the cart array. The function that adds a fruit/veggie is very similar, and I want to combine it into a function that can be shared across both components.
selectFruit: function(product){ var cart = this.cart for(p in cart){ if (cart[p]["type"] == "fruit"){ console.log("We already got a fruit!, Let's remove " + cart[p]["name"] + " and add in " + product["name"]); this.cart.$remove(cart[p]) } } console.log("Adding " + product.name + " to cart."); var productName = product.name var cartFruit = {name: product.name, type: 'fruit'} this.cart.push(cartFruit) } selectVeggie: function(product){ var cart = this.cart for(p in cart){ if (cart[p]["type"] == "veggie"){ console.log("We already got a veggie!, Let's remove " + cart[p]["name"] + " and add in " + product["name"]); this.cart.$remove(cart[p]) } } console.log("Adding " + product.name + " to cart."); var productName = product.name var cartVeggie = {name: product.name, type: 'veggie'} this.cart.push(cartVeggie) }
How can I make it so I can alter this method and have it used globally? I'm using the Vue Router with this project btw, thanks for any help!
回答1:
Option 1
One approach for sharing your method across components is to use a mixin. Here's a cartMixin
that contains a selectProduct
method:
var cartMixin = { methods: { selectProduct: function (product) { var cart = this.cart for(p in cart){ if (cart[p]["type"] == product.type){ console.log("We already got a "+ product.type +"!, Let's remove " + cart[p]["name"] + " and add in " + product["name"]); this.cart.$remove(cart[p]) } } console.log("Adding " + product.name + " to cart."); var productName = product.name var cartProduct = {name: product.name, type: product.type} this.cart.push(cartProduct) } } };
You can reference this in each component like this:
var Vegetable = Vue.extend({ template: '#vegetable', mixins: [cartMixin], data: function(){ return sourceOfTruth } })
... and then use it in your templates like this:
<li v-for="product in food | showOnly 'fruit'" @click="selectProduct(product)"> {{product.name}} </li>
Here's a fork of your Plunker.
Option 2
After thinking about this some more, another option you might consider is to create a base Product
component and extend that to create your Fruit
and Vegetable
components. You would then put your common functionality in the base component.
var Product = Vue.extend({ data: function(){ return sourceOfTruth }, methods: { selectProduct: function (product) { var cart = this.cart for(p in cart){ if (cart[p]["type"] == product.type){ console.log("We already got a "+ product.type +"!, Let's remove " + cart[p]["name"] + " and add in " + product["name"]); this.cart.$remove(cart[p]) } } console.log("Adding " + product.name + " to cart."); var productName = product.name var cartProduct = {name: product.name, type: product.type} this.cart.push(cartProduct) } } }) var Vegetable = Product.extend({ template: '#vegetable', }); var Fruit = Product.extend({ template: '#fruit', });
Here's a Plunker with this approach.
Given that your Fruit and Vegetable templates are so similar, you might be able to take this idea even further and use a common template from the base component.
回答2:
I found this technique to be more simple/satisfactory, as i prefer composition over inheritance:
src/shared.js
export default { foo: function(){ alert("foo!") } }
src/yourcomponent.vue
<template>..</template> <script> import 'shared' from './shared' export default { mounted: function(){ this.foo = shared.foo // now you can call this.foo() (in your functions/template) } } </script>
This will easify writing vue-agnostic tests as well.
NOTE: if you need foo to run in vue-scope replace this.foo = shared.foo
with this.foo = shared.foo.bind(this)
回答3:
You can put the method in your root Vue instance and then dispatch an event from the child instance when a veggie is selected, or when a fruit is selected. Events look for a handler on their parent component, and if they don't find an event handler they keep going up the chain until they do. So on your root instance:
events: { 'choose-fruit':function(fruit){ //handle the choosing of fruit } }
Then on the child instance:
selectFruit: function(product){ this.$dispatch('choose-fruit', product); }