velte 是构建 Web 应用程序的一种新方法,核心思想在于通过静态编译减少框架运行时的代码量,它可以像React和VUE一样开发,但却没有虚拟DOM,可以将代码编译为体积小、不依赖于框架的JS代码。使用Svelte开发的无框架依赖的Web Components,可以在各个框架间复用。同时,Svelte的开发方式也不像写pure js那样繁琐。本文将结合ol实现跨框架组件复用。
创建Svelte template工程。 svelte 官方提供了template 工程(https://github.com/sveltejs/component-template),只要clone或者下载项目即可。
修改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"
}
}
调整目录组织,调整后的目录组织如下:
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()
],
};
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';
执行命令npm run dev
或npm 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>
运行后效果如: