Vue.js继承:调用父方法

26

在Vue.js中是否可以使用方法重写(method overriding)?

var SomeClassA = Vue.extend({
  methods: {
    someFunction: function() {
      // ClassA some stuff
    }
  }
});

var SomeClassB = SomeClassA.extend({
  methods: {
    someFunction: function() {
      // CALL SomeClassA.someFunction
    }
  }
});

我想从ClassB的某个函数中调用ClassA的某个函数。这是否可能?

3个回答

21

不,Vue 不支持直接的继承模型。据我所知,你无法使用 A.extend 继承一个组件。Vue 的父子关系主要是通过 props 和 events 来实现的。

但是,有三种解决方案:

1. 通过 props 传递(父子)

var SomeComponentA = Vue.extend({
    methods: {
        someFunction: function () {
            // ClassA some stuff
        }
    }
});

var SomeComponentB = Vue.extend({
   props: [ 'someFunctionParent' ],
   methods: {
       someFunction: function () {
           // Do your stuff
           this.someFunctionParent();
       }
   }
});

并且在 SomeComponentA 的模板中:

<some-component-b someFunctionParent="someFunction"></some-component-b>

2. 混合(Mixins)

如果您希望在其他地方使用这个常见的功能,使用混合可能更符合习惯:

var mixin = {
    methods: {
        someFunction: function() {
            // ...
        }
    }
};

var SomeComponentA = Vue.extend({
    mixins: [ mixin ],
    methods: {
    }
});

var SomeComponentB = Vue.extend({
   methods: {
       someFunctionExtended: function () {
           // Do your stuff
           this.someFunction();
       }
   }
});

3. 调用父组件的属性(父子级,不太美观)

// In someComponentB's 'someFunction':
this.$parent.$options.methods.someFunction(...);

我真的不建议使用#3,只是为了参考而包含在内。其他两个对于vue来说更符合习惯(继承通常并没有太多意义,因为componentA并不是一个抽象类,而是DOM中的父组件,其职责与componentB不同)。如果您考虑组件的责任而不是可扩展性,可能会有所帮助。 - nils
你不能使用#3,因为它不起作用 :) 我不能同意"since componentA is not an abstract class but a parent component in the DOM with different responsibilities than componentB",因为我错命名了类,应该是SomeAbstractComponentA。我从Ember转到Vue,我认为组件中的继承并没有什么问题。 - MyFantasy512
当然,这个示例只是为了证明第三个选项不起作用。我在模板中实例化组件。 - MyFantasy512
放下组件职责,你不能说像重写方法这样简单的概念对于任何框架来说都是太过抽象的扩展性。 - MyFantasy512
好的,选项3只适用于组件之间存在父子关系的情况。正如我所说,你不能使用 A.extend。如果你想从一个独立的组件(不在父子关系中)进行扩展,目前唯一的选择是 mixins。实际方法覆盖仅在 JavaScript 的 ES6 类中引入,它不是该语言的本地功能。 - nils
显示剩余6条评论

14

如果有人对JustWorksTM解决方案感兴趣:

var FooComponent = {
  template: '<button @click="fooMethod()" v-text="buttonLabel"></button>',

  data: function () {
   return {
     foo: 1,
     bar: 'lorem',
     buttonLabel: 'Click me',
   }
  },

  methods: {
    fooMethod: function () {
      alert('called from FooComponent');
    },
    
    barMethod: function () {
      alert('called from FooComponent');
    },
  }
}

var FooComponentSpecialised = {
  extends: FooComponent,

  data: function () {
   return {
     buttonLabel: 'Specialised click me',
     zar: 'ipsum',
   }
  },

  methods: {
    fooMethod: function () {
      FooComponent.methods.fooMethod.call(this);
    
      alert('called from FooComponentSpecialised');
    },
  }
}

jsfiddle: https://jsfiddle.net/7b3tx0aw/2/


更多信息:

  1. 此解决方案适用于无法使用TypeScript的开发人员(我认为TypeScript允许将vue组件定义为类,从而允许完整的继承功能集)。
  2. 有关该解决方案的进一步阐述(原因和方法):https://github.com/vuejs/vue/issues/2977
  3. 考虑到这里没有使用任何高深技术(调用带替换的this指针的匿名函数对于任何像样的js开发人员来说都不应该是什么魔术), 这并不算太丑陋。

如何使用Function.prototype.call()

参考https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call

示例代码:

function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Product.call(this, name, price);
  this.category = 'food';
}

console.log(new Food('cheese', 5).name);
// expected output: "cheese"

我不知道自此帖子以来是否有所更改,但我需要使用FooComponent.options.methods.fooMethod.call(this); - Hamish

3

如果有人询问解决方案,这是我的方法,并且运行良好:

var SomeClassA = {
    methods: {
        someFunction: function () {
            this.defaultSomeFunction();
        },
        // defaultSomeFunction acts like parent.someFunction() so call it in inheritance
        defaultSomeFunction: function () {
            // ClassA some stuff
        },
    },
};

var SomeClassB = {
    extends: SomeClassA,
    methods: {
        someFunction: function () {
            // Replace the wanted SomeClassA::someFunction()
            this.defaultSomeFunction();
            // Add custom code here
        },
    },
};

使用 extends 替代 Vue.extends(),详见https://v2.vuejs.org/v2/api/#extends


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接