【小探索】在vue2中使用extends实现组件继承

4,138 阅读3分钟

在一些项目中,我们已经有了组件A,它能够完成我们业务90%以上的需求。但是在一些特殊情况下,我们还需要一些特殊的需求,比如正常情况下:

componentAHandler(val) {
    console.log(val)
}

这时,你在另一项工作中也需要组件A,但是有个小地方需要处理一下:需要在打印出val之前,先进行一定的处理,然后再将其打印出来,例如:

componentAHandler(val) {
    this.processByOther(val)
    console.log(val)
}

此时,直接在组件A中添加processByOther方法或者通过入参的形式将方法传入进去是不合适的,因为我们希望:当一个组件稳定工作时,尽量不要修改该正常工作的组件,否则视为对基本组件A的污染。 那么在此情况下,我们自然而然的想到了继承,比如类继承。

class A {
    processUnderA() {console.log('zis is from A')}
}
class B extends A {
    processUnderA() {console.log('zis is from B')}
    processUnderB() {console.log('zis is form B')}
}

在这种情况下,对新创建的实例B,我们不仅可以使用processUnderB,还可以重写类A中已经有的方法:processsUnderA()。

所以,我们希望能有个新的组件B,它是继承自组件A的,同时还能够重写原来的componentAHandler方法来适应我们新的业务需求。

在Vue2中,extends关键字可以帮助我们实现这个功能,但在介绍这个之前,我想讲讲我自己的解决方法。

在JS中,万物基于对象(Object)

我原本不是前端,是从C#转过来的,C#中基类也是Object,但是C#中的Object是个类。所以说,C#是基于类而创建的,包括类的继承、类方法的override,类的实例化,静态类,动态类等等。

但看了《JS高级编程设计》这本书后,发现JS基本是靠对象堆砌起来的,包括衍生出来的String、Number他们的prototype里都有valueOf,你会发现valueOf是来自于Object的prototype。而同时,你也会发现VueComponent其实就是一个对象。

**那么既然知道了VueComponent是一个对象,那直接使用对象的继承不就好了。**我最早的解决方案是使用Object.assign()方法,把我新写的componentAHandler覆盖掉原来A组件的componentAHandler,或者是使用Object.create(A)来创建一个新的对象B,然后使用B.methods.componentAHandler的方法来重写该方法,然后导入新的对象B。

结果嘛,这两种方法我都没有试验成功(但我觉得原理没错,只是可能我的语法,或者vue的一些限制导致试验失败,比如在重写componentAHandler方法时,this会指向这个方法而不是这个对象B,从而导致其他错误。)

后来,我阅读了vue文档并知晓extends

使用extends的话,那就简单的多了。具体写法为:

import A from './A'
const B = {
    name: 'B',
    extends: A,
    methods: {
        componentAHandler(val) {
            this.processByOther(val)
            console.log(val)
        },
        processByOther(val) {
            console.log('zis info is from B')
        }
    }
}

上述方法就可以生成一个继承自组件A同时还能重写A中componentAHandler方法的新的组件B:既能使用已经造好的轮子,还能根据新的业务需求进行灵活改变。

另外,如果你想在组件C中使用继承自A的组件B,同时该组件B还使用了组件C的方法,那么可以这么写:

import A from './A'
const B = {
    name: 'B',
    extends: A,
    methods: {
        componentAHandler(val) {
            C.processByOther(val)
            console.log(val)
        }
    }
}
const C = {
    name 'C',
    data() {},
    ...,
    components: {
        componentB: B
    },
    methods: {
        processByC(val) {
            console.log('zis info is from C')
        }
    }
}
export default C

使用extends碰到的问题

我们假设组件A中使用了table组件,该组件有个requestData方法,该方法是请求网页数据。

requestData() {
    return new Promise((resolve, reject) => {
        request(params).then(res => {
            if(res.code === 200) {
                resolve(res.data)
            } else {
                
            }
        })
    }).catch(error) {
        console.log('error Info: ', error)
    }
}

而组件A的使用方式为:

methods: {
    requestTableData() {
        this.refs['table'].requestData()
    }
}

而组件B中重写的方法为:

methods: {
    requestTableData() {
        this.refs['table'].requestData().then(result => C.drawTheData(result))
    }
}

然后我就发现在table组件成功获取到data并且其promise为fulfilled状态,但在组件B中获取到的Promise一直是pending状态。

还希望有大佬知道并解释下。