ホームページ ウェブフロントエンド フロントエンドQ&A vue の上位コンポーネントとは何ですか?

vue の上位コンポーネントとは何ですか?

Dec 20, 2022 pm 01:24 PM
vue の高次コンポーネント

vue では、高階コンポーネントは実際には高階関数、つまりコンポーネント関数を返す関数です。高次コンポーネントの特徴: 1. 副作用のない純粋な関数であり、元のコンポーネントを変更する必要はありません、つまり、元のコンポーネントを変更することはできません; 2. データ (props) を考慮しません。渡され、新しく生成されたコンポーネントはデータのソースを気にしません。 ; 3. 受け取った props はパッケージ化されたコンポーネントに渡される必要があります。つまり、元のコンポーネント props はパッケージ化コンポーネントに直接渡されます。 4. 高-オーダーコンポーネントは、プロパティを完全に追加、削除、変更できます。

vue の上位コンポーネントとは何ですか?

#このチュートリアルの動作環境: Windows7 システム、vue3 バージョン、DELL G3 コンピューター。

高次コンポーネントの概要

vue 高次コンポーネントの理解。React ではコンポーネントは再利用されたコードで実装されますが、Vue ではミックスインで実装されます。また、Vue で高次コンポーネントを実装するのは難しく、React ほど単純ではないため、公式ドキュメントには高次コンポーネントの概念がいくつか欠けています。実際、Vue のミックスインもミックスインに置き換えられます。ソースコードを見ると、Vue についての理解が深まります理解

いわゆる高階コンポーネントは、実際には高階関数、つまりコンポーネント関数を返す関数です。 Vueで?上位コンポーネントには次の特性があることに注意してください。

高阶组件(HOC)应该是无副作用的纯函数,且不应该修改原组件,即原组件不能有变动
高阶组件(HOC)不关心你传递的数据(props)是什么,并且新生成组件不关心数据来源
高阶组件(HOC)接收到的 props 应该传递给被包装组件即直接将原组件prop传给包装组件
高阶组件完全可以添加、删除、修改 props
ログイン後にコピー
上位コンポーネントの例

Base.vue

<template>
  <div>
    <p @click="Click">props: {{test}}</p>
  </div>
</template>
<script>
export default {
  name: 'Base',
  props: {
    test: Number
  },
  methods: {
    Click () {
      this.$emit('Base-click')
    }
  }
}
</script>
ログイン後にコピー
Vue コンポーネントには主に props、event、および 3 つのポイントがあります。スロット。 Base コンポーネント コンポーネントの場合、数値型のプロパティ (つまり test) を受け取り、カスタム イベントをトリガーします。イベントの名前は、Base-click (スロットなし) です。コンポーネントを次のように使用します:

次に、マウントされるたびに「笑」という文を出力するためのベースコンポーネントコンポーネントが必要です。同時に、これは多くのコンポーネントの要件である可能性があります。 mixins メソッドに従って、これを行うことができます。最初に mixins

export default consoleMixin {
  mounted () {
    console.log('haha')
  }
}
ログイン後にコピー
を定義し、次に Base コンポーネントで consoleMixin をミックスします。

<template>
  <div>
    <p @click="Click">props: {{test}}</p>
  </div>
</template>
<script>
export default {
  name: 'Base',
  props: {
    test: Number
  },
  mixins: [ consoleMixin ],
  methods: {
    Click () {
      this.$emit('Base-click')
    }
  }
}
</script>
ログイン後にコピー
Base コンポーネントをこのように使用する場合、ははは各実装が完了するとメッセージが出力されますが、今度は同じ機能を実現するために高次コンポーネントを使用します。高次コンポーネントの定義を思い出してください。コンポーネントをパラメータとして受け取り、新しいコンポーネントを返します。では、現時点で考えなければならないのは、Vue のコンポーネントとは何なのかということです。 Vue のコンポーネントは関数ですが、それは最終結果です。たとえば、単一ファイル コンポーネントのコンポーネント定義は、実際には次のような通常のオプション オブジェクトです:

