zl程序教程

您现在的位置是:首页 >  Javascript

当前栏目

sveltejs结合ol实现跨框架组件复用

2023-03-07 09:06:08 时间

概述

velte 是构建 Web 应用程序的一种新方法,核心思想在于通过静态编译减少框架运行时的代码量,它可以像React和VUE一样开发,但却没有虚拟DOM,可以将代码编译为体积小、不依赖于框架的JS代码。使用Svelte开发的无框架依赖的Web Components,可以在各个框架间复用。同时,Svelte的开发方式也不像写pure js那样繁琐。本文将结合ol实现跨框架组件复用。

实现

1. 创建工程

创建Svelte template工程。 svelte 官方提供了template 工程(https://github.com/sveltejs/component-template),只要clone或者下载项目即可。

2. 添加依赖

修改package.json文件,修改后执行命令npm i安装依赖。修改后的文件内容为:

{
  "name": "svelte-component",
  "svelte": "src/index.js",
  "module.prod": "dist/index.min.mjs",
  "main.prod": "dist/index.min.js",
  "module.dev": "dist/index.mjs",
  "main.dev": "dist/index.js",
  "scripts": {
    "dev": "rollup -wc ./config/rollup.config.dev.js",
    "build": "rollup -c ./config/rollup.config.js",
    "prepublishOnly": "npm run build",
    "tree": "treee -I \"node_modules\""
  },
  "devDependencies": {
    "@babel/core": "^7.20.12",
    "@babel/preset-env": "^7.20.2",
    "@rollup/plugin-node-resolve": "^15.0.1",
    "autoprefixer": "^10.4.13",
    "node-sass": "^8.0.0",
    "postcss": "^8.4.21",
    "rollup": "^2.0.0",
    "rollup-plugin-babel": "^4.4.0",
    "rollup-plugin-commonjs": "^10.1.0",
    "rollup-plugin-node-resolve": "^5.2.0",
    "rollup-plugin-svelte": "^7.0.0",
    "rollup-plugin-uglify": "^6.0.4",
    "rollup-obfuscator": "^3.0.1",
    "rollup-plugin-livereload": "^2.0.5",
    "rollup-plugin-serve": "^1.1.0",
    "sass": "^1.57.1",
    "svelte": "^3.5.0",
    "svelte-preprocess": "^5.0.1"
  },
  "keywords": [
    "svelte"
  ],
  "files": [
    "src",
    "dist"
  ],
  "dependencies": {
    "ol": "^7.2.2"
  }
}

3. 调整目录组织,添加配置

调整目录组织,调整后的目录组织如下:

sveltejs-component-template
├── README.md 
├── config
│   ├── rollup.config.dev.js  // 开发配置文件
│   └── rollup.config.js  // 编译配置文件
├── dist //  编译及调试文件
│   ├── index.html  // 调试文件
│   ├── index.js
│   ├── index.min.js
│   ├── index.min.mjs
│   └── index.mjs
├── package.json
└── src
    ├── ComponentMap.svelte
    └── index.js

rollup.config.dev.js文件内容如下:

import svelte from 'rollup-plugin-svelte'
import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import babel from 'rollup-plugin-babel'
import sveltePreprocess from 'svelte-preprocess';
import serve from 'rollup-plugin-serve'
import livereload from 'rollup-plugin-livereload'
import pkg from '../package.json';

const name = pkg.name
  .replace(/^(@\S+\/)?(svelte-)?(\S+)/, '$3')
  .replace(/^\w/, m => m.toUpperCase())
  .replace(/-\w/g, m => m[1].toUpperCase());

const preprocess = sveltePreprocess({
  scss: {
    includePaths: ['src'],
  },
  postcss: {
    plugins: [require('autoprefixer')],
  },
});

export default {
  input: 'src/index.js',
  output: [
    { file: pkg['module.dev'], 'format': 'es' },
    { file: pkg['main.dev'], 'format': 'umd', name, sourcemap: false }
  ],
  plugins: [
    serve({
      contentBase: 'dist', // 服务器启动的文件夹,默认是项目根目录
      port: 18080 // 端口号
    }),
    livereload('dist'), // 监听dist目录
    babel({
      babelrc: false,
      exclude: "node_modules/**",
      presets: [
        [
          '@babel/preset-env',
          {
            loose: true,
            // No need for babel to resolve modules
            modules: false,
            targets: {
              // ! Very important. Target es6+
              esmodules: true,
            },
          },
        ],
      ]
    }),
    svelte({
      preprocess: preprocess,
      compilerOptions: {
        customElement: true
      }
    }),
    //(resolve要放在commonjs之前)
    resolve(),
    commonjs({
      include: 'node_modules/**'
    })
  ],
};

rollup.config.js文件内容如下:

import svelte from 'rollup-plugin-svelte'
import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import babel from 'rollup-plugin-babel'
import { uglify } from 'rollup-plugin-uglify'
import { obfuscator } from 'rollup-obfuscator';
import sveltePreprocess from 'svelte-preprocess';
import pkg from '../package.json';

const name = pkg.name
  .replace(/^(@\S+\/)?(svelte-)?(\S+)/, '$3')
  .replace(/^\w/, m => m.toUpperCase())
  .replace(/-\w/g, m => m[1].toUpperCase());

const preprocess = sveltePreprocess({
  scss: {
    includePaths: ['src'],
  },
  postcss: {
    plugins: [require('autoprefixer')],
  },
});

export default {
  input: 'src/index.js',
  output: [
    { file: pkg['module.prod'], 'format': 'es' },
    { file: pkg['main.prod'], 'format': 'umd', name, sourcemap: false }
  ],
  plugins: [
    babel({
      babelrc: false,
      exclude: "node_modules/**",
      presets: [
        [
          '@babel/preset-env',
          {
            loose: true,
            // No need for babel to resolve modules
            modules: false,
            targets: {
              // ! Very important. Target es6+
              esmodules: true,
            },
          },
        ],
      ]
    }),
    svelte({
      preprocess: preprocess,
      compilerOptions: {
        customElement: true
      }
    }),
    //(resolve要放在commonjs之前)
    resolve(),
    commonjs({
      include: 'node_modules/**'
    }),
    obfuscator(),
    uglify()
  ],
};

4. 组件编写

ComponentMap.svelte文件的内容如下:

<svelte:options tag="ol-map" />

<div bind:this={mapDom} class="map">
</div>

<script>
    import { createEventDispatcher, onMount } from 'svelte';
    import Map from 'ol/Map.js'
    import XYZSource from 'ol/source/XYZ.js'
    import TileLayer from 'ol/layer/Tile.js'
    import View from 'ol/View.js'
    import { fromLonLat } from 'ol/proj'

    export let center = '0,0';

    let map = null
    let mapDom;

    // 监听变化
    $: valueChanged(center);
    function valueChanged(newValue) {
        if(map){
            map.setCenter(getCenter(newValue))
        }
    }

    // 事件
    const dispatch = createEventDispatcher();
    function dispatchEvent(name, e) {
        // dispatch(name, e);
        const event = new CustomEvent(name, {
            detail: e,
            bubbles: true,
            cancelable: true,
            composed: true
        });
        mapDom.dispatchEvent(event);
    }

    function getCenter(center) {
        return center.split(',').map(Number)
    }
    // 生命周期函数
    onMount(() => {
        map = new Map({
            target: mapDom,
            layers: [
                new TileLayer({
                    source: new XYZSource({
                        url: 'https://gac-geo.googlecnapps.cn/maps/vt?lyrs=m&x={x}&y={y}&z={z}'
                    })
                })
            ],
            view: new View({
                center: fromLonLat(getCenter(center)),
                zoom: 4
            })
        });
        map.on('zoomend', e => {
            dispatchEvent("zoomend", map.getZoom());
        });
    });
</script>

<style lang="scss">
  .map {
    width: 100%;
    height: 100%;
    overflow: hidden;
    position: relative;
  }
</style>

index.js文件的内容如下:

export { default as default } from './ComponentMap.svelte';

5. 打包编译

执行命令npm run devnpm run build进行开发调试和编译打包。其中index.html为开发时调试文件,其内容为:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Title</title>
  <script src="./index.js"></script>
  <style>
    html, body {
      height: 100%;
      width: 100%;
      margin: 0;
      padding: 0;
      overflow: hidden;
    }
    .map {
      /*height: 500px;*/
      /*width: 500px;*/
      height: 100%;
      width: 100%;
    }
  </style>
</head>
<body>
<div class="map">
  <ol-map center="113.940159,22.524729"></ol-map>
</div>
<script>
  const olMap = document.querySelector("ol-map")
  olMap.addEventListener("mapload", e => {
    console.log(e.detail)
  })
  olMap.addEventListener("zoomend", e => {
    console.log(e.detail)
  })
</script>
</body>
</html>

运行后效果如:

完整代码请移步:https://gitee.com/lzugis15/sveltejs-component-template.git