Google地点自动完成,如何清理pac-container?

22
我正在使用谷歌地点自动完成控件,它创建了一个下拉菜单元素并具有类 pac-container
我在一个Ember应用程序中使用自动完成功能,当我完成它后,自动完成绑定的DOM元素被删除,但是pac-container元素仍然存在,即使它已经隐藏。下一次我实例化新的自动完成时,新的pac-container将被创建,旧的容器仍然存在。我似乎找不到API上的dispose方法,所以有没有正确处理这个问题的方法?如果没有,我想我应该使用jQuery来清除这些元素。
5个回答

12

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

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();

希望这能帮助到你。


更新

我不确定谷歌的混淆是如何工作的,但上面的部分似乎已被混淆,如果混淆或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能尽快解决这个问题。


8

我没有使用jQuery实现上面代码

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()

2
这目前可行,直到Google更改类名为止
autocomplete.addListener('place_changed', function() {

    $('.pac-container').remove();

});

1
我编写了这个递归函数,用于定位自动完成对象中元素的位置。
获取第一个匹配的对象
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);
}

1
我也遇到了这个问题。可能与我的输入字段在flexbox内有关,但我还没有尝试重新构建页面。相反,我为我的输入字段添加了一个onfocus监听器以及一个onscroll监听器到它的容器上。里面我使用getBoundingClientRect获取输入字段的位置,然后使用这些值更新我的样式表。我尝试直接选择和更新.pac-container通过document.querySelctor,但那似乎不起作用。你可能需要一个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,这种方法就会失效,因此不是完美的解决方案,但在此期间仍可使用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接