export default {
  name: 'Base',
  props: {...},
  mixins: [...]
  methods: {...}
}
ログイン後にコピー
これは純粋なオブジェクトではありませんか?

import Base from './Base.vue'
console.log(Base)
ログイン後にコピー
Base とは何ですか? これは JSON オブジェクトです。これをコンポーネントのコンポーネントに追加すると、Vu は最終的にこのパラメーター (つまりオプション) を使用してインスタンスのコンストラクターを構築します。 Vue のコンポーネントは関数ですが、導入前はまだ単なるオプション オブジェクトであるため、Vue のコンポーネントは最初は単なるオブジェクト、つまり上位コンポーネントは関数であることが容易に理解できます。純粋なオブジェクトを受け入れ、新しい純粋なオブジェクトを返します

export default function Console (BaseComponent) {
  return {
    template: '<wrapped v-on="$listeners" v-bind="$attrs"/>',
    components: {
      wrapped: BaseComponent
    },
    mounted () {
      console.log('haha')
    }
  }
}
ログイン後にコピー
ここでのコンソールは上位コンポーネントであり、コンポーネントに渡されたパラメータ BaseComponent を受け取り、新しいコンポーネントを返し、BaseComponent をサブコンポーネントとして使用します新しいコンポーネントを作成し、出力するためにマウントされたフック関数を設定します (笑)。ミックスインでも同じことができます。問題は、サブコンポーネント Base を変更していないということです。ここの $listeners $attrs は、実際には props とイベントを透過的に送信しています。本当にこれで問題は完全に解決するのでしょうか?いいえ、まず第一に、テンプレート オプションは Vue のフル バージョンでのみ使用でき、ランタイム バージョンでは使用できないため、少なくともテンプレート (template) の代わりにレンダリング関数 (render) を使用する必要があります。

Console.js

export default function Console (BaseComponent) {
  return {
    mounted () {
      console.log('haha')
    },
    render (h) {
      return h(BaseComponent, {
        on: this.$listeners,
        attrs: this.$attrs,
      })
    }
  }
}
ログイン後にコピー

テンプレートをレンダリング関数に書き換えました。一見問題がないようですが、実はまだ問題があります。上記のコードでは、BaseComponent コンポーネントがまだ受信できません。 props. どうして、すでに h 関数に入っていないのですか? 2 つのパラメータの間に attrs を渡しましたか? なぜそれを受け取ることができないのですか?もちろん受け取ることはできません。Attrs は props として宣言されていない属性を参照するため、レンダリング関数に props パラメータを追加する必要があります:

export default function Console (BaseComponent) {
  return {
    mounted () {
      console.log('haha')
    },
    render (h) {
      return h(BaseComponent, {
        on: this.$listeners,
        attrs: this.$attrs,
        props: this.$props
      })
    }
  }
}
ログイン後にコピー

それでも機能しません。常に空のオブジェクトです。ここで props は上位コンポーネントのオブジェクトですが、上位コンポーネントは props を宣言していないため、別の props

export default function Console (BaseComponent) {
  return {
    mounted () {
      console.log('haha')
    },
    props: BaseComponent.props,
    render (h) {
      return h(BaseComponent, {
        on: this.$listeners,
        attrs: this.$attrs,
        props: this.$props
      })
    }
  }
}
ログイン後にコピー

ok を宣言する必要があります。同様の上位コンポーネントは次のとおりです。完了しましたが、まだ可能であれば実装するだけです。プロパティを透過的に送信し、イベントを透過的に送信すると、スロットだけが残ります。Base コンポーネントを変更して、名前付きスロットとデフォルト スロットを追加します。Base.vue

<template>
  <div>
    <span @click="handleClick">props: {{test}}</span>
    <slot name="slot1"/> <!-- 具名插槽 --></slot>
    <p>===========</p>
    <slot><slot/> <!-- 默认插槽 -->
  </div>
</template>
 
<script>
export default {
  ...
}
</script>

