2016-11-20 2 views
3

여러분이 선택한 단어에 강조 표시 CSS 규칙을 자동으로 적용 할 수있는 Google 크롬 확장 프로그램을 개발 중입니다..replace()를 사용하여 페이지의 텍스트를 강조 표시하십시오.

는 다음 코드 나누기 내 크롬 탭을 정지

var elements = document.getElementsByTagName('*'); 

for (var i=0; i<elements.length; i++) { 
    var element = elements[i]; 

    for (var j=0; j<element.childNodes.length; j++) { 
     var node = element.childNodes[j]; 

     if(node.nodeType === 3) { 
      var text = node.nodeValue; 

      var fetchedText = text.match(/teste/gi); 

      if(fetchedText) { 
       var replacedText = element.innerHTML.replace(/(teste)/gi, "<span style=\"background-color: yellow\">$1</span>"); 

       if (replacedText !== text) { 
        element.innerHTML = replacedText; 
       } 
      } 
     } 
    } 
} 

에게 있습니다. 그러나 element.innerHTML = replacedText;에서 element.innerHTML = "text";으로 전환하면 작동합니다.

다음 코드는 무엇이 잘못되었는지를 알 수 없습니다.

+0

'replacedText'에 값이 있습니까? –

+0

@ScottMarcus'replacedText'를 로그 할 때' teste'와 같은 정확한 값을 보여줍니다. 그러나이 요소를'element.innerHTML'에 사용하면 내 탭이 손상됩니다. – rafaelcpalmeida

+0

콘솔에'\ "'이스케이프 문자열이 표시되고 있습니까? 문자열을 다음과 같이 수정 해 보셨습니까?" $ 1 "'? –

답변

0

내가 재귀 루프로 인해 예를 들어, 내가 키워드 teste을 찾고 하였다 때문에 경험 된 오류 코드에서 수정 된 난 삽입했다 내용이 <span style=\"background-color: #ffff00\">teste</span> 인 새 요소는 스크립트가 새 키워드 teste을 다시 교체하도록합니다.

나는이 기능을 함께했다 : 나는 노드의 속성을 수정하고 다시는 재귀 무한 루프에 결국하지 않도록 이미 해당 노드를 수정 한 그 "말"
function applyReplacementRule(node) { 
    // Ignore any node whose tag is banned 
    if (!node || $.inArray(node.tagName, hwBannedTags) !== -1) { return; } 

    try { 
     $(node).contents().each(function (i, v) { 
      // Ignore any child node that has been replaced already or doesn't contain text 
      if (v.isReplaced || v.nodeType !== Node.TEXT_NODE) { return; } 

      // Apply each replacement in order 
      hwReplacements.then(function (replacements) { 
       replacements.words.forEach(function (replacement) { 
        //if(!replacement.active) return; 
        var matchedText = v.textContent.match(new RegExp(replacement, "i")); 

        if (matchedText) { 
         // Use `` instead of '' or "" if you want to use ${variable} inside a string 
         // For more information visit https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals 
         var replacedText = node.innerHTML.replace(new RegExp(`(${replacement})`, "i"), "<span style=\"background-color: #ffff00\">$1</span>"); 

         node.innerHTML = replacedText; 
        } 
       }); 
      }).catch(function (reason) { 
       console.log("Handle rejected promise (" + reason + ") here."); 
      }); 

      v.isReplaced = true; 
     }); 
    } catch (err) { 
     // Basically this means that an iframe had a cross-domain source 
     if (err.name !== "SecurityError") 
     { throw err; } 
    } 
} 

.

P. 이 솔루션은 jQuery를 사용합니다. 바닐라 JS 만 사용하도록 다시 작성하겠습니다.

+0

