如何在Vue.js中的组件之间共享方法?

时间:2016-01-27 18:21:01

标签: javascript vue.js

查看这个简单的购物车演示:

http://plnkr.co/edit/CHt2iNSRJAJ6OWs7xmiP?p=preview

用户可以选择素食和水果,它将被添加到购物车阵列中。添加水果/蔬菜的功能非常相似,我想将它组合成一个可以在两个组件之间共享的功能。

    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)
}

我该如何制作,以便我可以改变这种方法并将其全局使用?我正在使用这个项目的Vue路由器,感谢您的帮助!

4 个答案:

答案 0 :(得分:31)

我发现这种技术更简单/更令人满意,因为我更喜欢构图而不是继承:

的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>

这也允许您编写与Vue无关的测试。

  

注意:如果您需要foo在Vue范围内运行,请将this.foo = shared.foo替换为this.foo = shared.foo.bind(this)

答案 1 :(得分:28)

选项1

跨组件共享方法的一种方法是使用mixin。这是一个包含cartMixin方法的selectProduct

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)
    }
  }
};

您可以在每个组件中引用它,如下所示:

var Vegetable = Vue.extend({
    template: '#vegetable',
    mixins: [cartMixin],
    data: function(){
        return sourceOfTruth
    }
})

...然后在你的模板中使用它:

<li v-for="product in food | showOnly 'fruit'" @click="selectProduct(product)">
  {{product.name}}
</li>

Here's a fork of your Plunker

选项2

在考虑了这一点之后,您可以考虑的另一个选项是创建基本Product组件并对其进行扩展以创建FruitVegetable组件。然后,您可以将常用功能放在基本组件中。

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

鉴于您的水果和蔬菜模板非常相似,您可以进一步采用这个想法并使用基础组件中的通用模板。

答案 2 :(得分:2)

您可以将方法放在根Vue实例中,然后在选择素食时或选择水果时从子实例调度事件。事件在其父组件上寻找处理程序,如果他们找不到事件处理程序,他们就会继续向上行,直到他们这样做。所以在你的根实例上:

events: {
    'choose-fruit':function(fruit){

        //handle the choosing of fruit

    }
}

然后在子实例上:

selectFruit: function(product){

    this.$dispatch('choose-fruit', product);

}

答案 3 :(得分:1)

如果您试图在多个vue模板和布局之间或沿多个vue模板和布局共享相同的组件逻辑,则可以在下面简单地尝试这种方法:

之前:

a.vue

<template>
  <div>
     <h1>{{title}}</h1>
     <small>{{datetime}}</small>
  </div>
</template>

<script>
export default {
  props: {
    title: String
  },
  data() {
    return {
      datetime: new Date()
    }
  }
}
</script>

b.vue

<template>
  <div>
     <h3>{{title}}</h3>
     <h6>{{datetime}}</h6>
  </div>
</template>

<script>
export default {
  props: {
    title: String
  },
  data() {
    return {
      datetime: new Date()
    }
  }
}
</script>

之后:

a.vue

<template>
  <div>
     <h1>{{title}}</h1>
     <small>{{datetime}}</small>
  </div>
</template>

<script>
import shared from "./shared.js";
export default Object.assign({}, shared);
</script>

b.vue

<template>
  <div>
     <h3>{{title}}</h3>
     <h6>{{datetime}}</h6>
  </div>
</template>

<script>
import shared from "./shared.js";
export default Object.assign({}, shared);
</script>

shared.js

export default {
  props: {
    title: String
  },
  data() {
    return {
      datetime: new Date()
    }
  }
}