情景

比如我们可能在项目中会这样子写一个computed

selectGroup(): Model.Part[] {
    get() {
        return this.partSelection.selectGroup;
    },
    set(newValue: any) {
        const option = {
            selectGroup: newValue,
        }
        this.set_partData(option);
    }
},
name(): string {
    get() {
        return this.partSelection.name;
    },
    set(newValue: any) {
        const option = {
            age: newValue,
        }
        this.set_partData(option);
    }
},
age(): number {
    get() {
        return this.partSelection.age;
    },
    set(newValue: any) {
        const option = {
            age: newValue,
        }
        this.set_partData(option);
    }
},
color(): string {
    get() {
        return this.partSelection.color;
    },
    set(newValue: any) {
        const option = {
            color: newValue,
        }
        this.set_partData(option);
    }
},

这个时候你会发现其实写了很多相似的computed结构,这时候你想到了vuex的mapState

...mapState({
    partSelection: (state: any) => state.screen.editor.partSelection
}),

疑问

我能否也封装一个类似的函数,实现只需要传入一系列的值,自己构建成computed呢?如下:

...mapDataSource(['name', 'age', 'color']),

步骤分解

分解一下mapState的情况,

  1. 是对象展开符...,将一个对象混入computed中
  2. 可传入参数,可以是对象,可以是数组,其实就是你需要被进一步封装为computed属性的一系列值。
  3. 执行mapState函数并返回一个即将被结构的对象
  4. 被解构的对象中,每个属性应该和computed平时的写法是一样的,也就是如下
age(): number {
    return this.partSelection.age;
},
或
age(): number {
    get() {
        return this.partSelection.age;
    },
    set(newValue: any) {
        const option = {
            age: newValue,
        }
        this.set_partData(option);
    }
},

结论

每个属性都是方法的引用常量,且该方法中的上下文(this),都会是vue组件环境

所以根据上面的分析,很容易能够写出如下的封装:

// 类似mapState
const mapDataSource = (dataSourceProp: string[]) => {
    const computedProp: any = {};
    for (const prop of dataSourceProp) {
        computedProp[prop] = {
            get() {
                return (this.partData && this.partData[prop]) || '';
            },
            set(newValue: any) {
                const option = {
                    [prop]: newValue,
                }
                this.set_partData(option);
            }
        }
    }
    return computedProp;
};

优化

如果我们还有更复杂的情况,可能我们需要不同的数据源,可能我们需要对set方法中每个属性自定义内容,那么我们可以这么写:

...mapDataSource({
    sourceType: {
        // 需要从哪个对象上获取自身的属性
        carrier: 'partData',
        // 设置自身属性的简单适配器
        getOption: (newValue: any) => {
            return {
                sourceType: newValue,
            }
        },
    },
    valueType: {
        carrier: 'pointData',
        getOption: (newValue) => {
            return {
                valueType: newValue,
                mode: 'pointData',
            }
        },
    }
}),
// 类似mapState
const mapDataSource = (dataSourceProp: any) => {
    const computedProp: any = {};
    for (const [name, prop] of Object.entries(dataSourceProp)) {
        computedProp[name] = {
            get() {
                return (this[prop.carrier] && this[prop.carrier][name]) || '';
            },
            set(newValue: any) {
                const option = prop.getOption(newValue);
                this.set_partData(option);
            }
        }
    }
    return computedProp;
};

这样就能做到灵活的computed属性封装啦,类似mapState.


chuxiaoguo
334 声望44 粉丝

可视化数据开发工程师,自己独立开发了数据可视化网站[[链接]],欢迎star