<template>
  <div>
    <Base>
      <h2 slot="slot1">BaseComponent slot</h2>
      <p>default slot</p>
    </Base>
    <wrapBase>
      <h2 slot="slot1">EnhancedComponent slot</h2>
      <p>default slot</p>
    </wrapBase>
  </div>
</template>
 
<script>
  import Base from './Base.vue'
  import hoc from './Console.js'
 
  const wrapBase = Console(Base)
 
  export default {
    components: {
      Base,
      wrapBase
    }
  }
</script>
ログイン後にコピー

ここでの実行結果は、wrapBase にスロットがないということです。したがって、上位コンポーネントを変更する必要があります

function Console (BaseComponent) {
  return {
    mounted () {
      console.log('haha')
    },
    props: BaseComponent.props,
    render (h) {
 
      // 将 this.$slots 格式化为数组,因为 h 函数第三个参数是子节点,是一个数组
      const slots = Object.keys(this.$slots)
        .reduce((arr, key) => arr.concat(this.$slots[key]), [])
 
      return h(BaseComponent, {
        on: this.$listeners,
        attrs: this.$attrs,
        props: this.$props
      }, slots) // 将 slots 作为 h 函数的第三个参数
    }
  }
}
ログイン後にコピー

この時点では、スロットの内容は確かにレンダリングされますが、順序が正しくありません。そしてすべての上位コンポーネントが最後までレンダリングされます。 。実際、Vue は名前付きスロットを処理するときにスコープ要素を考慮します。まず、Vue はテンプレートをレンダリング関数 (render) にコンパイルします。たとえば、次のテンプレート:

<div>
  <p slot="slot1">Base slot</p>
</div>
ログイン後にコピー

は次のレンダリング関数にコンパイルされます。 :

var render = function() {
  var _vm = this
  var _h = _vm.$createElement
  var _c = _vm._self._c || _h
  return _c("div", [
    _c("div", {
      attrs: { slot: "slot1" },
      slot: "slot1"
    }, [
      _vm._v("Base slot")
    ])
  ])
}
ログイン後にコピー

上記のレンダリング関数を観察すると、通常の DOM が _c 関数を通じて対応する VNode を作成していることがわかります。次に、テンプレートを変更します。通常の DOM に加えて、テンプレートには次のようなコンポーネントもあります:

<div>
  <Base>
    <p slot="slot1">Base slot</p>
    <p>default slot</p>
  </Base>
</div>
ログイン後にコピー
ログイン後にコピー

そのレンダリング関数

var render = function() {
  var _vm = this
  var _h = _vm.$createElement
  var _c = _vm._self._c || _h
  return _c(
    "div",
    [
      _c("Base", [
        _c("p", { attrs: { slot: "slot1" }, slot: "slot1" }, [
          _vm._v("Base slot")
        ]),
        _vm._v(" "),
        _c("p", [_vm._v("default slot")])
      ])
    ],
  )
}
ログイン後にコピー

我们发现无论是普通DOM还是组件,都是通过 _c 函数创建其对应的 VNode 的 其实 _c 在 Vue 内部就是 createElement 函数。createElement 函数会自动检测第一个参数是不是普通DOM标签如果不是普通DOM标签那么 createElement 会将其视为组件,并且创建组件实例,注意组件实例是这个时候才创建的 但是创建组件实例的过程中就面临一个问题:组件需要知道父级模板中是否传递了 slot 以及传递了多少,传递的是具名的还是不具名的等等。那么子组件如何才能得知这些信息呢?很简单,假如组件的模板如下

<div>
  <Base>
    <p slot="slot1">Base slot</p>
    <p>default slot</p>
  </Base>
</div>
ログイン後にコピー
ログイン後にコピー

父组件的模板最终会生成父组件对应的 VNode,所以以上模板对应的 VNode 全部由父组件所有,那么在创建子组件实例的时候能否通过获取父组件的 VNode 进而拿到 slot 的内容呢?即通过父组件将下面这段模板对应的 VNode 拿到

<Base>
    <p slot="slot1">Base slot</p>
    <p>default slot</p>
  </Base>
