使用vue js进行组件继承

Don*_*ash 14 vue.js

我正在尝试构建一个基础DataComponent,它将包含处理基本CRUD实体的许多其他组件所需的通用功能.
到目前为止我有

//main.js
import Vue from 'vue';

new Vue({
  el:'#app',
  components:{
    DataComponent,
    Quotation
  }
});
Run Code Online (Sandbox Code Playgroud)

//data-component.js
import Vue from 'vue';

export
default Vue.extend({

      data() {
          return {
            saved: false
          }
        },

        methods: {

          //This method will be used by all inheriting components to alert
          //the user regarding any changes which need to be saved.
          
          alertSave(entity, fields, intFields) {
              var changeCount = 0;
              fields.forEach(function(field) {
                
                var compareWith = this[field];
                
                //Here "this" need to refer to the child instance but it does not
                //how can I achieve?
                
                if ((compareWith || entity[field.camelToSnake()]) &&
                  entity[field.camelToSnake()] !== compareWith) {
                  changeCount++;
                }
              });
              intFields.forEach(function(field) {
                var compareWith = parseInt(this[field]);
                if ((compareWith || entity[field.camelToSnake()]) &&
                  entity[field.camelToSnake()] !== compareWith) {
                  changeCount++;
                }
              });
              vm.saved = changeCount <= 0;
            },
          
            //sanitizeValue method works as intended as it does not have any reference to "this"
          
            sanitizeValue(value) {
              if (value) {
                return String(value).trim();
              } else {
                return null;
              }
            },
          
            //In getDbData method also this needs to refer to the inheriting child instance
            //from where this method is called - how can I achieve it?
          
            getDbData(entity) {
              if (entity) {
                this.dbTextFields.forEach(function(field) {
                  this[field] = entity[field.camelToSnake()];
                });
                this.dbIntFields.forEach(function(field) {
                  this[field] = entity[field.camelToSnake()];
                });
                this.dbObjFields.forEach(function(field) {
                  this[field] = entity[field.camelToSnake()];
                });
                this.dbAppendedFields.forEach(function(field) {
                  this[field] = entity[field.camelToSnake()]
                });
                this.saved = true;

              }
            }
        });
Run Code Online (Sandbox Code Playgroud)

//quotation.js

import DataComponent from './data-component';

export default DataComponent.extend({
  
  data(){
    return{
      id:0,
      date:'',
      remarks:'',
      terms:'',
      quote:{},
      dbTextFields:['to', 'org', 'address', 'items', 'description', 'quoted_by'],
      dbIntFields:['quote_ref', 'quantity', 'amount', 'discount', 'total'],
      dbObjFields:['inquiry', 'booking']
    }
  },
  
  methods:{
    setDbData(){
      let entity = this.quote;
      this.getDbData(entity);
      
      //getDbData gives error as "this" in getDbData does not refer to this
      // child component and so this.dbTextFields becomes undefined.
      
    }
  }
  
});
Run Code Online (Sandbox Code Playgroud)

How to achieve method inheritance as I am trying to do? Is it possible in Vue.js?  
Run Code Online (Sandbox Code Playgroud)

编辑

如果我将data-component.js中方法的签名更改为,将继承组件("this")的实例作为vm传递,则它可以工作

//data-component.js
import Vue from 'vue';

export
default Vue.extend({

      data() {
          return {
            saved: false
          }
        },

        methods: {

          //This method will be used by all inheriting components to alert
          //the user regarding any changes which need to be saved.
          
          alertSave(entity, fields, intFields, vm) {
              var changeCount = 0;
              fields.forEach(function(field) {
                //var compareWith = this[field];
                var compareWith = vm[field];
                
                //Changed "this" to vm (passed as a parameter) 
                //how can I achieve?
                
                if ((compareWith || entity[field.camelToSnake()]) &&
                  entity[field.camelToSnake()] !== compareWith) {
                  changeCount++;
                }
              });
              intFields.forEach(function(field) {
                //var compareWith = parseInt(this[field]);
                var compareWith = parseInt(vm[field]);
                if ((compareWith || entity[field.camelToSnake()]) &&
                  entity[field.camelToSnake()] !== compareWith) {
                  changeCount++;
                }
              });
              vm.saved = changeCount <= 0;
            },
          
            //sanitizeValue method works as intended as it does not have any reference to "this"
          
            sanitizeValue(value) {
              if (value) {
                return String(value).trim();
              } else {
                return null;
              }
            },
          
            //In getDbData method also this needs to refer to the inheriting child instance
            //from where this method is called - how can I achieve it?
          
            getDbData(entity, vm) { //instance as "vm" parameter
            //change all this to vm
              if (entity) {
                vm.dbTextFields.forEach(function(field) {
                  vm[field] = entity[field.camelToSnake()];
                });
                vm.dbIntFields.forEach(function(field) {
                  vm[field] = entity[field.camelToSnake()];
                });
                vm.dbObjFields.forEach(function(field) {
                  vm[field] = entity[field.camelToSnake()];
                });
                vm.dbAppendedFields.forEach(function(field) {
                  vm[field] = entity[field.camelToSnake()]
                });
                vm.saved = true;

              }
            }
        });
Run Code Online (Sandbox Code Playgroud)

然后在继承组件中

//quotation.js

import DataComponent from './data-component';

export default DataComponent.extend({
  
  data(){
    return{
      id:0,
      date:'',
      remarks:'',
      terms:'',
      quote:{},
      dbTextFields:['to', 'org', 'address', 'items', 'description', 'quoted_by'],
      dbIntFields:['quote_ref', 'quantity', 'amount', 'discount', 'total'],
      dbObjFields:['inquiry', 'booking']
    }
  },
  
  methods:{
    setDbData(){
      let entity = this.quote;
      this.getDbData(entity, this);
      
      //passing this (instance) as a parameter
      
      
    }
  }
  
});
Run Code Online (Sandbox Code Playgroud)

将实例("this")作为vm传递给方法,它按预期工作.

我不确定这是否是最好的方法.但那肯定不是继承.
如何使用继承来实现我想要做的事情?

Jef*_*eff 16

您应该使用Mixins为多个(或所有)组件添加常用功能:https://vuejs.org/guide/mixins.html

这将允许您向任何或所有组件添加相同的功能,因此您可以自动添加this.foobar()到组件.

如果要在不污染组件命名空间的情况下为所有组件添加功能,可以使用自定义插件:https://vuejs.org/guide/plugins.html

这将允许您为所有组件添加服务,以便您可以在任何地方使用它this.$service.foobar().

如果您想使用CRUD功能,则应使用VueResource以下命令创建资源:https://github.com/vuejs/vue-resource/blob/master/docs/resource.md

这样您就可以使用FoobarService.create({foo: 'bar'})或轻松创建/删除/编辑资源FoobarService.delete({id: 1})

编辑:要创建一个插件,它看起来像这样:

var MyPlugin = {};

MyPlugin.install = function (Vue, options) {

  var service = {
    foo: function(bar) {
      //do something
    }
  }

  Vue.prototype.$service = service;
}

Vue.use(MyPlugin); //this runs the install function

//Then when you have any Vue instance
this.$service.foo(bar);
Run Code Online (Sandbox Code Playgroud)

  • 嗯..这是误解抽象类的“通用功能”的一个常见错误 - 这是面向对象编程的概念。用组合表达的关系是“具有&lt;组件&gt;”。这对于 80% 的情况都是有利的。然而,如果我们有一组相同的控件,只是有小部分不同,那么它可能是一个用继承来表达的“是一个&lt;组件&gt;”关系。一个很好的例子是具有命令式 API(如“showModal()”方法)的基本对话框以及从该基本对话框组件继承的对话框。 (2认同)