web-dev-qa-db-ja.com

Vue.jsでカスタムレンダリング機能を使用してテキストノードを作成します

my-linkコンポーネントを使用して、さまざまなアイテムの周りにオンデマンドでアンカータグをラップしています。そのために、カスタムのrenderメソッドが使用されますが、createElementメソッドはHTMLノードしか作成できないため、プレーンテキストノードを作成することはできないようです。

現在のシナリオ

my-linkコンポーネントの使用法

<template v-for="item in items">
  <h4>
    <my-link :url="item.url">{{ item.text }}</my-link>
  </h4>
</template>

my-linkコンポーネントをLink.vueとして実装

<script>
export default {
  name: 'my-link',
  props: { url: String },
  render(createElement) {
    if (this.url) {
      return createElement(
          'a', {
            attrs: { href: this.url }
          }, this.$slots.default
      );
    }

    return createElement(
        'span',
        this.$slots.default
    );
  }
};
</script>

結果のHTML

<h4>
  <a url="/some-link">This item is linked</a>
</h4>
<h4>
  <span>Plain text item</span>
</h4>

望ましいシナリオ

この特定のシナリオのspanタグは不要であり、回避することができますが、Vue.jsでこれがどのように、そしてまったく可能かどうかは私にはわかりません。一般的に、カスタムrenderメソッドでプレーンテキストノードを作成する方法を知りたいです。

<h4>
  <a url="/some-link">This item is linked</a>
</h4>
<h4>
  Plain text item
</h4>
13
Oliver Hader

Vue _ vと呼ばれるプロトタイプの内部メソッドを公開します プレーンテキストノードを作成します。プレーンテキスト文字列をレンダリングするために、render関数からこのメソッドを呼び出した結果を返すことができます。

render(h){
    return this._v("my string value");
}

この方法でアンダースコアを付けて公開すると、プライベートAPIメソッドとして意図されている可能性が高いため、注意して使用してください。

機能コンポーネントを使用する場合、「これ」も使用できません。この場合、次のようにcontext._v()を呼び出す必要があります。

functional: true,
render(h, context){
    return context._v("my string value")
}

これをスロットからテキストを抽出することと組み合わせると(コメントのように、役立つ getChildrenTextContent を使用して)、目的の結果が得られます。

15
Bert

MyLinkコンポーネントの実装を次のように変更することで、上記の回答に記載されている_vメソッドを使用する必要を実際に回避できます(そして、後で名前が変更される可能性のある内部Vueメソッドの使用を回避できる可能性があります)機能コンポーネント。機能コンポーネントはルート要素を必要としないため、非リンク要素の周囲にスパンを配置する必要があります。

MyLinkは次のように定義できます。

const MyLink = {
  functional: true,
  name: 'my-link',
  props: { url: String },
  render(createElement, context) {
    let { url } = context.props
    let slots = context.slots()
    if (url) {
      return createElement(
          'a', {
            attrs: { href: url }
          }, slots.default
      );
    }
    else {
      return slots.default 
    }
  }
};

次に、それを使用するために、別のコンポーネントで次のようなことを行うことができます。

<div>
  <h4 v-for="item in items">
    <my-link :url="item.url">{{ item.text }}</my-link>
  </h4>
</div>

参照: https://codepen.io/hunterae/pen/MZrVEK?editors=101

また、補足として、元のコードスニペットがファイルにLink.vueという名前を付けているようです。 Vueのテンプレートシステムを使用する代わりに独自のレンダリング関数を定義しているため、理論的にはファイルの名前をLink.jsに変更し、開始スクリプトタグと終了スクリプトタグを削除して、完全にJSコンポーネントファイルを作成できます。ただし、コンポーネントにカスタムシステムが含まれている場合(スニペットには含まれていません)、このアプローチは機能しません。お役に立てれば。

1
Andrew H

コンポーネントのルート要素が必要です。あなたの場合、ルート要素として「h4」を使用できるかもしれません。とにかくv-forループにそれを含めることができるからです。それが済んだら、次のようなテキストノードを作成できます。

return createElement(
    'h3',
    {},
    ['Plain text item']
);

Vueのドキュメントによると、createElementの3番目の引数は文字列または配列である可能性があり、文字列の場合はテキストノードに変換されます。

https://vuejs.org/v2/guide/render-function.html#createElement-Arguments

0
Henry Liu