ログイン後にコピー

如果能够通过父级拿到这段模板对应的 VNode,那么子组件就知道要渲染哪些 slot 了,其实 Vue 内部就是这么干的,实际上你可以通过访问子组件的 this.$vnode 来获取这段模板对应的 VNode

this.$vnode 并没有写进 Vue 的官方文档

子组件拿到了需要渲染的 slot 之后进入到了关键的一步,这一步就是导致高阶组件中透传 slot 给 Base组件 却无法正确渲染的原因 children的VNode中的context引用父组件实例 其本身的context也会引用本身实例 其实是一个东西

console.log(this. vnode.context===this.vnode.componentOptions.children[0].context) //ture

而 Vue 内部做了一件很重要的事儿,即上面那个表达式必须成立,才能够正确处理具名 slot,否则即使 slot 具名也不会被考虑,而是被作为默认插槽。这就是高阶组件中不能正确渲染 slot 的原因

即 高阶组件中 本来时父组件和子组件之间插入了一个组件(高阶组件),而子组件的 this.$vnode其实是高阶组件的实例,但是我们将slot透传给子组件,slot里 VNode 的context实际引用的还是父组件 所以

console.log(this.vnode.context === this.vnode.componentOptions.children[0].context) // false
ログイン後にコピー

最终导致具名插槽被作为默认插槽,从而渲染不正确。

决办法也很简单,只需要手动设置一下 slot 中 VNode 的 context 值为高阶组件实例即可

function Console (Base) {
  return {
    mounted () {
      console.log(&#39;haha&#39;)
    },
    props: Base.props,
    render (h) {
      const slots = Object.keys(this.$slots)
        .reduce((arr, key) => arr.concat(this.$slots[key]), [])
        // 手动更正 context
        .map(vnode => {
          vnode.context = this._self //绑定到高阶组件上
          return vnode
        })
 
      return h(WrappedComponent, {
        on: this.$listeners,
        props: this.$props,
        attrs: this.$attrs
      }, slots)
    }
  }
}
ログイン後にコピー

说明白就是强制把slot的归属权给高阶组件 而不是 父组件 通过当前实例 _self 属性访问当实例本身,而不是直接使用 this,因为 this 是一个代理对象

【相关推荐:vuejs视频教程web前端开发

以上がvue の上位コンポーネントとは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

HTMLにおけるReactの役割:ユーザーエクスペリエンスの向上 HTMLにおけるReactの役割:ユーザーエクスペリエンスの向上 Apr 09, 2025 am 12:11 AM

ReactはJSXとHTMLを組み合わせてユーザーエクスペリエンスを向上させます。 1)JSXはHTMLを埋め込み、開発をより直感的にします。 2)仮想DOMメカニズムは、パフォーマンスを最適化し、DOM操作を削減します。 3)保守性を向上させるコンポーネントベースの管理UI。 4)国家管理とイベント処理は、インタラクティブ性を高めます。

ReactとFrontend:インタラクティブエクスペリエンスの構築 ReactとFrontend:インタラクティブエクスペリエンスの構築 Apr 11, 2025 am 12:02 AM

Reactは、インタラクティブなフロントエンドエクスペリエンスを構築するための好ましいツールです。 1)Reactは、コンポーネント化と仮想DOMを通じてUIの開発を簡素化します。 2)コンポーネントは、関数コンポーネントとクラスコンポーネントに分割されます。関数コンポーネントはよりシンプルで、クラスコンポーネントはより多くのライフサイクル方法を提供します。 3)Reactの作業原則は、パフォーマンスを改善するために仮想DOMおよび調整アルゴリズムに依存しています。 4)国家管理は、usestateまたはthis.stateを使用し、ComponentDidmountなどのライフサイクルメソッドが特定のロジックに使用されます。 5)基本的な使用には、コンポーネントの作成と状態の管理が含まれ、高度な使用にはカスタムフックとパフォーマンスの最適化が含まれます。 6)一般的なエラーには、不適切なステータスの更新とパフォーマンスの問題が含まれます。

