Замените ссылку href на функцию JS - PullRequest
0 голосов
/ 13 июля 2020

В моем приложении для реагирования, которое работает с API, я получаю JSON значений для отображения данных в компонентах. Так, например, у меня есть компонент Features:

const Features = () => {
  const { title } = useSelector(({ titles }) => titles);
  let string = title.features;
  // the string can contain some html tags. Example bellow:
  // sting = 'This is a string containing a href to <a href="www.google.com">Google</a>';

  string = string.replace(/href="(.*?)"/g, function() {
    return `onClick="${() => shell.openExternal('www.google.com')}"`;
  });

  return (
    <>
      <Heading>Features</Heading>
      <Text content={parsedHTML} />
    </>
  );
};

Я хочу заменить атрибут href на onClick и назначить функцию Electron shell.openExternal().

Функция обратного вызова string.replace() делает это, но когда я нажимаю на элемент <a>, приложение выдает следующую ошибку:

error: uncaughtException: Ожидается, что прослушиватель onClick будет функцией, вместо этого он получил значение типа string.

ОБНОВЛЕНИЕ

Также пробовал этот лог c, и возникает та же ошибка:

  global.openInBrowser = openInBrowser; // openInBrowser is basically a function that calls shell.openExternal(url)

  const re = new RegExp('<a([^>]* )href="([^"]+)"', 'g');
  string = string.replace(re, '<a$1href="#" onClick="openInBrowser(\'$2\')"');

Вот ссылка на Sandbox rep.

Как мне это сделать правильно?

Ответы [ 2 ]

1 голос
/ 14 июля 2020

onclick, не установленный в элементе React, на самом деле является ожидаемым поведением.

Потому что существует риск безопасности XSS при обходе строки onclick. Рекомендуемое решение - использовать параметр replace в html-react-parser.

вы также можете использовать dangerouslySetInnerHTML, что связано с риском безопасности.

Sandbox Demo

export default function App() {
  let string =
    'This is a string containing html link to <a href="www.google.com">Google</a>';

  const re = new RegExp('<a([^>]* )href="([^"]+)"', "g");
  let replaced = string.replace(re, "<a onclick=\"alert('$2')\"");

  return (
    <div className="App">
      <p dangerouslySetInnerHTML={{__html: replaced}}></p>
      <p>{parse(string, {
        replace: domNode => {
          if (domNode.name === 'a') {
            let href = domNode.attribs.href
            domNode.attribs.onClick = () => { alert(href) }
            delete domNode.attribs.href
          }
        }
      })}</p>
    </div>
  );
}
1 голос
/ 13 июля 2020

Не уверен в специфике электрона, но передача (function(){functionName()})() не будет работать в html, если в области окна нет переменной functionName. Поскольку в электроне есть глобальная среда, это может ответить на ваш вопрос:

const Features = () => {
  const { title } = useSelector(({ titles }) => titles);
  let string = title.features;
  // the string can contain some html tags. Example bellow:
  // sting = 'This is a string containing a href to <a href="www.google.com">Google</a>';
  
  function runOpen(href){
      shell.openExternal(href)
  }      

  global.runOpen = runOpen;

  string = string.replace(/href="(.*?)"/g, function() {
    return `onClick="runOpen(${'www.google.com'})"`;
  });

  return (
    <>
      <Heading>Features</Heading>
      <Text content={parsedHTML} />
    </>
  );
};

, если это не так, вы можете использовать что-то вроде onclick="console.log(this)", чтобы узнать, в какой области работает onclick, и затем назначить свой runOpen там переменная.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...