How can I share a method between components in Vue.js?

前端 未结 4 1491
野趣味
野趣味 2020-12-13 03:55

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

相关标签:
4条回答
  • 2020-12-13 04:17

    If you are trying to share the same component logic between or along multiple vue template and layout, you can simply try this approach below:

    before:

    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>
    
    

    after:

    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()
        }
      }
    }
    
    
    0 讨论(0)
  • 2020-12-13 04:32

    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);
    
    }
    
    0 讨论(0)
  • 2020-12-13 04:36

    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 {
        created() { 
          this.foo = shared.foo // now you can call this.foo() (in your functions/template)
        }
      }
    </script>
    

    This will also allow you to write Vue-agnostic tests.

    NOTE: if you need foo to run in Vue-scope replace this.foo = shared.foo with this.foo = shared.foo.bind(this)

    0 讨论(0)
  • 2020-12-13 04:36

    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.

    0 讨论(0)
提交回复
热议问题