如何在 Vue.js 中的组件之间共享方法?
Posted
技术标签:
【中文标题】如何在 Vue.js 中的组件之间共享方法?【英文标题】:How can I share a method between components in Vue.js? 【发布时间】:2016-05-04 20:41:55 【问题描述】:查看这个简单的购物车演示:
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 路由器,感谢您的帮助!
【问题讨论】:
【参考方案1】:我只会配置一个 mixin
export const sharedMethods =
// Generic funcion
methods:
axiosGet(route)
return axios.get(route)
.then(response => response.data)
.catch((error)=> console.log(error))
,
axiosPost(route, postObj, resolveCallback, rejectCallback)
axios.post(route, postObj)
.then(resolveCallback)
.catch(rejectCallback);
,
然后在组件中使用 mixin,调用它的函数,就像调用组件本身的函数一样,就好像这些函数是你要导入 mixin 的组件的一部分:
放在组件上:mixins: [sharedMethods],
在组件内部,我调用了mixin函数:
this.axiosPost(
'/route',
data,
() => console.log('success'),
() => console.log('fail')
)
这很有用,因为使用一种方法,您只需从 js 文件中导入函数,正在导入的文件中的函数将在函数中使用它们自己的“this”,这可能会导致一些混乱,而 mixin 将使用它被导入的组件的“this”,就像我说的那样,它的功能是组件的一部分。
【讨论】:
【参考方案2】:如果您尝试在多个 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()
【讨论】:
【参考方案3】:我发现这种技术更简单/令人满意,因为我更喜欢组合而不是继承:
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>
这也将允许您编写与 Vue 无关的测试。
注意:如果您需要 foo 在 Vue 范围内运行,请将
this.foo = shared.foo
替换为this.foo = shared.foo.bind(this)
【讨论】:
我认为应该是import shared from './shared'
,不带引号的shared
为了在模板中使用它,您可以将函数添加到您的方法中,例如 export default name: 'componentName', methods: shared,
@GiorgioTempesta 可以添加更多方法吗?
是的,只要您导入它们并用逗号分隔每个方法即可。此外,如果您需要使用不同的名称调用该方法,则必须将其声明为:methods: 'new_method_name': shared, 'other_method_name': shared2
您好,请问如何使用这种方法进行异步,语法是什么?是 export default async foo: function() alert("foo!") 【参考方案4】:
选项 1
跨组件共享方法的一种方法是使用 mixin。这是一个包含selectProduct
方法的cartMixin
:
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
组件并将其扩展以创建您的Fruit
和Vegetable
组件。然后,您可以将常用功能放入基本组件中。
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.
鉴于您的水果和蔬菜模板非常相似,您或许可以更进一步地利用这个想法,并使用基础组件中的通用模板。
【讨论】:
我认为选项 1 是这里最“正确”的 vue 答案......虽然 Mixins 有一个不幸的名字 imo 不清楚。也许应该称为 AddIns、AddOns、Extenders、ShareMes 等。【参考方案5】:您可以将该方法放在您的根 Vue 实例中,然后在选择蔬菜或选择水果时从子实例调度一个事件。事件在它们的父组件上寻找一个处理程序,如果他们没有找到一个事件处理程序,他们会继续往上走,直到找到为止。所以在你的根实例上:
events:
'choose-fruit':function(fruit)
//handle the choosing of fruit
然后在子实例上:
selectFruit: function(product)
this.$dispatch('choose-fruit', product);
【讨论】:
请注意,$dispatch
在 Vue 2.0 中已被删除,尽管您可以使用 $emit
、$on
和 $off
来替换它:vuejs.org/v2/guide/…以上是关于如何在 Vue.js 中的组件之间共享方法?的主要内容,如果未能解决你的问题,请参考以下文章
如何在多个 Angular 2 项目之间共享一个 Angular 2 组件?
如何在 Monorepo 中的 VueJS 项目之间共享组件