反応コンポーネント:HTMLで再利用可能な要素を作成します 反応コンポーネント:HTMLで再利用可能な要素を作成します Apr 08, 2025 pm 05:53 PM

Reactコンポーネントは、機能またはクラスによって定義され、UIロジックのカプセル化、およびプロップを介して入力データを受け入れることができます。 1)コンポーネントの定義:関数またはクラスを使用して、反応要素を返します。 2)レンダリングコンポーネント:Reactコールレンダリングメソッドまたは機能コンポーネントを実行します。 3)マルチプレックスコンポーネント:データをプロップに渡して、複雑なUIを構築します。コンポーネントのライフサイクルアプローチにより、ロジックをさまざまな段階で実行でき、開発効率とコードメンテナビリティが向上します。

反応とフロントエンドスタック:ツールとテクノロジー 反応とフロントエンドスタック:ツールとテクノロジー Apr 10, 2025 am 09:34 AM

Reactは、コアコンポーネントと状態管理を備えたユーザーインターフェイスを構築するためのJavaScriptライブラリです。 1)コンポーネントと州の管理を通じてUIの開発を簡素化します。 2)作業原則には和解とレンダリングが含まれ、React.memoとusememoを通じて最適化を実装できます。 3)基本的な使用法は、コンポーネントを作成およびレンダリングすることであり、高度な使用法にはフックとコンテキストアピの使用が含まれます。 4)不適切なステータスの更新などの一般的なエラーでは、ReactDevtoolsを使用してデバッグできます。 5)パフォーマンスの最適化には、React.MEMO、仮想化リスト、コードスプリッティの使用が含まれ、コードを読みやすく保守可能に保つことがベストプラクティスです。

Reactのエコシステム:ライブラリ、ツール、およびベストプラクティス Reactのエコシステム:ライブラリ、ツール、およびベストプラクティス Apr 18, 2025 am 12:23 AM

Reactエコシステムには、状態管理ライブラリ(Reduxなど)、ルーティングライブラリ(Reactrouterなど)、UIコンポーネントライブラリ(材料-UIなど)、テストツール(JESTなど)、およびビルディングツール(Webpackなど)が含まれます。これらのツールは、開発者がアプリケーションを効率的に開発および維持し、コードの品質と開発効率を向上させるのを支援するために協力します。

TypeScriptをReactで使用することの利点は何ですか? TypeScriptをReactで使用することの利点は何ですか? Mar 27, 2025 pm 05:43 PM

タイプスクリプトは、タイプの安全性を提供し、コードの品質を改善し、IDEサポートを改善し、エラーを減らし、保守性を向上させることにより、反応開発を促進します。

React vs.バックエンドフレームワーク:比較 React vs.バックエンドフレームワーク:比較 Apr 13, 2025 am 12:06 AM

Reactは、ユーザーインターフェイスを構築するためのフロントエンドフレームワークです。バックエンドフレームワークは、サーバー側のアプリケーションを構築するために使用されます。 Reactはコンポーネントで効率的なUIアップデートを提供し、バックエンドフレームワークは完全なバックエンドサービスソリューションを提供します。テクノロジースタックを選択するときは、プロジェクトの要件、チームのスキル、およびスケーラビリティを考慮する必要があります。

Reactを使用したフロントエンド開発:利点とテクニック Reactを使用したフロントエンド開発:利点とテクニック Apr 17, 2025 am 12:25 AM

Reactの利点は、その柔軟性と効率性であり、これは以下に反映されています。1)コンポーネントベースの設計により、コードの再利用性が向上します。 2)仮想DOMテクノロジーは、特に大量のデータ更新を処理する場合、パフォーマンスを最適化します。 3)リッチエコシステムは、多数のサードパーティライブラリとツールを提供します。 Reactがどのように機能し、例を使用するかを理解することにより、そのコアコンセプトとベストプラクティスをマスターして、効率的で保守可能なユーザーインターフェイスを構築できます。

See all articles