leaflet之扩展leaflet类,定制功能
简介:leaflet提供了操作地图的基本类,提供了扩展功能。用户可以自由个性化定制扩展功能,开发自己的插件。
扩展leaflet
Leaflet有几百个插件。这些扩展了Leaflet的功能:有时以通用方式,有时以特定于用例的方式。
有这么多插件的部分原因是Leaflet很容易扩展。本教程将介绍最常用的方法。
请注意,本教程需要已经掌握了以下基础:
- JavaScript
- DOM处理
- 面向对象的编程(理解类,实例,继承,方法和属性等概念)
leaflet架构
让我们看一下Leaflet 1.0.0的简化UML类图。有超过60个JavaScript类,所以图表有点大。幸运的是,我们可以制作一个可缩放的图像L.ImageOverlay:
单独查看此示例。 |
从技术角度来看,Leaflet可以以不同的方式扩展:
- 最常见的:创建一个新的子类L.Layer,L.Handler或L.Control与L.Class.extend()
- 移动/缩放地图时图层会移动
- 处理程序是不可见的并解释浏览器事件
- 控件是固定的界面元素
- 在现有类中包含更多功能 L.Class.include()
- 添加新方法和选项
- 改变一些方法
- 使用addInitHook运行额外的构造函数代码。
- 更改现有类的部分(替换类方法的工作方式)L.Class.include()。
本教程介绍了仅在Leaflet 1.0.0中可用的一些类和方法。如果您正在为以前的版本开发插件,请谨慎使用。
L.Class
JavaScript是一种奇怪的语言。它不是一种面向对象的语言,而是一种面向原型的语言。这使得JavaScript在历史上难以在术语的经典OOP含义中使用类继承。
Leaflet通过使用来解决这个问题L.Class,从而简化了类的继承。
尽管现代JavaScript可以使用ES6类,但Leaflet并不是围绕它们设计的。
L.Class.extend()
要在Leaflet中创建任何子类,请使用该.extend()方法。这接受一个参数:具有键值对的普通对象,每个键是属性或方法的名称,每个值是属性的初始值,或方法的实现:
var MyDemoClass = L.Class.extend({ // A property with initial value = 42 myDemoProperty: 42, // A method myDemoMethod: function() { return this.myDemoProperty; } }); var myDemoInstance = new MyDemoClass(); // This will output "42" to the development console console.log( myDemoInstance.myDemoMethod() );
命名类,方法和属性时,请遵循以下约定:
- 功能,方法,属性和工厂名称应该在lowerCamelCase。
- 班级名称应该在UpperCamelCase。
- 私有属性和方法以下划线(_)开头。这不会使它们变得私密,只是建议开发人员不要直接使用它们。
L.Class.include()
如果已定义类,则可以重新定义现有属性/方法,或者可以使用.include()以下方法添加新属性/方法:
MyDemoClass.include({ // Adding a new property to the class _myPrivateProperty: 78, // Redefining a method myDemoMethod: function() { return this._myPrivateProperty; } }); var mySecondDemoInstance = new MyDemoClass(); // This will output "78" console.log( mySecondDemoInstance.myDemoMethod() ); // However, properties and methods from before still exist // This will output "42" console.log( mySecondDemoInstance.myDemoProperty );
L.Class.initialize()
在OOP中,类具有构造函数方法。在Leaflet中L.Class,构造函数方法总是被命名initialize。
如果你的类有一些特定的options,那么L.setOptions()在构造函数中初始化它们是个好主意。此实用程序函数将提供的选项与类的默认选项合并。
var MyBoxClass = L.Class.extend({ options: { width: 1, height: 1 }, initialize: function(name, options) { this.name = name; L.setOptions(this, options); } }); var instance = new MyBoxClass('Red', {width: 10}); console.log(instance.name); // Outputs "Red" console.log(instance.options.width); // Outputs "10" console.log(instance.options.height); // Outputs "1", the default
Leaflet options以特殊方式处理属性:父类可用的选项将由子类继承:
var MyCubeClass = MyBoxClass.extend({ options: { depth: 1 } }); var instance = new MyCubeClass('Blue'); console.log(instance.options.width); // Outputs "1", parent class default console.log(instance.options.height); // Outputs "1", parent class default console.log(instance.options.depth); // Outputs "1"
子类运行父的构造函数,然后运行自己的构造函数是很常见的。在传单中,这是使用L.Class.addInitHook()。此方法可用于“挂钩”在类’之后运行的初始化函数,initialize()例如:
MyBoxClass.addInitHook(function(){ this._area = this.options.width * this.options.length; });
这将在initialize()调用之后运行(调用setOptions())。这意味着this.options存在并且在init钩子运行时有效。
addInitHook 有一个替代语法,它使用方法名称并可以填充方法参数:
MyCubeClass.include({ _calculateVolume: function(arg1, arg2) { this._volume = this.options.width * this.options.length * this.options.depth; } }); MyCubeClass.addInitHook('_calculateVolume', argValue1, argValue2);
父类的方法
调用父类的方法是通过到达父类的原型并使用来实现的Function.call(…)。例如,可以在以下代码中看到L.FeatureGroup:
L.FeatureGroup = L.LayerGroup.extend({ addLayer: function (layer) { … L.LayerGroup.prototype.addLayer.call(this, layer); }, removeLayer: function (layer) { … L.LayerGroup.prototype.removeLayer.call(this, layer); }, … });
调用父的构造函数是以类似的方式完成的,而是使用ParentClass.prototype.initialize.call(this, …)。
工厂
大多数Leaflet类具有相应的工厂功能。工厂函数与类具有相同的名称,但lowerCamelCase代替UpperCamelCase:
function myBoxClass(name, options) { return new MyBoxClass(name, options); }
命名规范
为Leaflet插件命名类时,请遵循以下命名约定:
- 永远不要在插件中公开全局变量。
- 如果您有一个新类,请将其直接放在L命名空间(L.MyPlugin)中。
- 如果继承其中一个现有类,请将其设为子属性(L.TileLayer.Banana)。