1

innerHTML을 사용하여 모든 노드에 설정된 값을 즉시 변경해야합니다.즉석에서 innerHTML 설정 변경

... 
Object.defineProperty(Element.prototype, 'innerHTML', { 
    set: function() { 
     // get value (ok) 
     var value = arguments[0]; 
     // change it (ok) 
     var new_value = my_function(value); 
     // set it (problem) 
     this.innerHTML = new_value;    // LOOP 
    } 
} 
... 

그러나 분명히 무한 루프입니다 :

내가 찾은 가장 가까운 솔루션입니다. 원래 innerHTML 세트를 호출하는 방법이 있습니까?

나는 또한 Proxy way을 시도하지만 제대로 작동하지 않을 수 있습니다.

자세한 내용 : 내가 그렇게 생성하고 웹 사이트에 CSP 정책을 추가하는 리버스 프록시를 사용하는 실험 프로젝트, 일하고

:

  • 웹 사이트의 소유자가 될 것입니다 이러한 인식
  • 내가 정책을 트리거 할 수 생성 된 JS 코드 클라이언트를 처리하는 데 필요한 " 덮어 쓰기"
  • 콘텐츠 보안 정책 엔진 평가 전에 수정해야합니다!

답변

3

필수 경고 : Element.prototype의 속성에 대한 세터와 게터 재정 는 모든 생산 수준 코드의 나쁜 생각 수밖에 없다. innerHTML에 의존하는 라이브러리를 사용해야하거나 이러한 변경 사항을 알지 못하는 다른 개발자가 프로젝트에있는 경우 이상한 점이있을 수 있습니다. 또한 앱의 다른 부분에서 innerHTML을 "일반적으로"사용할 수있는 기능이 없어집니다.

에 대한 정보를 아직 제공하지 않으 셨으므로을 사용하시는 것이 좋을 것이라고 생각합니다. 사용자가주의 사항을 알고 있고 브라우저 자체의 기능을 재정의하려고한다고 가정합니다. 아마도 개발 목적으로.


솔루션 : 당신은 Element.prototype.innerHTML에 대한 브라우저의 기본 세터를 무시하는,하지만 당신은 또한 당신의 목표를 달성하기 위해 원래 세터가 필요합니다. 이는 Object.getOwnPropertyDescriptor을 사용하여 수행 할 수 있으며, 이는 Object.defineProperty의 '대응 항목'입니다.

(function() { 
 
    
 
    //Store the original "hidden" getter and setter functions from Element.prototype 
 
    //using Object.getOwnPropertyDescriptor 
 
    var originalSet = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML').set; 
 
    
 
    Object.defineProperty(Element.prototype, 'innerHTML', { 
 
    set: function (value) { 
 
     // change it (ok) 
 
     var new_value = my_function(value); 
 
     
 
     //Call the original setter 
 
     return originalSet.call(this, new_value); 
 
    } 
 
    }); 
 
         
 
    function my_function(value) { 
 
    //Do whatever you want here 
 
    return value + ' World!'; 
 
    } 
 
         
 
})(); 
 

 

 
//Test 
 
document.getElementById('test').innerHTML = 'Hello';
<div id="test"></div>

+0

새 게터를 정의 할 필요가 없습니다. 이전 게터를 사용하도록 할 수 있습니다. – Oriol

+0

@Oriol 사실, 대답을 편집했습니다. 팁 고마워. – noppa

+0

좋은 답변입니다! 그러나이 전략은 Safari에서는 작동하지 않습니다. 왜냐하면'innerHTML'을 구성 할 수 없게 구현하기 때문입니다. –

1

아니, 임의의 HTML 문자열이 작업을 수행 할 간단한 방법이 없습니다 (이이 "비를 너무 좋아"솔루션을 필요로하는 주요 문제이다).

문제는 임의의 HTML 문자열을 사용하고 있다는 것입니다. 현재 임의의 HTML을 요소에 설정하는 유일한 방법은 innerHTML입니다. 당신은 임시 노드에 HTML을 추가하고 그 내용을 잡아 예를 들어, 요소에 임의의 HTML을 설정하는 다른 방법을 찾아야 할 것 :

// Attempt: build a temporary element, append the HTML to it, 
    // then grab the contents 
    var div = document.createElement('div'); 
    div.innerHTML = new_value; 
    var elements = div.childNodes; 

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

그러나이 같은 문제를 겪고을 div.innerHTML = new_value; 영원히 때문에 재귀 적 당신은 임의의 HTML 설정에 대한 유일한 진입 점을 수정하고 있습니다.

내가 생각할 수있는 유일한 해결책은 임의의 HTML 문자열을 받아 document.createElement('p') 등의 DOM 노드로 바꿀 수있는 사실적이고 완벽한 HTML 파서를 구현하는 것입니다. 그러면 appendChild으로 현재 요소에 추가 할 수 있습니다. . 그러나 그것은 끔찍하고 과장된 해결책 일 것입니다.

제쳐두고이 작업을해서는 안됩니다.이 코드는 누군가의 일을 망칠 것입니다. 프런트 엔드 개발에서 알게 된 몇 가지 원칙을 위반합니다.

  • 기본 객체 프로토 타입을 수정하지 마십시오.이 코드를 실행하거나 동일한 페이지 (예 : 타사 추적 라이브러리)에서 코드를 실행하는 사용자는 그 아래에서 깔개를 꺼냅니다. 무슨 일이 일어나고 있는지 추적하는 것은 거의 불가능할 것입니다. 아무도 도둑 맞으려고 innerHTML을 찾지 않을 것입니다.
  • 일반적으로 세터는 계산 된 속성 또는 부작용이있는 속성 용입니다. 당신은 값을 공중 납치하고 그것을 바꾸고 있습니다. 당신은 위생 문제에 직면 해 있습니다. 누군가가 이미 도용당한 값을 다시 설정하면 어떻게 될까요?
  • 까다로운 코드를 작성하지 마십시오.이 코드는 분명히 "까다로운"해결책입니다.

어디서나 가장 깨끗한 해결책은 단지 my_function 일 것입니다. 그것은 짧은 읽을 수있어, 간단한, 바닐라 프로그래밍 :

someElement.innerHTML = my_function(value); 

당신은 대안 방법을 정의 할 수처럼 (이 사용자로부터 값을 내리 쳤을 때부터 부동산을 통해 방법을 할 것) :

Element.prototype.setUpdatedHTML = function(html) { 
    this.innerHTML = my_function(html); 
} 

이 방법은 개발자가 setUpdatedHTML을 통과 할 때 분명히 비표준 일 것이고 요소 프로토 타입을 더 쉽게 가로 채는 사람을 찾을 수 있습니다.

+0

I 때문에 "자세한 내용"섹션에서 추가 한 이유, 당신이 말에 동의하지만, 나는 새로운 방법 (나는 종종 그 코드를 제어하지 않음) 및 개발자를 정의 할 수 없습니다 이 "_overwrites_"을 알게 될 것입니다. –