简体   繁体   English

在Web组件中使用外部JS库

[英]Using external JS libraries in a web component

I am developing a web component using Polymer 2, and would like to make use of a third-party JavaScript library, which was not specifically designed for use with web components. 我正在使用Polymer 2开发一个Web组件,并且希望使用第三方JavaScript库,该库不是专门为Web组件设计的。 As far as I know, the only way to do this is to include a <script> tag referencing the library, within the HTML file of my web component. 据我所知,唯一的方法是在我的Web组件的HTML文件中包含一个引用该库的<script>标记。

I can see a couple of issues with doing this, and want to know if there are any ways around them, and indeed whether including third-party libraries in this way is considered bad-practice. 我可以看到这样做的几个问题,并想知道是否有任何解决方法,实际上是否以这种方式包含第三方库被认为是不好的做法。

  1. The external library might set global variables which are visible to other components on the page, allowing web components to break each other, or break the page they are hosted on. 外部库可能设置全局变量,这些变量对页面上的其他组件可见,允许Web组件相互分离,或者破坏它们所托管的页面。 Since encapsulation is often touted as one of the big advantages of using web components , this seems like a problem. 由于封装经常被吹捧为使用Web组件的一大优势 ,这似乎是一个问题。

  2. The external library might perform DOM queries or updates which would not be able to access the shadow-dom of the web component that is using them, so the external library might not actually work at all, or might update the hosting page's DOM again breaking encapsulation. 外部库可能执行DOM查询或更新,这些查询或更新无法访问正在使用它们的Web组件的影子,因此外部库可能根本不工作,或者可能再次更新托管页面的DOM,从而破坏封装。

So, am I missing something or does this mean that including external libraries in a web component is a really bad idea? 所以,我错过了什么或这是否意味着在Web组件中包含外部库是一个非常糟糕的主意? If so, it seems like a huge limitation of this technology, since we can't take advantage of the vast number of pre-existing JS libraries out there. 如果是这样,这似乎是这项技术的一个巨大限制,因为我们无法利用大量已有的JS库。

If you have an external library that does things like document.querySelector then you have two choices. 如果你有一个外部库来执行document.querySelector那么你有两个选择。

  1. Choose to not use ShadowDOM with any of your components. 选择不将ShadowDOM与任何组件一起使用。 If that is not an option, or if you really, REALLY want to use shadowDOM then: 如果那不是一个选项,或者如果你真的那么,真的想要使用shadowDOM:
  2. You need to modify the third party library to allow a root element to be specified instead of always using document . 您需要修改第三方库以允许指定根元素,而不是始终使用document

Beyond those two options you will probably not be able to use a third party library that assumes document will work for everything. 除了这两个选项之外,您可能无法使用假定document适用于所有内容的第三方库。

I guess the other option is to re-evaluate the third party library and see if it is REALLY worth using. 我想另一个选择是重新评估第三方库,看看它是否真的值得使用。

On my team we don't use third party libraries that are not just solid logic. 在我的团队中,我们不使用不仅仅是可靠逻辑的第三方库。 Things like moment.js are just logic and we can use them without problems. moment.js这样的东西只是逻辑,我们可以毫无问题地使用它们。

But something like jQuery? 但是像jQuery这样的东西? Yuck! 呸! I can't see needing something like that for a component. 我看不到组件需要这样的东西。

Good luck! 祝好运!

I actually had to deal with that exact same issue yesterday so good timing ;) In my case the view in the first page has two sections one with radio buttons and because of business requirements depending on the user's radio button selection an input text with google maps autocomplete would get enabled (or stay disabled) 我实际上昨天必须处理完全相同的问题这么好的时机;)在我的情况下,第一页中的视图有两个部分,一个带有单选按钮,并且由于业务需求取决于用户的单选按钮选择一个输入文本与谷歌地图自动完成功能将启用(或保持禁用状态)

In this scenario it was much more efficient to load the page without the google maps libraries and then dynamically load the gmaps code after the webcomponent was fully rendered which lead to a 50% drop in time to interactive :) Here is what I ended up doing. 在这种情况下,加载没有谷歌地图库的页面更有效率,然后在webcomponent完全呈现后动态加载gmaps代码,导致交互时间减少50%:)这就是我最终做的事情。

NOTE: The loadGoogleMaps() method and the initCalled variable declaration are outside the class and thus outside of the webcomponent (I put them under the import statements). 注意:loadGoogleMaps()方法和initCalled变量声明在类之外,因此在web组件之外(我将它们放在import语句下)。 I also omitted most of the class code from the example as it wasn't relevant to your question :) 我也省略了示例中的大部分类代码,因为它与你的问题无关:)

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM