virtualDOM (VNode 仮想 DOM)

目次

分析する

一連の考え

模範解答

I.はじめに

二、レンダリング機能

3. レンダリング機能の適用

4. 詳細データ オブジェクト

6. まとめ

述べる

分析する

ほとんどすべての既存のフレームワークは、現在 VNode および VDOM として知られている実際の DOM を抽象化するために仮想 DOM を導入していますが、なぜ仮想 DOM を導入する必要があるのでしょうか? この質問に答えましょう!

一連の考え

  1. vdomとは何ですか
  2. vdom導入のメリット
  3. vdom の生成方法と dom になる方法
  4. その後の差分での役割

模範解答

  1. 名前が示すように、仮想 dom は仮想 dom オブジェクトであり、それ JavaScript 自体がオブジェクトですが、さまざまな属性を通じてビュー構造を記述します。

  2. vdom を導入することで、次の利点が得られます。

    実際の要素ノードを VNode に抽象化し、直接操作の dom の数を効果的に減らし、それによってプログラムのパフォーマンスを向上させます。

    • DOM の直接操作は、次のように制限されています: diff、clone およびその他の操作. 実際の要素には多くのコンテンツがあります. 直接 diff 操作を実行すると、不要なコンテンツが diff に追加されます. 同様に、必要な場合clone その場合、その内容をすべてコピーする必要はありません。しかし、これらの操作を JavaScript のオブジェクトに移せば簡単になります。
    • dom の操作は比較的高価な操作です. 頻繁な dom 操作はページの再描画とリフローを引き起こす可能性があります. しかし, 抽象 VNode による中間処理は直接 dom 操作の数を効果的に減らすことができます.

    クロスプラットフォームを簡単に実現

    • 同じ VNode ノードを異なるプラットフォームで対応するコンテンツにレンダリングできます。たとえば、レンダリングはブラウザーの dom 要素ノードであり、レンダリングはネイティブ (iOS、Android) で対応するコントロールになり、SSR を実現し、WebGL にレンダリングできます。
    • Vue3 を使用すると、開発者は VNode に基づいてカスタム レンダラー (レンダラー) を実装して、さまざまなプラットフォームのレンダリングを容易にすることができます。
    • vdom はどのように生成されますか? In vue, we often write templates for components - templates. このテンプレートはコンパイラーによってレンダリング関数にコンパイルされます - コンパイラー. レンダリング関数は次のマウントプロセス中に呼び出され、返されるオブジェクトは仮想 DOM です. しかし、それらはまだ実際の dom ではないため、その後のパッチ プロセスでさらに dom に変換されます。

 レンダリング機能の詳細は以下のとおりです

  4. マウント プロセスが終了すると、vue プログラムは更新プロセスに入ります。一部のレスポンシブ データが変更されると、コンポーネントが再レンダリングされます. このとき、新しい vdom が生成され、最後のレンダリング結果の diff は変更された場所を取得できるため、最小量に変換されます。 dom 操作の効率的なビューの更新。

I.はじめに

Render 関数は Vue2.x の新しい関数で、主にノードのレンダリング パフォーマンスを向上させるために使用されます. JavaScript の計算に基づいています. Render 関数を使用して、テンプレート内のノードを仮想 Dom に解析します。

Vue は、ほとんどの場合、テンプレートを使用して HTML を作成することを推奨しています。ただし、一部のシナリオでは、JavaScript の完全なプログラミング機能が必要になります。このとき、テンプレートよりもコンパイラに近いレンダリング関数 render を使用できます。

レンダリング機能に入る前に、ブラウザーの仕組みについて少し理解しておくことが重要です。例として、次の HTML を取り上げます。

<div>
  <h1>My title</h1>
  Some text content
  <!-- TODO: Add tagline -->
</div>

ブラウザーがこのコードを解析すると、家族のメンバーの成長を追跡するために家系図を描くのと同じように、DOM ノードのツリーを構築することによってすべてを追跡します。

上記の HTML に対応する DOM ノード ツリーを次の図に示します。

 各要素はノードです。各テキストもノードです。コメントもノードです。ノードはページのセクションです。ファミリー ツリーと同様に、各ノードには子を含めることができます (つまり、各セクションに他のセクションを含めることができます)。

これらすべてのノードを効率的に更新するのは難しい場合がありますが、幸い手動で行う必要はありません。ページの HTML をどうしたいかを Vue に伝える必要があるだけです。これはテンプレートに含めることができます。

<h1>{
   
   { blogTitle }}</h1>

またはレンダリング関数で:

