ホームページ > ウェブフロントエンド > htmlチュートリアル > シンプルな仮想 DOM 実装を最初から段階的に作成する 2: Props&Event処理_html/css_WEB-ITnose

シンプルな仮想 DOM 実装を最初から段階的に作成する 2: Props&Event処理_html/css_WEB-ITnose

WBOY
リリース: 2016-06-24 11:14:57
オリジナル
1067 人が閲覧しました

Props

まず最初に、上記の少し偏った点を確認する必要があります。JSX で最も単純な Div のみを記述するとします。

<div></div>
ログイン後にコピー

Babel は、JSX を次の DOM 式に自動的に変換します。 式:

{ type: ‘’, props: null, children: [] }
ログイン後にコピー

ここでの props はデフォルトでは null であることに注意してください。前の記事ではこの属性に注意を払いませんでした。この部分では、Virtual DOM での Props の使用法を説明します。一般的に言えば、どのようなプログラミング環境であっても、Null の発生を避けるように努めなければなりません。そのため、最初に h 関数を変換して、デフォルトで Null の代わりに空のオブジェクトを返せるようにします。 Props

React に触れたことのある学生は Props に精通しているはずです。Props の設定は、通常の HTML タグ属性を使用するのと非常に似ています:

function h(type, props, …children) { return { type, props: props || {}, children };}
ログイン後にコピー

そして、それは最終的に次の式に変換されます:

<ul className=”list” style=”list-style: none;”></ul>
ログイン後にコピー

各要素props オブジェクト キーは属性名、値は属性値です。一般に、必要なのは setAttribute メソッドを呼び出すだけで、Props のキーと値のペアを DOM 要素に設定します:

{  type: ‘ul’,  props: { className: ‘list’, style: ’list-style: none;’ }  children: []}
ログイン後にコピー

この関数。単一の Prop 値が DOM 要素に設定され、props オブジェクトについては、それを順番に走査するだけで済みます。

function setProp($target, name, value) { $target.setAttribute(name, value);}
ログイン後にコピー

要素の作成に使用される createElement メソッドを覚えておく必要があります。要素が正常に作成されるまで setProps メソッドを配置します。その後:

function setProps($target, props) { Object.keys(props).forEach(name => {   setProp($target, name, props[name]); });}
ログイン後にコピー

焦る必要はありません。それだけでは十分ではありません。 React の初心者向けチュートリアルでは、常に className と class の違いを強調してきました。 setProps では、次のような JS 予約語も置き換える必要があります。

function createElement(node) { if (typeof node === ‘string’) {   return document.createTextNode(node); } const $el = document.createElement(node.type); setProps($el, node.props); node.children   .map(createElement)   .forEach($el.appendChild.bind($el)); return $el;}
ログイン後にコピー

さらに、Processing of など、DOM のより一般的なブール属性もあります。チェック済み、無効化など:

<nav className=”navbar light”> <ul></ul></nav>
ログイン後にコピー

実際の DOM ノードでは、false が発生した場合、checked 属性が表示されることを望まないため、Props 関数はインテリジェントに判断できなければなりません:

<input type=”checkbox” checked={false} />
ログイン後にコピー

最後に、必要なことカスタムの非標準 HTML 属性をフィルタリングすることです。これらの属性は、実際の DOM オブジェクトではなく JS オブジェクトにのみ表示される必要があります:

function setBooleanProp($target, name, value) { if (value) {   $target.setAttribute(name, value);   $target[name] = true; } else {   $target[name] = false; }}
ログイン後にコピー
function isCustomProp(name) { return false;}
ログイン後にコピー

要約すると、この部分の完全な JSX コードは次のとおりです:

function setProp($target, name, value) { if (isCustomProp(name)) {   return; } else if (name === ‘className’) {   $target.setAttribute(‘class’, value); } else if (typeof value === ‘boolean’) {   setBooleanProp($target, name, value); } else {   $target.setAttribute(name, value); }}
ログイン後にコピー

Props: Props の比較比較の変更

Props 属性を持つ要素を作成したので、次に考慮すべきことは、上で中央で説明した Diff アルゴリズムを適用する方法です。まず、実際の DOM から特定の Props を削除する方法を検討する必要があります。

/** @jsx h */function h(type, props, ...children) {  return { type, props: props || {}, children };}function setBooleanProp($target, name, value) {  if (value) {    $target.setAttribute(name, value);    $target[name] = true;  } else {    $target[name] = false;  }}function isCustomProp(name) {  return false;}function setProp($target, name, value) {  if (isCustomProp(name)) {    return;  } else if (name === 'className') {    $target.setAttribute('class', value);  } else if (typeof value === 'boolean') {    setBooleanProp($target, name, value);  } else {    $target.setAttribute(name, value);  }}function setProps($target, props) {  Object.keys(props).forEach(name => {    setProp($target, name, props[name]);  });}function createElement(node) {  if (typeof node === 'string') {    return document.createTextNode(node);  }  const $el = document.createElement(node.type);  setProps($el, node.props);  node.children    .map(createElement)    .forEach($el.appendChild.bind($el));  return $el;}//--------------------------------------------------const f = (  <ul style="list-style: none;">    <li className="item">item 1</li>    <li className="item">      <input type="checkbox" checked={true} />      <input type="text" disabled={false} />    </li>  </ul>);const $root = document.getElementById('root');$root.appendChild(createElement(f));
ログイン後にコピー

