Javascript 在web组件中使用外部JS库

Javascript 在web组件中使用外部JS库,javascript,polymer,web-component,Javascript,Polymer,Web Component,我正在使用Polymer 2开发一个web组件,并希望使用第三方JavaScript库,该库不是专门为web组件设计的。据我所知,唯一的方法是在我的web组件的HTML文件中包含一个引用库的标记 我可以看到这样做的一些问题,并且想知道是否有任何方法可以解决这些问题,事实上,以这种方式包括第三方库是否被认为是不好的做法 外部库可以设置对页面上的其他组件可见的全局变量,从而允许web组件彼此断开,或者断开它们承载的页面。由于封装经常被吹捧为一个问题,这似乎是一个问题 外部库可能会执行DOM查询或更新

我正在使用Polymer 2开发一个web组件,并希望使用第三方JavaScript库,该库不是专门为web组件设计的。据我所知,唯一的方法是在我的web组件的HTML文件中包含一个引用库的
标记

我可以看到这样做的一些问题,并且想知道是否有任何方法可以解决这些问题,事实上,以这种方式包括第三方库是否被认为是不好的做法

  • 外部库可以设置对页面上的其他组件可见的全局变量,从而允许web组件彼此断开,或者断开它们承载的页面。由于封装经常被吹捧为一个问题,这似乎是一个问题

  • 外部库可能会执行DOM查询或更新,而这些查询或更新将无法访问正在使用它们的web组件的影子DOM,因此外部库可能根本无法工作,或者可能会再次更新托管页的DOM,从而破坏封装


  • 那么,我是否遗漏了什么,或者这是否意味着在web组件中包含外部库是一个非常糟糕的主意?如果是这样的话,这似乎是这项技术的一个巨大限制,因为我们无法利用现有的大量JS库。

    事实上,我昨天也不得不处理同样的问题,所以时机很好;)在我的例子中,第一个页面中的视图有两个部分,一个是单选按钮,由于业务需要,根据用户的单选按钮选择,带有google maps autocomplete的输入文本将被启用(或保持禁用)

    在这种情况下,在没有google maps库的情况下加载页面,然后在webcomponent完全呈现后动态加载gmaps代码,这将导致交互时间减少50%:)下面是我最后要做的

    注意:loadGoogleMaps()方法和initCalled变量声明在类之外,因此在webcomponent之外(我把它们放在import语句下面)。我还省略了示例中的大部分类代码,因为它与您的问题无关:)

    从'@polymer/lit element'导入{html};
    从“./page view element.js”导入{PageViewElement};
    从“./shared styles.js”导入{SharedStyles};
    导入“@vaadin/vaadin单选按钮/vaadin单选按钮.js”;
    导入“@vaadin/vaadin单选按钮/vaadin radio group.js”;
    从“/my icons.js”导入{spinner};
    让我们来打电话;
    函数loadGoogleMaps(){
    //仅在以前未加载的情况下加载GMAP(由initCalled标志跟踪)
    如果(!initCalled){
    //动态导入库并将其附加到文档标题
    const script=document.createElement('script');
    script.type='text/javascript';
    script.async=true;
    script.onload=函数(){
    //下载库并由浏览器解析和处理后要执行的代码从此处开始:)
    initCalled=true;
    //TODO:重构此DOM遍历逻辑
    const searchAutocomplete=document.querySelector('my-app').shadowRoot.querySelector(“主属性视图”)
    .shadowRoot.querySelector('home-property').shadowRoot.querySelector(“输入[type='text']);
    const autocomplete=new google.maps.places.autocomplete(
    搜索自动完成{
    类型:[“地址”],
    组件限制:{//仅限于美国地址
    “国家”:“美国”
    }
    });
    autocomplete.addListener('place\u changed',function(){
    const place=autocomplete.getPlace();
    dispatchEvent(新CustomEvent('propertyAddressChanged'){
    泡泡:是的,
    是的,
    细节:地点
    }));
    });
    };
    //指定gmaps库的位置
    script.src='//maps.googleapis.com/maps/api/js?v=3.33&key=&libraries=places';
    //将其附加到文档标题
    document.head.appendChild(脚本);
    }
    }
    类HomeProperty扩展了PageViewElement{
    //…为简洁起见,省略了类代码。。。
    _didRender(道具、变更道具、前置道具){
    加载谷歌地图();
    }
    //…为简洁起见,省略了类代码。。。
    }
    
    如果您有一个执行类似于
    document.querySelector
    的操作的外部库,那么您有两个选择

  • 选择不将ShadowDOM用于任何组件。如果 不是一个选项,或者如果你真的,真的想使用shadowDOM 然后:
  • 您需要修改第三方库以允许根目录 要指定的元素,而不是始终使用
    文档
  • 除了这两个选项之外,您可能无法使用假定
    文档
    适用于所有内容的第三方库

    我想另一个选择是重新评估第三方库,看看它是否真正值得使用

    在我的团队中,我们不使用不仅仅是可靠逻辑的第三方库。像这样的东西只是逻辑,我们可以毫无问题地使用它们

    但是像jQuery这样的东西?讨厌!我看不出组件需要这样的东西


    祝你好运

    你想用哪一个第三方JavaScript库?我很好奇为什么要投否决票。我想讨论一下还有哪些其他选择。
    import { html } from '@polymer/lit-element';
    import { PageViewElement } from './page-view-element.js';
    import { SharedStyles } from './shared-styles.js';
    import '@vaadin/vaadin-radio-button/vaadin-radio-button.js';
    import '@vaadin/vaadin-radio-button/vaadin-radio-group.js';
    import { spinner } from './my-icons.js';
    
    let initCalled;
    
    function loadGoogleMaps() {
      //Only load gmaps if it has not been loaded before (tracked by the initCalled flag)
      if (!initCalled) {
        //Dynamically import the library and append it to the document header
        const script = document.createElement('script');
        script.type = 'text/javascript';
        script.async = true;
        script.onload = function () {
          //Code to execute after the library has been downloaded parsed and processed by the browser starts here :)
          initCalled = true;
    
          //TODO: Refactor this DOM traversing logic
          const searchAutocomplete = document.querySelector('my-app').shadowRoot.querySelector("home-property-view")
            .shadowRoot.querySelector('home-property').shadowRoot.querySelector("input[type='text']");
    
          const autocomplete = new google.maps.places.Autocomplete(
            searchAutocomplete, {
              types: ['address'],
              componentRestrictions: {  //Limit to only US addresses
                'country': 'us'
              }
            });
    
          autocomplete.addListener('place_changed', function () {
            const place = autocomplete.getPlace();
            dispatchEvent(new CustomEvent('propertyAddressChanged', {
              bubbles: true,
              composed: true,
              detail: place
            }));
          });
        };
        //Specify the location of the gmaps library
        script.src = '//maps.googleapis.com/maps/api/js?v=3.33&key=<YOUR-API-KEY-GOES-HERE>&libraries=places';
    
        //Append it to the document header
        document.head.appendChild(script);
      }
    }
    
    class HomeProperty extends PageViewElement {
      //....omitted class code for brevity...
    
      _didRender(props, changedProps, prevProps) {
        loadGoogleMaps();
      }
    
      //....omitted class code for brevity...
    }