render: function (createElement) {
  return createElement('h1', this.blogTitle)
}

どちらの場合も、blogTitle が変更されても、Vue はページを自動的に更新し続けます。

Vue は、仮想 DOM を構築することによって実際の DOM をどのように変更するかを追跡します。次のコード行を注意深く見てください。

return createElement('h1', this.blogTitle)

createElement は正確に何を返しますか? 実際には、実際の DOM 要素ではありません。そのより正確な名前は createNodeDescription かもしれません。これに含まれる情報は、子ノードの説明情報を含め、ページにレンダリングする必要があるノードの種類を Vue に伝えるためです。このようなノードを「仮想ノード(仮想ノード)」と呼び、「VNode」と略すことが多いです。「仮想 DOM」は、Vue コンポーネント ツリーから構築された VNode ツリー全体と呼ばれるものです

二、レンダリング機能

簡単に言えば、vue ではテンプレート HTML 構文を使用してページを構築し、render 関数を使用して js 言語で DOM を構築します。

vue は仮想 DOM であるため、テンプレート テンプレートを取得するときに VNode 関数に変換する必要があり、render 関数を使用して DOM を構築するときに、vue は変換プロセスを排除します。

render 関数を使用して仮想 DOM を記述する場合、vue は仮想 DOM を構築するために必要なツールである関数を提供します。公式 Web サイトの名前は createElement です。合意された省略形 h もあります。h を createElement のエイリアスとして使用することは、Vue エコシステムの一般的な方法であり、実際に JSX で必要とされます。

vm にはメソッド _c があり、これもこの関数のエイリアスです。

createElement の公式 Web サイトの紹介を最初に見てください。

// @returns {VNode}
createElement(
  // {String | Object | Function}
  // 一个 HTML 标签字符串,组件选项对象,或者解析上述任何一种的一个 async 异步函数,必要参数。
  'div',

  // {Object}
  // 一个包含模板相关属性的数据对象
  // 这样,您可以在 template 中使用这些属性。可选参数。
  {
    // (详情见下一节)
  },

  // {String | Array}
  // 子节点 (VNodes),由 `createElement()` 构建而成,或使用字符串来生成“文本节点”。可选参数。组件树中的所有 VNode 必须是唯一的。
  [
    '先写一些文字',
    createElement('h1', '一则头条'),
    createElement(MyComponent, {
      props: {
        someProp: 'foobar'
      }
    })
  ]
)

つまり、createElement(params1, params2, params3) は 3 つのパラメーターを受け取り、各パラメーターの型は公式の紹介で説明されています。

3. レンダリング機能の適用

render:(h) => {
    return h('div',{ //给div绑定value属性
       props: {
           value:''
       }, 
       //给div绑定样式
       style:{
           width:'30px'                                                                                   
       }, 
       //给div绑定点击事件  
       on: {
           click: () => {
               console.log('点击事件')
           }
       },
   })
}

4. 詳細データ オブジェクト

1 つ注意してください: v-bind:class と v-bind:style がテンプレート構文で特別に扱われるのと同様に、VNode データ オブジェクトにも対応する最上位フィールドがあります。このオブジェクトを使用すると、通常の HTML 属性だけでなく、innerHTML などの DOM プロパティをバインドすることもできます (これは v-html ディレクティブをオーバーライドします)。

{
  // 与 `v-bind:class` 的 API 相同,
  // 接受一个字符串、对象或字符串和对象组成的数组
  'class': {
    foo: true,
    bar: false
  },
  // 与 `v-bind:style` 的 API 相同,
  // 接受一个字符串、对象,或对象组成的数组
  style: {
    color: 'red',
    fontSize: '14px'
  },
  // 普通的 HTML attribute
  attrs: {
    id: 'foo'
  },
  // 组件 prop
  props: {
    myProp: 'bar'
  },
  // DOM property
  domProps: {
    innerHTML: 'baz'
  },
  // 事件监听器在 `on` 内,
  // 但不再支持如 `v-on:keyup.enter` 这样的修饰器。
  // 需要在处理函数中手动检查 keyCode。
  on: {
    click: this.clickHandler
  },
  // 仅用于组件,用于监听原生事件,而不是组件内部使用
  // `vm.$emit` 触发的事件。
  nativeOn: {
    click: this.nativeClickHandler
  },
  // 自定义指令。注意,你无法对 `binding` 中的 `oldValue`
  // 赋值,因为 Vue 已经自动为你进行了同步。
  directives: [
    {
      name: 'my-custom-directive',
      value: '2',
      expression: '1 + 1',
      arg: 'foo',
      modifiers: {
        bar: true
      }
    }
  ],
  // 作用域插槽的格式为
  // { name: props => VNode | Array<VNode> }
  scopedSlots: {
    default: props => createElement('span', props.text)
  },
  // 如果组件是其它组件的子组件,需为插槽指定名称
  slot: 'name-of-slot',
  // 其它特殊顶层 property
  key: 'myKey',
  ref: 'myRef',
  // 如果你在渲染函数中给多个元素都应用了相同的 ref 名,
  // 那么 `$refs.myRef` 会变成一个数组。
  refInFor: true
}


