【问题标题】:Google places autocomplete, how to clean up pac-container?Google 放置自动完成功能,如何清理 pac-container?
【发布时间】:2014-01-28 05:34:27
【问题描述】:

我正在使用 google Places 自动完成控件,它为下拉菜单创建了一个元素,其类为 pac-container

我在 ember 应用程序中使用自动完成功能,当我完成它时,自动完成功能绑定到的 DOM 元素会被删除,但 pac-container 元素仍然存在,即使它被隐藏了。下次我实例化一个新的自动完成功能时,会创建一个新的 pac-container 并保留旧的。我似乎在 API 上找不到类似 dispose 方法的东西,那么有没有办法正确地做到这一点?如果不是,我想我应该只使用 jquery 来清除元素。

【问题讨论】:

    标签: javascript google-places-api


    【解决方案1】:

    我遇到了同样的问题,希望 Google 最终能提供一种官方的清理方法,但现在我能够通过手动删除 pac-container 对象来解决问题,可以在自动完成中找到该对象的引用返回的类:

    var autocomplete = new google.maps.places.Autocomplete(element, options);
    

    可以在以下位置找到对 pac-container 元素的引用:

    autocomplete.gm_accessors_.place.Mc.gm_accessors_.input.Mc.L
    

    我只是在我的小部件析构函数中从 DOM 中删除了它:

    $(autocomplete.gm_accessors_.place.Mc.gm_accessors_.input.Mc.L).remove();
    

    希望这会有所帮助。


    更新

    我不确定 Google 的混淆是如何工作的,但上面的部分内容似乎被混淆了,如果混淆或 API 的内部结构发生变化,显然会失败。不能对后者做太多,但对于前者,您至少可以按预期标准搜索对象属性。正如我们所看到的,有些属性名称没有被混淆,而有些似乎是,例如“Mc”和“L”。为了使它更健壮一点,我编写了以下代码:

    var obj = autocomplete.gm_accessors_.place;
    $.each(Object.keys(obj), function(i, key) {
      if(typeof(obj[key]) == "object" && obj[key].hasOwnProperty("gm_accessors_")) {
        obj = obj[key].gm_accessors_.input[key];
        return false;
      }
    });
    $.each(Object.keys(obj), function(i, key) {
      if($(obj[key]).hasClass("pac-container")) {
        obj = obj[key];
        return false;
      }
    });
    $(obj).remove();
    

    代码期望一般结构保持不变,而不依赖于(可能)混淆的名称“Mc”和“L”。我知道很丑,但希望 Google 能尽快解决这个问题。

    【讨论】:

      【解决方案2】:

      我在没有 jquery 的情况下实现 code from above

      var autocomplete = new google.maps.places.Autocomplete(element, options);
      

      export function getAutocompletePacContainer(autocomplete) {
       const place: Object = autocomplete.gm_accessors_.place;
      
       const placeKey = Object.keys(place).find((value) => (
          (typeof(place[value]) === 'object') && (place[value].hasOwnProperty('gm_accessors_'))
       ));
      
       const input = place[placeKey].gm_accessors_.input[placeKey];
      
       const inputKey = Object.keys(input).find((value) => (
         (input[value].classList && input[value].classList.contains('pac-container'))
       ));
      
       return input[inputKey];
      }
      

      getAutocompletePacContainer(autocomplete).remove()
      

      【讨论】:

        【解决方案3】:

        这暂时有效直到 Google 更改类名

        autocomplete.addListener('place_changed', function() {
        
            $('.pac-container').remove();
        
        });
        

        【讨论】:

          【解决方案4】:

          构建此递归函数来定位自动完成对象内的元素位置。


          获取第一个匹配对象

          var elementLocator = function(prop, className, maxSearchLevel, level) {
          
              level++;
          
              if (level === (maxSearchLevel + 1) || !prop || !(Array.isArray(prop) || prop === Object(prop))) {
                  return;
              }
          
              if (prop === Object(prop) && prop.classList && prop.classList.contains && typeof prop.classList.contains === 'function' && prop.classList.contains(className)) {
                  return prop;
              }
          
              for (const key in prop) {
                  if (prop.hasOwnProperty(key)) {
                      var element = elementLocator(prop[key], className, maxSearchLevel, level);
                      if (element) {
                          return element;
                      }
                  }
              }
          };
          

          用法:

          var elm = null;
          try {
              //set to search first 12 levels, pass -1 to search all levels
              elm = elementLocator(this.autocomplete, 'pac-container', 12, null); 
          } catch(e) {
              console.log(e);
          }
          

          【讨论】:

            【解决方案5】:

            我也遇到了这个问题。这可能与我的输入字段位于弹性框内有关,但我还没有尝试重组我的页面。相反,我在我的输入字段中添加了一个 onfocus 侦听器,并在它的容器中添加了一个 onscroll 侦听器。在里面,我用getBoundingClientRect 获取输入字段的位置,然后用这些值更新我的样式表。我尝试通过document.querySelctor 直接选择和更新.pac-container,但这似乎不起作用。你可能需要一个 setTimeout 来允许它首先被添加到 DOM 中。

            这是我的代码:

            let ruleIndex = null;
            const form = document.body.querySelector('.form');
            const input = document.body.querySelector('.form-input');
            
            const positionAutoComplete = () => {
              const { top, left, height } = inputField.getBoundingClientRect();
              if(ruleIndex) document.styleSheets[0].deleteRule(ruleIndex);
              ruleIndex = document.styleSheets[0].insertRule(`.pac-container { top: ${top + height}px !important; left: ${left}px !important; }`);
            }
            
            form.addEventListener('scroll', positionAutoComplete);
            input.addEventListener('focus', positionAutoComplete);
            

            正如之前的回答中提到的,这打破了谷歌决定重命名 .pac-container 的那一刻,所以这不是一个完美的修复,但在此期间可以工作。

            【讨论】:

              猜你喜欢
              • 2020-03-14
              • 2014-08-29
              • 1970-01-01
              • 2021-08-31
              • 2015-12-30
              • 1970-01-01
              • 1970-01-01
              • 2021-06-24
              • 2015-05-01
              相关资源
              最近更新 更多