首页 > 解决方案 > 使用 ES6 模块时,在 2 个网页之间共享非常相似的代码

问题描述

解释

我有 2 个使用不同入口点的应用程序/网页,我们分别调用它们app1app2,它们分别使用entry1.jsentry2.js。在这两个应用程序中,我都使用了非常通用的模块,它们存储在一个shared文件夹中。

我在我的项目中使用 OpenLayers,其概念是我有一个“第 1 页”和一个“第 2 页”,它们有很多共同点(地图、相同的特征样式、一些图层、相同的数据存储逻辑),但也很多不同的东西(一些层次,商店的内容,我使用商店做事的方式)。

我目前使用的文件结构如下所示:

entry1.js
entry2.js
app1/
    map.js
    [...]
app2/
    map.js
    [...]
shared/
    pointsLayer.js
    store.js
    styles.js
    [...]

在此示例中,pointsLayer应用程序之间使用完全相同的逻辑,但我获取点样式的方式不同。

entry1.js

import './app1/map';
import { togglePoint } from './shared/pointsLayer';

// pointsLayer is used here to bind the togglePoint function to the DOM event
$('.point-checkbox').change(function() {
    let $this = $(this);
    let eid = $this.data('eid');
    togglePoint(eid, $this.is(':checked'));
});

entry2.js

import './app2/map';
import { togglePoint } from './shared/pointsLayer';

// pointsLayer is used here to bind the togglePoint function to the DOM event
$('.another-point-checkbox').change(function() {
    // Bind the function to another DOM element than app1
    // [...]
    togglePoint(eid, $this.is(':checked'));
});

app1/map.jsapp2/map.js

// The files looks the same because I only extracted what's relevant for you
import { Map, View } from 'ol';
import pointLayer, { updatePoint } from '../shared/pointsLayer';

const map = new Map({
    layers: [pointLayer],
    target: 'map',
    view: new View([/*...*/])
});

map.addEventListener /* ... */
// Here, on a specific map event, I call updatePoint(eid, position)

shared/store.js

// Here I initialise some data that come from the Global Scope
// This module allows me to share data between ES modules
export default {
    a: window.a,
    b: window.b
};
// In app1, a will be set, b will be undefined
// In app2, a will be undefined, b will be set
// a and b contain information used to set the color of a Feature Style
// That's part of the problem I'm trying to resolve

shared/styles.js

import { Circle, Fill, Stroke, Style, Text } from 'ol/style';
import Store from './store';

function getElementColor(eid) {
    // Here
    // I need to access Store.a[eid].color when it's app1
    // Or access Store.b[eid].color when it's app2
}

function getPointStyle(eid) {
    return new Style({
        image: new Circle({
            fill: new Fill({
                color: getElementColor(eid)
            }),
            radius: 6,
            stroke: new Stroke({
                color: '#000',
                width: 2
            })
        })
    });
}

export { getPointStyle };

shared/pointsLayer.js

import { Feature } from 'ol';
import { Point } from 'ol/geom';
import { Vector as VectorSource } from 'ol/source';
import { Vector as VectorLayer } from 'ol/layer';

import Styles from './styles';

const points = {};
const source = new VectorSource();
const layer = new VectorLayer({
    source: source,
    style: new Style(null)
});

export function updatePoint(eid, position) {
    // Do stuff to update a point using the provided eid and position
    // I call the getPointStyle function from 'shared/styles.js' here
    // [...]
    points[eid].setStyle(Styles.getPointStyle(eid));
    // [...]
}

export function togglePoint(eid, visible) {
    // Do stuff to toggle a point visible or not
    // Also uses Styles.getPointStyle(eid) to set the corresponding style
}

export default layer;

问题

我的问题是shared/pointsLayer文件中的所有内容都可以在两个应用程序中使用,但是该模块依赖于另一个模块,该模块在其中做不同的事情并将app1a应用于a (请参阅 中的函数)。app2colorStylePointgetElementColorshared/styles.js

我想我可以让getElementColor函数做类似的事情,if (Store.a === undefined) { // I am in app2 } [...]但我很确定这不是处理这个问题的好方法。

我想到了另外两个想法,但我也不满意。

理念一

map.js

import { Map, View } from 'ol';
import pointLayer, { updatePoint } from '../shared/pointsLayer';

// HERE
import Store from '../shared/store';
Store.app = "app1"; // Or "app2"

const map = new Map({
    layers: [pointLayer],
    target: 'map',
    view: new View([/*...*/])
});

map.addEventListener /* ... */
// Here, on a specific map event, I call updatePoint(eid, position)

shared/styles.js

// [...]
function getElementColor(eid) {
    if (Store.app == 'app1') {
        // Access Store.a[eid].color
    } else {
        // Access Store.b[eid].color
    }
}
// [...]

想法 2

shared/pointsLayer.js

import { Feature } from 'ol';
import { Point } from 'ol/geom';
import { Vector as VectorSource } from 'ol/source';
import { Vector as VectorLayer } from 'ol/layer';

const points = {};
const source = new VectorSource();
const layer = new VectorLayer({
    source: source,
    style: new Style(null)
});

// HERE
let getPointColor = () => {};
export function setGetPointColor(fct) {
    getPointColor = fct;
}
function getPointStyle(eid) {
    return new Style({
        image: new Circle({
            fill: new Fill({
                color: getPointColor(eid)
            }),
            radius: 6,
            stroke: new Stroke({
                color: '#000',
                width: 2
            })
        })
    });
}
//

export function updatePoint(eid, position) {
    // [...]
    points[eid].setStyle(getPointStyle(eid));
    // [...]
}

export function togglePoint(eid, visible) {
    // Also uses getPointStyle(eid) to set the corresponding style
}

export default layer;

app1/map.jsapp2/map.js

import { Map, View } from 'ol';
import pointLayer, { updatePoint, setGetPointColor } from '../shared/pointsLayer';

// HERE
setGetPointColor(function(eid) {
    let element = Store.a[eid]; // Or Store.b[eid]
    if (!element) {
        // Log, error, whatever...
        return '#000';
    }
    return element.color;
});

const map = new Map({
    layers: [pointLayer],
    target: 'map',
    view: new View([/*...*/])
});

map.addEventListener /* ... */
// Here, on a specific map event, I call updatePoint(eid, position)

这些解决方案/想法对我来说都不合适,我是使用 ES6 的新手,我想也许我错过了一些重要的 ES 模块概念?
您的帮助将不胜感激。

标签: javascriptecmascript-6es6-modules

解决方案


推荐阅读