5. 適用例
公式ウェブサイトの例を例にとると、このコンポーネントは、親コンポーネントから渡されたレベルに応じて、h1 または h6 をレンダリングできます。コードは次のとおりです。

<template>  
<div>
  <h1 v-if="level === 1">
    <slot></slot>
  </h1>
  <h2 v-else-if="level === 2">
    <slot></slot>
  </h2>
  <h3 v-else-if="level === 3">
    <slot></slot>
  </h3>
  <h4 v-else-if="level === 4">
    <slot></slot>
  </h4>
  <h5 v-else-if="level === 5">
    <slot></slot>
  </h5>
  <h6 v-else-if="level === 6">
    <slot></slot>
  </h6>
</div>
</template>
 
<script>
export defalut {
  // 接收父组件传来的 level
  props: {
    level: {
      type: Number,
      required: true
    }
  }
}
</script>

実際、そのようなアプリケーション シナリオは多くありませんが、遭遇することもあります.たとえば、現在、1、2、3、4、5、および 6 で表される 6 つの異なる状態があります。これらの状態を介して異なる画像を表示したいのですが、背景が画像のアドレスを返さず、状態に対応する番号のみを返す場合 (画像がローカルに配置されている場合) は、render 関数を使用するのが適切です (前提は州はたくさんありますが、2 つまたは 3 つでも構いません。上)。render 関数を使用して上記のコンポーネントを書き直してみましょう。

export default {
  render: function (createElement) {    // createElement可以写成h,这是公认写法
    // createElement 是 render 函数的参数,它本身也是个函数,并且有三个参数。
    
    /*
    这里说明它的三个参数:
    1、一个 HTML 标签字符串,组件选项对象,或者解析上述任何一种的一个 async 异步函数。类型:{String | Object | Function}。必需。
    2、一个包含模板相关属性的数据对象你可以在 template 中使用这些特性。类型:{Object}。可选。
    3、子虚拟节点 (VNodes),由 createElement() 构建而成,也可以使用字符串来生成“文本虚拟节点”。类型:{String | Array}。可选。
    */
    return createElement(
       // 参数1、标签名称,父组件传几,我这就是h几,不用再template上面加if,else了是不是很简洁实用?(必填)
      'h' + this.level, 
       // 参数2、这里相当于给标签加属性 例如:<div class='foo' style='color:red,font-size: 14px'></div>(可选)
      {
          // 与 `v-bind:class` 的 API 相同,
          // 接受一个字符串、对象或字符串和对象组成的数组
          'class': {
            foo: true,
            bar: false
          },
          // 与 `v-bind:style` 的 API 相同,
          // 接受一个字符串、对象,或对象组成的数组
          style: {
            color: 'red',
            fontSize: '14px'
          },
      },
      // 参数3、参数中渲染的标签子元素数组(可选)
      [
           'text',   // 文本节点直接写就可以
           _this.$slots.default,  // 所有不具名插槽,是个数组
           createElement('div', _header)   // createElement()创建的VNodes
      ]
    )
  },
  // 接收父组件传来的 level
  props: {
    level: {
      type: Number,
      required: true
    }
  }
}

6. まとめ

render メソッドの本質は、テンプレート テンプレートを生成することです。
メソッドを呼び出すことによって生成され、このメソッドは render メソッドのパラメータを介して渡されます。
このメソッドには、タグ名、タグ関連を提供する 3 つのパラメータがあります。属性、および タグ内の HTML コンテンツ ;
これら 3 つのパラメータを使用して、完全なテンプレートを生成できます。

述べる:

render メソッドは JSX 構文を使用できますが、Babel プラグインが必要です;
render メソッドの 3 番目のパラメータは、関数を使用して複数のコンポーネントを生成できます (特にそれらが同じ場合)。ただし、生成された結果が配列であり、配列要素は単なる VNode です。

おすすめ

転載: blog.csdn.net/csdssdn/article/details/125511176