次に、古いノードと新しいノードの Props の変更に従って、実際の DOM ノードに適切な変更を加える updateProp 関数を記述する必要があります。以下のタイプがあります。 状況:

    新しいノードが古いノードの Prop を削除した

    新しいノードが古いノードになかった Prop を追加した

    新しいものと古いもの ノードの特定の Prop の値 変更が発生しました

上記のルールによれば、Prop を更新する関数は次のとおりであることがわかります。

function removeBooleanProp($target, name) { $target.removeAttribute(name); $target[name] = false;}function removeProp($target, name, value) { if (isCustomProp(name)) {   return; } else if (name === ‘className’) {   $target.removeAttribute(‘class’); } else if (typeof value === ‘boolean’) {   removeBooleanProp($target, name); } else {   $target.removeAttribute(name); }}
ログイン後にコピー

を更新する関数であることがわかります。単一の Prop は依然として非常に単純です。つまり、削除と設定を組み合わせると、Props に展開され、次の関数が得られます:

function updateProp($target, name, newVal, oldVal) { if (!newVal) {   removeProp($target, name, oldVal); } else if (!oldVal || newVal !== oldVal) {   setProp($target, name, newVal); }}
ログイン後にコピー

同様に、updateElement 関数に update 関数を追加する必要があります:

function updateProps($target, newProps, oldProps = {}) {  const props = Object.assign({}, newProps, oldProps);  Object.keys(props).forEach(name => {    updateProp($target, name, newProps[name], oldProps[name]);  });}
ログイン後にコピー

Events

ユーザー操作はあらゆるアプリケーションに不可欠な部分であり、ここでは、仮想 DOM にイベント処理機能を追加する方法について説明します。おそらく React はこれを行うでしょう:

function updateElement($parent, newNode, oldNode, index = 0) {  ...  } else if (newNode.type) {    updateProps(      $parent.childNodes[index],      newNode.props,      oldNode.props    );     ...  }}
ログイン後にコピー

イベント ハンドラーを設定することは Prop を追加することであることがわかりますが、 name は on で始まり、次の関数を使用して、Prop がイベントに関連しているかどうかを判断できます:

<button onClick={() => alert(‘hi!’)}></button>
ログイン後にコピー

イベント タイプを決定した後、イベント名を抽出できます:

function isEventProp(name) { return /^on/.test(name);}
ログイン後にコピー

これを見て、直接配置することを検討できます。 setProps 関数と updateProps 関数のイベント処理ですが、ここで問題が発生します。 diffProps の場合、2 つの関数を比較するのは困難です:

したがって、すべてのイベント タイプ Props をカスタム Props としてみなします。上で述べたように、それは機能します:

function extractEventName(name) { return name.slice(2).toLowerCase();}
ログイン後にコピー

そして、イベント応答関数を実際の DOM ノードにバインドすることも非常に簡単です:

function isCustomProp(name) { return isEventProp(name);}
ログイン後にコピー

同じ関数を createElement に追加する必要があります:

function addEventListeners($target, props) { Object.keys(props).forEach(name => {   if (isEventProp(name)) {     $target.addEventListener(       extractEventName(name),       props[name]     );   } });}
ログイン後にコピー

イベントの再追加: イベントをリセットします応答

ここでは、現時点では複雑さは考慮しません。つまり、これらのイベント タイプの Prop の変更を詳細に比較することはありません。代わりに、DOM 全体を強制的に更新する ForceUpdate 属性を導入します。

function createElement(node) { if (typeof node === ‘string’) {   return document.createTextNode(node); } const $el = document.createElement(node.type); setProps($el, node.props); addEventListeners($el, node.props); node.children   .map(createElement)   .forEach($el.appendChild.bind($el)); return $el;}
ログイン後にコピー
function changed(node1, node2) { return typeof node1 !== typeof node2 ||        typeof node1 === ‘string’ && node1 !== node2 ||        node1.type !== node2.type ||        node.props.forceUpdate;}
ログイン後にコピー

最後に、この記事の完全な JSX は次のとおりです:

function isCustomProp(name) { return isEventProp(name) || name === ‘forceUpdate’;}
ログイン後にコピー

この時点で、最も単純な Virtual DOM アルゴリズムが完成しましたが、実際の戦闘に使用できる Virtual DOM アルゴリズムにはまだ程遠いです。 :

  • 徹底した分析: 仮想 DOM アルゴリズムの実装方法

  • 私のフロントエンド ストーリー ----React アルゴリズムとは一体何ですか? !

  • 仮想 DOM と差分アルゴリズム: 比較的複雑な仮想 DOM アルゴリズムの実装

  • simple-virtual-dom: 仮想 DOM の単純な実装

  • how-to-write-your-own - virtual-dom

  • 仮想 DOM ベンチマーク

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート