首页 文章

在Web组件中使用外部JS库

提问于
浏览
16

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

我可以看到这样做的几个问题,并想知道是否有任何解决方法,实际上是否以这种方式包含第三方库被认为是不好的做法 .

  • 外部库可能设置全局变量,这些变量对页面上的其他组件可见,允许Web组件相互分离,或者破坏它们所托管的页面 . 由于封装经常被吹捧为one of the big advantages of using web components,这似乎是一个问题 .

  • 外部库可能执行DOM查询或更新,这些查询或更新无法访问正在使用它们的Web组件的影子,因此外部库可能根本不起作用,或者可能再次更新托管页面的DOM封装 .

所以,我错过了什么或这是否意味着在Web组件中包含外部库是一个非常糟糕的主意?如果是这样,这似乎是这项技术的一个巨大限制,因为我们无法利用大量已有的JS库 .

2 回答

  • 4

    如果你有一个像 document.querySelector 这样的外部库,那么你有两个选择 .

    • 选择不将ShadowDOM与任何组件一起使用 . 如果那不是一个选项,或者如果你真的那么,真的想要使用shadowDOM:

    • 您需要修改第三方库以允许指定根元素,而不是始终使用 document .

    除了这两个选项之外,您可能无法使用假定 document 适用于所有内容的第三方库 .

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

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

    但是像jQuery这样的东西?呸!我看不到组件需要这样的东西 .

    祝好运!

  • 0

    我实际上昨天必须处理完全相同的问题这么好的时机;)在我的情况下,第一页中的视图有两个部分,一个带有单选按钮,并且由于业务需求取决于用户的单选按钮选择一个输入文本与谷歌 Map 自动完成功能将启用(或保持禁用状态)

    在这种情况下,加载没有谷歌 Map 库的页面更有效率,然后在webcomponent完全呈现后动态加载gmaps代码,导致交互时间减少50%:)这就是我最终做的事情 .

    注意:loadGoogleMaps()方法和initCalled变量声明在类之外,因此在web组件之外(我将它们放在import语句下) . 我也省略了示例中的大部分类代码,因为它与你的问题无关:)

    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...
    }
    

相关问题