당신의 솔루션은 여전히 ​​RegExp를 사용하여 부모 요소의 .innerHTML을 변경합니다. 따라서 텍스트 노드에도 해당 단어가 포함되어 있으면 대체중인 단어가 포함 된 HTML이 계속 손상됩니다. 바꾸어 말하면 대체 텍스트가 실제 텍스트에서 일어나지 않는 한 바꾸기는하지 않지만 HTML이 변경되는 것을 막을 수는 없습니다 (예 :'src = "yourWord"'또는'href = "http : // foo.com/yourWord/bar.html "). – Makyen

+0

비판적인 의도가 아닌 단지 주석 : 템플릿 리터럴의 사용법을 설명하기 위해 두 줄의 주석을 사용합니다. 설명하는 것이 좋지만,' '('+ replacement + ')' '로 대체 할 수있을 때이 상황에서 사용하는 것은별로 의미가 없습니다. 스트레이트 문자열 연결을 사용하면 두 줄의 설명이 필요하고 Chrome> = ver로 코드를 제한하지 않았다고 느끼지 못할 것입니다. 41. – Makyen

+0

FYI : 현재 단어 목록을 반복하고 있습니다. 각각 단어 목록을 대체하고 있습니다. 하나만 사용할 수있는 경우 두 개의 다른 RegExp를 사용합니다 (존재 여부에 대한 테스트는 캡처 그룹에서 단어를 갖는 것에 신경 쓰지 않습니다). 단어 배열에있는 모든 단어를 포함하는 단일 RegExp를 미리 만드는 것이 훨씬 더 효율적입니다. 그렇게하면 모든 단어에 대해 단 하나의 .replace() 만 수행됩니다. 이렇게하면 내부 루프에 꽤 많은 시간을 절약 할 수 있습니다. [이 답변] (http://stackoverflow.com/a/40576258/3773011)이 일을 예를 들어있다. – Makyen

3

먼저 #text 노드를 테스트하여 강조 표시하려는 단어가 텍스트에 포함되어 있는지 확인한 다음 부모 요소의 .innerHTML에서 대체를 수행하십시오. 이 문제는 몇 가지 있습니다.

  • 무한 교체 : 상위 요소의 .innerHTML을 수정하면 childNodes 배열을 변경합니다. 바꿀 텍스트를 포함하는 배열에 노드를 더 추가 한 방식으로 그렇게합니다. 따라서 childNodes 배열을 계속 스캔하면 대체 할 텍스트가 포함 된 (새) 노드가 항상 있습니다. 따라서 다시 배열을 바꾸어 childNodes 배열에 더 높은 색인을 가진 다른 노드를 만듭니다. 무한히 반복하십시오.
  • RegExp를 사용하여 .innerHTML 속성의 텍스트를 바꿉니다. 이미 대체하려는 텍스트가 실제로 텍스트 노드에 포함되어 있는지 테스트 한 동안 RegExp가 에서 요소의 실제 HTML 내에서 일치하는 단어를 바꿀 수 있습니다 (예 : src="yourWord", href="http://foo.com/yourWord/bar.html", 또는 style, color, background, span, id, height, width, button, form, input 등 같은 단어를 강조하려는 경우).
  • <script> 또는 <style> 태그에서 텍스트를 변경하지 않는지 확인하지 않습니다.
  • 텍스트 노드에서만 변경했는지 확인하고 있습니다 (예 : node.nodeType === 3). 이 확인되지 않은 경우 당신은 또한 인해 HTML을 변경 .innerHTML을 사용하여 다음과 같은 문제가있을 것입니다 :
    • 당신은 당신이 .replace()으로 무엇을 변경하고 있는지에 따라 변화하는 속성, 또는 실제 HTML 태그를 끝낼 수 있었다. 이로 인해 페이지 레이아웃과 기능이 완전히 중단 될 수 있습니다.
    • .innerHTML을 변경하면 페이지의 해당 부분에 대한 DOM이 완전히 다시 작성됩니다. 즉, 요소는 새로운 요소가 동일한 특성을 가진 동일한 유형 일 수 있지만 이전 요소에 연결된 이벤트 리스너는 새 요소에 연결되지 않습니다. 이로 인해 페이지의 기능이 크게 손상 될 수 있습니다.
    • DOM의 많은 부분을 반복적으로 변경하면 페이지를 다시 렌더링하는 데 많은 노력이 필요할 수 있습니다. 이를 수행하는 방법에 따라 사용자가 인식하는 중요한 성능 문제가 발생할 수 있습니다.텍스트를 대체 할 정규식을 사용하려는 경우

따라서, 당신은하지 부모 노드의 .innerHTML에 만 #text 노드의 내용에 작업을 수행해야합니다. 추가 <span style=""> 요소 (어린이 #text 노드 포함)와 같은 추가 HTML 요소를 만들려고하기 때문에 몇 가지 문제가 있습니다. 텍스트 노드에 직접 새 HTML을 할당 할 방법이 없습니다

하고 새로운 노드를 생성, HTML로 평가가 있습니다

새로운 HTML 노드를 생성하는 텍스트 노드에 HTML 텍스트를 할당 할 수 없습니다. 텍스트 노드의 .innerHTML 속성에 할당하면 Object에 대한 속성과 마찬가지로 Object에 대한 속성이 만들어 지지만 화면에 표시된 텍스트 (즉, #text 노드의 실제 값)는 변경되지 않습니다. 따라서 부모 노드의 새로운 HTML 하위 항목을 만들지 않으려 고합니다.

페이지의 DOM에 미치는 영향이 가장 적은 (즉, 페이지에서 기존 JavaScript를 손상시키지 않는) 방법은 <span>을 작성하여 작성중인 새 텍스트 노드를 포함하는 것입니다 <span>에있는 #text 노드)와 작성중인 복수 <span> 요소가 있습니다. 이로 인해 단일 #text 노드가 단일 <span> 요소로 바뀝니다. 이렇게하면 추가 자손이 생성되지만 부모 요소에있는 자식 수는 변경되지 않습니다. 따라서, 의존하고있는 JavaScript는 영향을받지 않습니다. DOM을 변경했다는 것을 감안할 때 다른 JavaScript를 손상시키지 않는 방법은 없지만 그 가능성을 최소화해야합니다.

이 할 수있는 방법의 예 : this answer를 참조하십시오 및 this answer (장소 버튼으로 공백으로 분리 <p> 요소의 모든 텍스트) 정규식을 수행 전체 확장을 위해 (그 버튼 단어와 단어의 목록을 대체합니다) 새로운 HTML로 대체하십시오. 기본적으로 똑같은 일을하지만 (다른 두 예제에서 사용 된 NodeIterator 대신에 을 사용하여 DOM을 탐색하는 다른 구현이 있습니다) this answer을 참조하십시오. 이

: 여기

당신이 document.body에서 각 텍스트 노드에서 희망하는 교체를 수행하고 style 텍스트의 일부 다를 수있는 데 필요한 새로운 HTML을 생성하는 코드입니다 이 작업을 수행하는 다른 방법이 있습니다. 그러나 특정 요소 (예 : 부모의 여러 추가 노드)에 대한 하위 구조의 변경이 더 크게 나타날 것입니다. 이렇게하면 페이지의 현재 구조에 의존하는 페이지에 이미있는 JavaScript가 깨질 가능성이 높아집니다. 실제로 이와 같은 변경 사항은 현재 자바 스크립트를 깨뜨릴 가능성이 있습니다.

이 답변에 대한 코드는 this other answer of mine

+0

실제로 텍스트 노드가 포함 된 요소를 수정했기 때문에 이러한 유형의 오류가 발생하지 않았습니다. 내가 원하는 단어를 바꾼다면 괜찮 았는데 – rafaelcpalmeida

+0

@rafaelcpalmeida, 네, 문제의 한 부분을 묘사 할 때 오류가있었습니다. 문제의 수정 된 설명으로 답변을 업데이트했습니다 (해결책은 변경되지 않음). – Makyen