Неперехваченная ошибка типа: Не удается прочитать свойства null (чтение "addEventListener") Расширение Chrome

0

Вопрос

Я делаю расширение chrome для автозаполнения. А именно, после нажатия кнопки форма ввода на веб-странице содержимого будет заполнена текстом из popup.html. Я получаю эту ошибку "не удается прочитать свойства null", начиная с того места, где я добавил прослушиватель событий к своей кнопке. [Неперехваченная ошибка типа: Не удается прочитать свойства null (чтение "addEventListener")][1]

Вот мой html-файл

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Autofill</title>
    <link rel="stylesheet" href="style.css">
    
  </head>
  <body>

    <p id="testText">Text to put</p>
  
    <button id="fillForm">Fill!</button>

    
    <script src="app.js" ></script>
  </body>
  
</html>

Вот мой app.js

console.log('background running!!!')
let testtext = document.getElementById('testText')

let button = document.getElementById('fillForm')
button.addEventListener('click', buttonClick);

function buttonClick(){
    params = {
        active: true,
        currentWindow: true
    }
    chrome.tabs.query(params, gotTabs);

    function gotTabs(tabs){
        let text = testtext.innerHTML
        let content = {
        username: text
        } 
        chrome.tabs.sendMessage(tabs[0].id, content);
    }
}

Вот мой content.js

console.log("Receiving message...")
chrome.runtime.onMessage.addListener(gotMessage);

function gotMessage(message, sender, sendReponse){
    document.getElementById('email').value = content.username
    
}

Наконец, мой манифест.json

{
    "name": "Resume Autofiller",
    "description": "Build an Extension!",
    "version": "1.0",
    "manifest_version": 2,
    "browser_action":{
        "default_popup": "index.html"
    },
    "permissions": [
        "activeTab",
        "<all_urls>"
    ],
    "content_scripts": [
        {
            "matches": ["<all_urls>"],
            "js": [ "content.js" ]
        } 
    ],
    "background": {
        "scripts": ["app.js"]
      }
    
  }

Я читал в Интернете, что я должен поместить свой тег сценария в нижней части тега тела, но я все равно получаю эту ошибку. Я чувствую, что наблюдаю за чем-то очевидным, поэтому любая помощь будет очень признательна. Спасибо!! Прилагается ошибка, которую я получаю. [1]: https://i.stack.imgur.com/GyNXO.png

1

Лучший ответ

0

Как уже было сказано, удаление фона из манифеста исправит это, но в примере кода, похоже, есть концептуальная путаница, поэтому я хотел бы объяснить, почему это решение работает.

Сценарий назывался app.js похоже, что он предназначен для всплывающего сценария, но используется в качестве фонового сценария в примере. Всплывающее окно отличается от фона. Это поможет понять разницу между этими двумя частями расширения и их вариантами использования. Для обеспечения непрерывности следующее объяснение будет относиться к версии и условиям MV3.

Фон: "Работник фоновой службы загружается, когда это необходимо, и выгружается, когда он простаивает [...] Структурируйте фоновые сценарии вокруг событий, от которых зависит расширение. Определение функционально значимых событий позволяет фоновым сценариям бездействовать до тех пор, пока эти события не будут запущены, и предотвращает пропуск важных триггеров расширением" (Управление событиями с помощью сотрудников службы). Дополнительное примечание: фон буквально находится в фоновом режиме; нет видимого пользовательского интерфейса. Пользователь не будет взаимодействовать с кнопками в фоновом режиме (хотя можно отправлять события в фоновом режиме для дальнейшей обработки посредством передачи сообщений). Рассмотрим фон как одноэлементный.

Всплывающее окно: Это одно из возможных мест для предоставления пользовательского интерфейса пользователю расширения. Всплывающее окно активируется пользователем, щелкающим значок расширения, и уничтожается, когда всплывающее окно теряет фокус (также при закрытии вкладки), и перезагружается снова, когда пользователь нажимает значок в следующий раз. "Как и фоновый сценарий, этот файл должен быть объявлен в манифесте, чтобы Chrome мог представить его во всплывающем окне расширения. Для этого добавьте объект действия в манифест и установите popup.html как действие default_popup." (Представьте пользовательский интерфейс). Во всплывающем окне вы можете добавить кнопки и другие элементы, на которые пользователь может нажать. Всплывающее окно специфично для каждой вкладки. Открыв несколько окон браузера и щелкнув значок, можно одновременно открыть несколько всплывающих окон.

Короче говоря: ошибка возникает из-за поиска элемента кнопки в фоновом режиме, когда таких кнопок нет; удаление ключа манифеста предотвратит это.


Минимальный рабочий пример

манифест.json: background ключ удален

{
  "name": "Resume Autofiller",
  "description": "Build an Extension!",
  "version": "1.0",
  "manifest_version": 2,
  "browser_action":{
    "default_popup": "index.html"
  },
  "permissions": [
    "activeTab",
    "<all_urls>"
  ],
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": [ "content.js" ]
    }
  ]
}

index.html: без изменений

(style.css вызовет ошибку "не найдено", но не вызывает беспокойства по этому вопросу)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Autofill</title>
    <link rel="stylesheet" href="style.css">
    
  </head>
  <body>

    <p id="testText">Text to put</p>
  
    <button id="fillForm">Fill!</button>

    
    <script src="app.js" ></script>
  </body>
  
</html>

app.js: изменен текст журнала, существенных изменений нет

console.log('popup running!!!')
let testtext = document.getElementById('testText')

let button = document.getElementById('fillForm')
button.addEventListener('click', buttonClick);

function buttonClick(){
    params = {
        active: true,
        currentWindow: true
    }
    chrome.tabs.query(params, gotTabs);

    function gotTabs(tabs){
        let text = testtext.innerHTML
        let content = {
            username: text
        }
        chrome.tabs.sendMessage(tabs[0].id, content);
    }
}

content.js: немного изменил выходные данные журнала, прокомментировал назначение

chrome.runtime.onMessage.addListener(gotMessage);

function gotMessage(message, sender, sendResponse){
    console.log("Receiving message...")
    console.log('message', JSON.stringify(message));
    // next line has undefined references, commenting out
    // document.getElementById('email').value = content.username
}
2021-11-21 21:21:52

спасибо, я удалил фоновый сценарий из манифеста, однако я все еще получаю ту же ошибку. Единственная разница сейчас в том, что контекст выводит текущую вкладку, в которой я нахожусь, в отличие от _generated_background_page.html это было показано ранее. Читая онлайн, можно исправить "свойство, установленное в значение null" кнопки, либо проверив ошибки именования, либо добавив прослушиватель событий DOMContentLoaded, что я сделал и то, и другое, и все равно получаю ту же ошибку
Chris Wu

Хорошо, позвольте мне опубликовать минимальный рабочий пример. Я отредактирую ответ.
Neea

В фоновом режиме нет кнопки, если она не была сгенерирована программно первой. getElementById будет продолжать возвращаться неопределенным после проверки именования или ожидания загрузки содержимого. Фон следует рассматривать как безголовый (хотя в mv2 можно просматривать сгенерированную страницу, но фактический пользователь ее не увидит).
Neea

вау, это помогло прояснить многие вещи, я заставил это работать. Очень признателен!!!! Это было связано с передачей сообщений (message.username вместо content.username)
Chris Wu

На других языках

Эта страница на других языках

Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................