onclick или встроенный скрипт не работает в расширении

Кажется, это проще всего сделать, но это просто не работает. В обычном браузере файлы .html и .js работают отлично, но в расширении Chrome / Firefox функция onClick не выполняет то, что должна.

.js файл:

function hellYeah(text) {
  document.getElementById("text-holder").innerHTML = text;
}

.html файл:

<!doctype html>
<html>
  <head>
    <title>
      Getting Started Extension's Popup
    </title>
    <script src="popup.js"></script>
  </head>
  <body>
    <div id="text-holder">
      ha
    </div>
    <br />
    <a onClick=hellYeah("xxx")>
      hyhy
    </a>
  </body>
</html>

Итак, в основном, когда пользователь нажимает hyhy, ha должно измениться на xxx. И снова - он отлично работает в браузере, но не работает в расширении. Ты знаешь почему? На всякий случай я также прикрепляю файл manifest.json ниже.

manifest.json:

{
  "name": "My First Extension",
  "version": "1.0",
  "manifest_version": 2,
  "description": "The first extension that I made.",
  "browser_action": {
    "default_icon": "icon.png",
    "default_popup": "popup.html"
  },
  "permissions": [
    "http://api.flickr.com/"
  ]
}

person teeZee    schedule 27.11.2012    source источник


Ответы (5)


Расширения Chrome не позволяют использовать встроенный JavaScript (документация).
То же самое касается Firefox WebExtensions (документация < / а>).

Вам нужно будет сделать что-то подобное:

Присвойте ссылке идентификатор (<a onClick=hellYeah("xxx")> станет <a id="link">) и используйте _3 _ привязать событие. Поместите в свой popup.js файл следующее:

document.addEventListener('DOMContentLoaded', function() {
    var link = document.getElementById('link');
    // onClick's logic below:
    link.addEventListener('click', function() {
        hellYeah('xxx');
    });
});

popup.js следует загрузить как отдельный файл сценария:

<script src="popup.js"></script>
person David    schedule 27.11.2012
comment
У меня получилось что-то вроде этого: Отказался выполнять встроенный скрипт, потому что он нарушает следующую директиву Политики безопасности контента: script-src 'self' chrome-extension-resource :. - person teeZee; 28.11.2012
comment
Javascript не может быть в вашем HTML-файле для расширений. Вам необходимо загрузить весь javascript из внешнего источника. Что-то вроде <script src="javascript.js"></script> - person David; 28.11.2012
comment
@teeZee Для дальнейшего использования помещайте обратные кавычки (`) вокруг вашего кода, чтобы отформатировать его в комментариях. Like this. - person joe_young; 05.07.2015
comment
Разметка в моем всплывающем окне создается во время выполнения (например, теги ‹a› со значениями, которые невозможно предсказать). Я установил идентификаторы своих тегов ‹a›, равные значению тега ‹a› innerhtml как такового: ‹a href=# id=xxxxxx› xxxxxx ‹/a› ‹a href=# id=abc123› abc123 ‹/A›, но мне нужно передать значение в javascript для обработки при нажатии на них ... как бы я это сделал? В конечном итоге, просто заставить javascript предупреждать о значении нажатой href было бы хорошим началом. - person stumped221; 09.02.2017
comment
Обратите внимание, что даже если вы не можете использовать встроенный onclick="handleClick()", вы все равно можете использовать el.onclick = handleClick. - person thdoan; 16.05.2017

Причина

Это не работает, потому что Chrome запрещает любой встроенный код в расширениях через политику безопасности контента. .

Встроенный JavaScript не будет выполняться. Это ограничение запрещает как встроенные <script> блоки, и встроенные обработчики событий (например, <button onclick="...">).

Как обнаружить

Если это действительно проблема, Chrome выдаст в консоли следующую ошибку:

Отказался от выполнения встроенного сценария, поскольку он нарушает следующую директиву политики безопасности содержимого: script-src 'self' chrome-extension-resource :. Для включения встроенного выполнения требуется ключевое слово 'unsafe-inline', хэш ('sha256 -...') или одноразовый номер ('nonce -...').

Чтобы получить доступ к консоли JavaScript всплывающего окна (которая полезна для отладки в целом), щелкните правой кнопкой мыши кнопку расширения и выберите Проверить всплывающее окно из контекстного меню.

Дополнительную информацию об отладке всплывающих окон можно найти здесь.

Как исправить

Необходимо удалить весь встроенный JavaScript. В документации Chrome есть руководство.

Предположим, оригинал выглядит так:

<a onclick="handler()">Click this</a> <!-- Bad -->

Необходимо удалить атрибут onclick и присвоить элементу уникальный идентификатор:

<a id="click-this">Click this</a> <!-- Fixed -->

А затем прикрепите слушателя из сценария (который должен быть в файле .js, предположим, popup.js):

// Pure JS:
document.addEventListener('DOMContentLoaded', function() {
  document.getElementById("click-this").addEventListener("click", handler);
});

// The handler also must go in a .js file
function handler() {
  /* ... */
}

Обратите внимание на обертку в событии DOMContentLoaded. Это гарантирует, что элемент существует во время выполнения. Теперь добавьте тег скрипта, например, в <head> документа:

<script src="popup.js"></script>

Альтернатива, если вы используете jQuery:

// jQuery
$(document).ready(function() {
  $("#click-this").click(handler);
});

Ослабление политики

В: В ошибке упоминаются способы разрешения встроенного кода. Я не хочу / не могу изменять свой код, как мне включить встроенные скрипты?

A: Несмотря на сообщение об ошибке, вы не удается включить встроенный скрипт:

Не существует механизма для снятия ограничения на выполнение встроенного JavaScript. В частности, установка политики сценария, включающей 'unsafe-inline', не будет иметь никакого эффекта.

Обновление. Начиная с Chrome 46, можно добавить в белый список определенные встроенные блоки кода:

Начиная с Chrome 46, встроенные скрипты можно добавить в белый список, указав в политике хеш исходного кода в кодировке base64. Этот хэш должен иметь префикс используемого алгоритма хеширования (sha256, sha384 или sha512). См. Использование хеша для <script> элементов для примера.

Однако я не вижу причин для использования этого, и он не будет включать встроенные атрибуты, такие как onclick="code".

person Community    schedule 08.09.2014
comment
если я хочу сделать то же самое с именем класса вместо Id .. Я пробовал, но не повезло ' - person Ratan Paul; 29.10.2016
comment
Есть мысли о том, как можно анонимизировать это решение, чтобы оно могло работать для приложения angular с сгенерированными именами div? Я не могу создавать слушателей событий, потому что имена кнопок должны быть уникальными для каждого элемента в моем ng repeat ... :( - person itchyspacesuit; 29.04.2017

Как уже упоминалось, расширения Chrome не позволяют использовать встроенный JavaScript из соображений безопасности, поэтому вы также можете попробовать этот обходной путь.

HTML файл

<!doctype html>
    <html>
        <head>
            <title>
                Getting Started Extension's Popup
            </title>
            <script src="popup.js"></script>
        </head>
        <body>
            <div id="text-holder">ha</div><br />
            <a class="clickableBtn">
                  hyhy
            </a>
        </body>
    </html>
<!doctype html>

popup.js

window.onclick = function(event) {
    var target = event.target ;
    if(target.matches('.clickableBtn')) {
        var clickedEle = document.activeElement.id ;
        var ele = document.getElementById(clickedEle);
        alert(ele.text);
    }
}

Или, если у вас есть файл JQuery, тогда

window.onclick = function(event) {
    var target = event.target ;
    if(target.matches('.clickableBtn')) {
        alert($(target).text());
    }
}
person jai gupta    schedule 20.04.2020

У меня была та же проблема, и я не хотел переписывать код, поэтому я написал функцию для изменения кода и создания встроенных объявленных событий:

function compile(qSel){
    var matches = [];
    var match = null;
    var c = 0;

    var html = $(qSel).html();
    var pattern = /(<(.*?)on([a-zA-Z]+)\s*=\s*('|")(.*)('|")(.*?))(>)/mg;

    while (match = pattern.exec(html)) {
        var arr = [];
        for (i in match) {
            if (!isNaN(i)) {
                arr.push(match[i]);
            }
        }
        matches.push(arr);
    }
    var items_with_events = [];
    var compiledHtml = html;

    for ( var i in matches ){
        var item_with_event = {
            custom_id : "my_app_identifier_"+i,
            code : matches[i][5],
            on : matches[i][3],
        };
        items_with_events.push(item_with_event);
        compiledHtml = compiledHtml.replace(/(<(.*?)on([a-zA-Z]+)\s*=\s*('|")(.*)('|")(.*?))(>)/m, "<$2 custom_id='"+item_with_event.custom_id+"' $7 $8");
    }

    $(qSel).html(compiledHtml);

    for ( var i in items_with_events ){
        $("[custom_id='"+items_with_events[i].custom_id+"']").bind(items_with_events[i].on, function(){
            eval(items_with_events[i].code);
        });
    }
}

$(document).ready(function(){
    compile('#content');
})

Это должно удалить все встроенные события из выбранного узла и вместо этого воссоздать их с помощью jquery.

person sergio0983    schedule 04.08.2015
comment
этот код не выполняется должным образом, пожалуйста, помогите мне правильно - person employeegts; 24.09.2015

Решаю опубликовать свой пример, который я использовал в своем случае. Я попытался заменить содержимое в div с помощью скрипта. Моя проблема заключалась в том, что Chrome не распознал / не запускал этот скрипт.

Более подробно. Что я хотел сделать: щелкнуть ссылку и эту ссылку для «чтения» внешнего файла html, чтобы он был загружен в раздел div.

  • Я обнаружил, что, поместив скрипт перед DIV с ID, который был вызван, скрипт не работал.
  • Если скрипт был в другом DIV, тоже не работает
  • Скрипт должен быть закодирован с использованием document.addEventListener ('DOMContentLoaded', function (), как было сказано

        <body>
        <a id=id_page href ="#loving"   onclick="load_services()"> loving   </a>
    
            <script>
                    // This script MUST BE under the "ID" that is calling
                    // Do not transfer it to a differ DIV than the caller "ID"
                    document.getElementById("id_page").addEventListener("click", function(){
                    document.getElementById("mainbody").innerHTML = '<object data="Services.html" class="loving_css_edit"; ></object>'; });
                </script>
        </body>
    
      <div id="mainbody" class="main_body">
            "here is loaded the external html file when the loving link will 
             be  clicked. "
      </div>
    
person Elias EstatisticsEU    schedule 31.10.2018
comment
Не уверен .... работает ли он на 100% правильно. Определение txt / html было удалено. - person Elias EstatisticsEU; 31.10.2018