Angular 2+并实施Leaflet地图(Open Street Map)

时间:2017-05-05 09:14:35

标签: angular leaflet

我想在我的网页上实现(ASP.NET Core SPA模板(使用Angular 2+ - 使用yeoman生成)Leaflet地图。

所以我在leafletjs.com上搜索教程

首先测试这个例子(它可以作为独立工作):

function(p1,p2..,pk)

我尝试将它与Angular 2+一起使用并创建一些简单的组件,如<html> <head> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.3/dist/leaflet.css" integrity="sha512-07I2e+7D8p6he1SIM+1twR5TIrhUQn9+I6yjqD53JQjFiMf8EtC93ty0/5vJTZGF8aAocvHYNEDJajGdNx1IsQ==" crossorigin=""/> <script src="https://unpkg.com/leaflet@1.0.3/dist/leaflet.js" integrity="sha512-A7vV8IFfih/D732iSSKi20u/ooOfj/AGehOKq0f4vLT1Zr2Y+RX7C+w8A1gaSasGtRUZpF/NZgzSAu4/Gc41Lg==" crossorigin=""></script> <style> #map { height: 180px; } </style> </head> <body> <div id="map"></div> <script> var map = L.map('map').setView([50.0817444,19.9253805], 13); L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', { attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' }).addTo(map); L.marker([50.0817444,19.9253805]).addTo(map) .bindPopup('A pretty CSS3 popup.<br> Easily customizable.') .openPopup(); </script> </body> </html> 我已经完成了以下步骤:

  1. 将依赖项添加到 package.json
  2. LeafletMapComponent.
    1. webpack.config.vendor.js
    2. 中添加传单
      "dependencies": {
          ...
         "leaflet":"^1.0.3"
          ...
      }
      "devDependencies": {
          ...
          "@types/geojson":"^1.0.2",
          "@types/leaflet":"^1.0.60"
      }
      
      1. 然后我用这么简单的代码创建了新的组件
      2. entry: {
                    vendor: [
                        '@angular/common',
                        '@angular/compiler',
                        '@angular/core',
                        '@angular/http',
                        '@angular/platform-browser',
                        '@angular/platform-browser-dynamic',
                        '@angular/router',
                        '@angular/platform-server',
                        'angular2-universal',
                        'angular2-universal-polyfills',
                        'bootstrap',
                        'bootstrap/dist/css/bootstrap.css',
                        'es6-shim',
                        'es6-promise',
                        'event-source-polyfill',
                        'jquery',
                        'zone.js',
                        'leaflet',
                    ]
                },
                output: {
                    publicPath: '/dist/',
                    filename: '[name].js',
                    library: '[name]_[hash]'
                },
        
        1. 当然我也有#leafletMap div和样式应用
        2. import {Component, OnInit} from '@angular/core'; 
            import * as L from 'leaflet';
          
          @Component({
              selector: 'leaflet-map',
              templateUrl: 'leaflet-map.component.html',
              styleUrls: ['leaflet-map.component.css', '../../../..//node_modules/leaflet/dist/leaflet.css'], }) export class
           LeafletMapComponent implements OnInit { 
          
              ngAfterViewInit() {
                      L.map('leafletMap').setView([50.0817444,19.9253805], 13);
              }
          
              ngOnInit() {  
          
              }    
            }
          
          1. 我已经运行了这样的应用程序:
          2.  #leafletMap { 
                 height: 400px; 
                 width: 600px;
              }
            
              <div id="leafletMap"></div>
            

            但我仍然收到这样的错误:

              

            失败:Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware [0]         发生未处理的异常:调用节点模块失败并显示错误:由于错误,预渲染失败:ReferenceError:   窗口未定义

1 个答案:

答案 0 :(得分:3)

您似乎在ASP.NET Core Angular启动器中使用Angular Universal(服务器端渲染)。在服务器端,没有定义窗口对象(LeafletMap可能在内部使用)。

有两种选择:

  1. 通过从Views / Home / Index.cshtml中的元素中删除asp-prerender-module属性来禁用项目中的服务器端呈现。
  2. 通过在代码中实现专用执行分支,将LeafletMap的使用限制在客户端部分(参见Life cycle
  3. 修改

    根据选项2,您必须注意在加载第三方库(如jquery或LeafletMap)时没有灵丹妙药。只是import语句本身(如果没有在代码优化中删除)可能会导致服务器端的奇怪副作用。 A&#34;可能&#34;实践(因为没有&#34;最佳&#34;实践)可以实现有条件地加载这些库的服务。

    import { Injectable, Inject, PLATFORM_ID, Component, OnInit } from '@angular/core';
    import { isPlatformBrowser, isPlatformServer } from '@angular/common';
    
    @Injectable()
    export class LegacyService {
        private _L : any;
        private _jquery : any;
    
        public constructor(@Inject(PLATFORM_ID) private _platformId: Object) {
            this._init();
        }
    
        public getJquery() {
            return this._safeGet(() => this._jquery);
        }
    
        public getL() {
            return this._safeGet(() => this._L);
        }
    
        private _init() {
            if(isPlatformBrowser(this._platformId)){
                this._requireLegacyResources();     
            }
        }
    
        private _requireLegacyResources() {
            this._jquery = require('jquery');
            this._L = require('leaflet');
        }
    
        private _safeGet(getCallcack : () => any) {
            if(isPlatformServer(this._platformId)){
                throw new Error ('invalid access to legacy component on server');
            }
    
            return getCallcack();
        }
    }
    

    在组件实现上,您还应该实现仅在客户端使用服务的条件分支:

    ngAfterViewInit() {
        if(isPlatformBrowser(this.platformId)){
          this._legacyService.getL().map('leafletMap').setView([50.0817444,19.9253805], 13);
        }
      }