我正在编写Chrome扩展程序。令我困惑的一个问题是来自querySelectorAll的元素的感知粘性。
我有一个库中的代码,我已将其放在我的content.js文件中。该库定义了ready()函数,用于检查特定元素是否已在页面上完成加载,以便在加载时可以执行某些操作。我发现如果我从一个页面导航到另一个页面,两个相同的类型(相同的DOM结构),就绪函数似乎没有做任何事情。
我控制台记录所有内容以进行故障排除,因此最后我得出结论,在元素完成加载后没有采取任何操作的原因是if (!element.ready)
函数中的checkSelector
检查失败第二页(以及任何其他页面)。原因是在第一页上,element.ready是未定义的,但是一旦我导航到第二页,element.ready始终为true。坦率地说,这对我来说完全出乎意料,因为有人是javascript的新手。我的意思是,不仅通过控制台日志记录在函数中定义了var element
,我还知道整个content.js文件在我导航到的第二个页面上重新运行,以便{{1}中的函数定义的每次都被重新调用。此外,当我安慰记录元素本身时,它显示它已经获取内容的更改:即使选择器定义为相同,所选内容/数据在第一页和第二页之间是不同的,因此记录的元素是也不同。到目前为止解决该问题的唯一方法是在导航到它之后刷新第二页 - 这导致var element
再次未定义,通过检查。
我的问题:发生了什么?每当导航到新页面时,如何使该功能通过var element
部分?
content.js:
fn.call(element, element);
额外信息:
background.js:
var listeners = [],
doc = document,
MutationObserver = MutationObserver || WebKitMutationObserver,
observer;
console.log("new listeners created");
/*
* Checks a selector for new matching
* elements and invokes the callback
* if one is found
*
* @param {String} selector
* @param {Function} fn
* @api private
*/
function checkSelector(selector, fn) {
//var elements = ['a', 'b'];
var elements = doc.querySelectorAll(selector);
var i = 0,
len = elements.length, element;
for (; i < len; i++) {
element = elements[i];
// Make sure the callback isn't invoked with the
// same element more than once
console.log(element);
console.log(element.ready);
if (!element.ready) {
element.ready = true;
console.log("so I think this part is not called in the reload");
// Invoke the callback with the element
fn.call(element, element);
}
}
}
/*
* Check all selectors for new elements
* following a change in the DOM
*
* @api private
*/
function checkListeners(mutations) {
//console.log("checking listeners. The length is "+listeners.length);
mutations.forEach(function(mutation) {
//console.log(mutation.type);
});
for (var i = 0, len = listeners.length, listener; i < len; i++) {
listener = listeners[i];
//console.log(listener.selector);
//console.log(listener.fn);
(function() {
checkSelector(listener.selector, listener.fn);
})();
}
}
/*
* Add a selector to watch for when a matching
* element becomes available in the DOM
*
* @param {String} selector
* @param {Function} fn
* @api public
*/
function ready(selector, fn) {
// Store the selector and callback to be monitored
listeners.push({
selector: selector,
fn: fn
});
if (!observer) {
observer.observe(doc.documentElement, {
childList: true,
subtree: true
//characterData: true,
//attributes: true
});
}
// Check if the element is currently in the DOM
checkSelector(selector, fn);
}
ready('.pv-top-card-section__name', function (element) {
console.log("the top card is loaded");
headlines['full-name'] = $('.pv-top-card-section__name').text().replace(/ /g, '_').trim();
//console.log(headlines['full-name']);
headlines['headline'] = $('.pv-top-card-section__headline').text().trim();
//console.log(headlines['headline']);
headlines['company'] = $('.pv-top-card-section__company').text().trim();
//console.log(headlines['company']);
headlines['location'] = $('.pv-top-card-section__location').text().trim();
//console.log(headlines['location']);
headlines['school'] = $('.pv-top-card-section__school').text().trim();
//console.log(headlines['school']);
});
的manifest.json:
chrome.webNavigation.onHistoryStateUpdated.addListener(function() {
//chrome.tabs.executeScript(null,{file:"extensions/ready.js"});
chrome.tabs.executeScript(null,{file:"content.js"});
});
chrome.browserAction.setBadgeBackgroundColor({ color: '#a442f4', tabId: 1 });
chrome.browserAction.setBadgeText({ text: 'hello'});
chrome.runtime.onMessage.addListener(
function(request, sender) {
// read `newIconPath` from request and read `tab.id` from sender
chrome.browserAction.setBadgeText({
text: request.text
});
});