프레임워크가 없는 클라이언트 JavaScript 데이터 바인딩

최근에 나는 줄곧 순수한 JavaScript의 기능을 생각하고 있다.이것은 지난 몇 년 동안 장족하게 발전한 언어다.모듈 캐리어 같은 유행하는 라이브러리와 프레임워크 (예: Angular, Vue.js, React) 를 많이 만들어서 원시적인 시대에 뒤떨어진 실현에 존재하는 결함과 격차를 해결했습니다.ECMAScript 6 / 2015이 있어서 나는 대부분의 제한이 사라졌다고 믿는다.다음과 같은 주요 기능이 이미 제공됩니다.
  • 지지modules 및 동적 하중
  • 노선 차단 및 관리 능력
  • 내장형DOM query mechanism 1개, jQuery
  • 불필요
  • 로컬 template 지원
  • 재사용 가능web components
  • 나는 과거에 현대 웹 개발에 관한 "3D"를 쓴 적이 있다.
    The Three D’s of Modern Web Development

    주입, 성명성 문법과 데이터 귀속에 의존하는 학습을 통해Angular,React,Vue 등 현대 자바스크립트 프레임워크의 역사를 이해하고 분해한다.
    최신 JavaScript 버전의 이 컴퓨터가 완전히 지원하지 않는 기능 중 하나는 데이터 바인딩입니다.하지만 실행하기가 얼마나 어려운가?만약 당신이 중형 프레임워크를 사용하는 유일한 동기가 데이터 귀속 지원이라면, 당신은 놀랄 수도 있습니다!우리 소매를 말아 봅시다.

    변화를 관찰하다


    우선 변화를 관찰하는 능력이 필요하다.이것은 Observable류를 통해 실현하기 쉽다.반 전체가 세 가지 일을 해야 한다.
  • 추적값
  • 수신기 구독 변경 허용
  • 값이 변할 때 알림 탐지기
  • 다음은 간단한 실현이다.
    class Observable {
       constructor(value) {
          this._listeners = [];
          this._value = value;
       }
       notify() {
          this._listeners.forEach(listener => listener(this._value));
       }
       subscribe(listener) {
          this._listeners.push(listener);
       }
       get value() {
          return this._value;
       }
       set value(val) {
          if (val !== this._value) {
             this._value = val;
             this.notify();
          }
       }
    }
    
    
    이 간단한 클래스는 내장된 클래스 지원을 이용한다TypeScript모든 것을 잘 처리하다.다음은 우리가 사용하고 있는 새로운 클래스의 예입니다. 이 클래스는 관찰할 수 있는 변경 사항을 만들고 컨트롤러에 로그아웃합니다.
    const name = new Observable("Jeremy");
    name.subscribe((newVal) => console.log(`Name changed to ${newVal}`));
    name.value = "Doreen";
    // logs "Name changed to Doreen" to the console
    
    
    이것은 매우 쉽지만, 계산 값은?예를 들어, 여러 입력에 의존하는 출력 속성이 있을 수 있습니다.전체 이름에 속성을 공개하기 위해 이름과 성을 추적해야 한다고 가정해 보세요.이게 어떻게 된 일입니까?

    계산 값("관찰 가능한 체인")


    상속에 대한 JavaScript 지원이 있으면 클래스를 확장하여 계산 값을 처리할 수 있습니다.이 반은 약간의 추가 일을 해야 한다.
  • 새로운 속성을 계산하는 함수 추적
  • 관련성, 즉 계산 속성에 의존하는 관찰 속성
  • 구독 의존 관계의 변경으로 계산된 속성을 재평가할 수 있음
  • 이 클래스는 더욱 쉽게 실현될 수 있다.
    class Computed extends Observable {
       constructor(value, deps) {
          super(value());
          const listener = () => {
             this._value = value();
             this.notify();
          }
          deps.forEach(dep => dep.subscribe(listener));
       }
       get value() {
          return this._value;
       }
       set value(_) {
          throw "Cannot set computed property";
       }
    }
    
    
    이것은 함수와 의존항을 가져오고 초기 값에 피드를 설정합니다.그것은 관련 변경 사항을 정탐하고 계산 값을 재평가한다.마지막으로, 이것은 읽기만 하기 때문에, 이상을 일으키기 위해 setter를 다시 쓴다.여기서 사용:
    const first = new Observable("Jeremy");
    const last = new Observable("Likness");
    const full = new Computed(
       () => `${first.value} ${last.value}`.trim(), 
       [first, last]);
    first.value = "Doreen";
    console.log(full.value);
    // logs "Doreen Likness" to the console
    
    
    이제 우리는 데이터를 추적할 수 있지만, HTML DOM은?

    양방향 데이터 바인딩


    양방향 데이터 바인딩의 경우 관찰된 값으로 DOM 속성을 초기화하고 값이 변경될 때 업데이트해야 합니다.새 값을 데이터에 중계하기 위해 DOM이 언제 업데이트되는지 확인해야 합니다.내장된 DOM 이벤트를 사용하여 입력 요소를 사용하여 양방향 데이터 바인딩을 설정하는 코드입니다.
    const bindValue = (input, observable) => {
       input.value = observable.value;
       observable.subscribe(
          () => input.value = observable.value);
       input.onkeyup = () => observable.value = input.value;
    }
    
    
    어렵지 않을 것 같은데, 그래요?만약 내가 입력 요소가 하나 있다면, 그 Observable 속성은 id 로 설정되어 있으며, 나는 그것을 이렇게 연결할 수 있다.
    const first = new Observable("Jeremy");
    const firstInp = document.getElementById("first");
    bindValue(firstInp, first);
    
    
    다른 값의 경우 이 작업을 반복할 수 있습니다.

    Tip: This is, of course, a simple example. You may have to convert values if you are expecting numeric inputs and write different handlers for elements like radio lists, but the general concept remains the same.


    "3D"로 돌아가서 코드 숨김과 데이터 연결을 성명 방식으로 최소화할 수 있다면 좋은 일입니다.탐색해 봅시다.

    성명성 데이터 귀속


    목표는 원소의 id에 따라 원소를 불러와야 하는 것을 피하고 관찰할 수 있는 대상에 직접 연결시키는 것이다.나는 작업에 대한 설명적 속성을 선택하고 이름을 first 로 지었다.나는 하나의 값으로 속성을 선언합니다. 이 값은 상하문의 속성을 가리키기 때문에 다음과 같이 보입니다.
    <label for="firstName">
       <div>First Name:</div>
       <input type="text" data-bind="first" id="firstName" />
    </label>
    
    연결을 위해 나는 기존의 data-bind 를 다시 사용하여 실현할 수 있다.우선, 나는 귀속할 상하문을 설정했다.그리고 상하문을 설정하고 귀속을 적용합니다.
    const bindings = {};
    const app = () => {
       bindings.first = new Observable("Jeremy");
       bindings.last = new Observable("");
       bindings.full = new Computed(() =>
          `${bindings.first.value} ${bindings.last.value}`.trim(),
          [bindings.first, bindings.last]);
       applyBindings();
    };
    setTimeout(app, 0);
    
    
    dataBind 는 초기 렌더링 주기를 완료합니다.이제 나는 설명을 해석하고 코드를 연결했다.
    const applyBindings = () => {
       document.querySelectorAll("[data-bind]").forEach(elem => {
          const obs = bindings[elem.getAttribute("data-bind")];
          bindValue(elem, obs);
       });
    };
    
    
    코드는 setTimeout 속성이 있는 모든 태그를 가져와 색인으로 상하문의 관찰 가능한 항목을 인용한 다음 data-bind 동작을 호출합니다.
    그렇습니다.우리 끝났어.Click here 전체 코드 예시를 엽니다.

    참고: 평가 배경


    데이터 귀속은 항상 관찰 가능한 대상의 이름을 가리키는 것처럼 간단하지 않다.많은 경우, 계산 표현식이 필요할 수도 있습니다.만약 상하문을 구속할 수 있다면, 표현식이 다른 표현식에 충돌하거나 안전하지 않은 조작을 하지 않도록 할 수 있다면 매우 좋다.이것도 가능하다.표현식 고려dataBind.컨텍스트에서 구속할 수 있는 몇 가지 방법우선, 가장 안전하지 않은 것은 특정 환경에서 사용하는 것이다a+b.예제 코드는 다음과 같습니다.
    const strToEval = "this.x = this.a + this.b";
    const context1 = { a: 1, b: 2 };
    const context2 = { a: 3, b: 5 };
    const showContext = ctx =>
       console.log(`x=${ctx.x}, a=${ctx.a}, b=${ctx.b}`);
    const evalInContext = (str, ctx) =>
       (function (js) { return eval(js); }).call(ctx, str);
    showContext(context1);
    // x=undefined, a=1, b=2
    showContext(context2);
    // x=undefined, a=3, b=5
    evalInContext(strToEval, context1);
    evalInContext(strToEval, context2);
    showContext(context1);
    // x=3, a=1, b=2
    showContext(context2);
    // x=8, a=3, b=5
    
    
    이것은 상하문에 변이를 허용하지만, 몇 가지 결함이 있다.사용eval의 약속은 어색하고 잠재적인 안전 결함이 많다.this문장만 추가하면 알 수 있습니다.더 안전한 방법은 값의 구값만 되돌려 주고 동적 함수에 포장하는 것이다.다음 코드는 네비게이션 부작용 없이 이 기능을 실현했다.
    const strToEval = "a + b; window.location.href='https://blog.jeremylikness.com/';";
    const context1 = { a: 1, b: 2 };
    const context2 = { a: 3, b: 5 };
    const evalInContext = (str, ctx) => 
       (new Function(`with(this) { return ${str} }`)).call(ctx);
    console.log(evalInContext(strToEval, context1));
    // 3
    console.log(evalInContext(strToEval, context2));
    // 8
    
    
    이 작은 기교를 사용하면 특정 상하문에서 안전하게 표현식을 계산할 수 있습니다.

    결론


    나는 틀에 반대하지 않는다.나는 믿을 수 없는 대형 기업의 웹 응용 프로그램을 구축했다. 이런 응용 프로그램의 성공은 어느 정도에 우리가 Angular 등 프레임워크를 사용하는 것에서 얻은 장점 덕분이다.그러나 중요한 것은 이 기계의 최신 진전을 따라가는 것이다. 틀을 모든 문제를 해결할 수 있는 황금 도구로 여기지 마라.프레임워크에 의존하는 것은 설정, 설정과 유지보수를 통해 자신의 비용, 위험 안전 결함을 폭로하고 많은 상황에서 대형 유효 부하를 배치하는 것을 의미한다.너는 이 틀의 미세한 차이에 익숙한 인재를 고용하거나 그들을 훈련시켜 갱신을 따라가야 한다.본 컴퓨터의 코드를 이해하면 하나의 구축 과정만 절약할 수 있고 현대 브라우저에서 대량의 코드가 필요하지 않고'일만 한다'는 장면을 사용할 수 있습니다.
    예전과 같이, 나는 당신의 피드백, 생각, 평론과 문제를 환영합니다.
    ... 로 여기다

    좋은 웹페이지 즐겨찾기