第24回  Vue.js入門 描画関数

render プログラミング

以前、コンポーネントの作り方の中でも、本当に少しだけですが描画関数というものについて触れました。今回は、描画関数について少し詳しく説明します。

描画関数とは

描画関数とは、コンポーネントの内容を細かく設定するための関数です。

これまで、コンポーネントをつくるというと、Vue.component APIに渡すオブジェクトの中にtemplateプロパティを設定して、そのtemplateプロパティの値として、コンポーネントの内容を書くことが多かったと思います。

しかし、コンポーネントを使用するときにコンポーネントの属性値として与えた値によって表示するコンポーネントを変えたい場合などがあるかもしれません。

そのようなときには、templateプロパティにコンポーネントの内容を設定するよりも、描画関数で設定したほうが、簡単に設定することができる場合があります。

描画関数の設定方法

どのようなときに描画関数が便利なのかを説明する前に、描画関数をどのように書けばコンポーネントの内容を設定することができるのかを説明します。

基本的な書き方

ちなみに、コンポーネントの内容とは、<my-component></my-component>のようにしてmy-componentという名前のコンポーネントを使ったときに、実際に表示されるHTMLのことを指しています。

次のようにして書くことで、描画関数を使ってコンポーネントの内容を設定することができます。

Vue.component("コンポーネントの名前", {
    render: function (createElement) {
        rerurn createElement("一番外側の要素名", 属性設定用のオブジェクト, "内側に入れる文字列")
    }
})

まず、renderプロパティという値に関数を持ったプロパティを設定します。この関数には引数にcreateElementという関数を設定します。

引数として設定したcreateElement関数をreturn文で使い、その時の引数の設定の仕方でコンポーネントの内容を設定することができる様になっています。

これだけだけだと、createElement関数の引数に何を書いていいのかわからないと思うので、1つ例を挙げてみます。

例えば、これから設定するコンポーネントは、これまでどおりのtemplateプロパティに設定する方法でコンポーネントの内容を書くと次のようになります。

Vue.component("myComponent", {
  template: "<a href='https://konsuki.com'>コンスキブログ</a>"
})

これのコンポーネントを描画関数で設定すると次のようになります。

Vue.component ("myComponent", {
  render: function (createElement) {
    return createElement("a", {
      attrs: {
        href: "https://konsuki.com"
      }
    }, "コンスキブログ")
  } 
})

コンポーネントの一番外側の要素名は「a要素」であるため、createElement関数の第1引数には「”a”」が書かれています。

次に、a要素の属性には、「href属性」を設定して、その属性値は「https://konsuki.com」であるため、createElement関数の第2引数には、上のようなオブジェクトを書きます。

最後に、a要素の内側に入れるものは「コンスキブログ」という文字列であるため、createElement関数の第3引数には、「”コンスキブログ”」と書きます。

ちなみに、第2引数の「属性設定用のオブジェクト」は必要でなければ省略することができます。「属性設定用のオブジェクト」必要がない場合には、第1引数に「一番外側の要素名」を設定し、第2引数には「内側に入れるもの」を設定します。

要素が重なっている場合の書き方

コンポーネントを作る際には、上の例に出てきた簡単な構成のものではなく、次のような何重かに重なった構成になっている複雑なコンポーネントを作りたいときがあります。

Vue.component("complexComponent", {
  template: `
    <div>
      <a href="https://konsuki.com">
        <img src="./img/konsuki_QR.png">
      </a>
    </div>
  `
})

このような場合は、次のようにcreate関数の第3引数に関数の要素としてさらに、create関数を設定する必要があります。

Vue.component("complexComponent", {
  render: function (createElement) {
    return createElement("div", [
      createElement("a", {
        attrs: {
          href: "https://konsuki.com"
        }
      }, [
        createElement("img", {
          attrs: {
            src: "./img/konsuki_QR.png"
          }
        })
      ])
    ])
  }
})

上のように書くことで、コンポーネントの内容のHTML要素が入れ子になっているような場合でも描画関数を使って書くことができます。

しかし、コードが複雑で読みづらくなるという問題があります。

描画関数を使う利点

ここまでで、描画関数のを使ってコンポーネントを作る方法が少しわかったかもしれません。

しかし、ここまでで取り上げた例であれば、templateプロパティにコンポーネントの内容を設定する方法のほうが簡単に書けると考える方が多いと思います。

そこで、描画関数を使うと便利なコンポーネントとは、どういうコンポーネントかというと、利用するときに属性値によって内容を切り替えるようなコンポーネントです。

言葉だけだとそれがどのようなコンポーネントなのかわからないため、例を見てみましょう。

例えば、使用するときに設定する属性値で内容を切り替えられるコンポーネントをtemplateプロパティを使って設定します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>描画関数</title>
  <script src="https://unpkg.com/vue"></script>
</head>
<body>
  <div id="app">
    <changeable-component tag="h1">ヘッダ</changeable-component>
    <changeable-component tag="h2">ヘッダ</changeable-component>
    <changeable-component tag="h3">ヘッダ</changeable-component>
    <changeable-component tag="h4">ヘッダ</changeable-component>
    <changeable-component tag="h5">ヘッダ</changeable-component>
    <changeable-component tag="h6">ヘッダ</changeable-component>
  </div>
  <script>
    Vue.component ("changeableComponent", {
      props: [ "tag" ],
      template: `
        <h1 v-if="tag === 'h1'">
          <slot></slot>
        </h1>
        <h2 v-else-if="tag === 'h2'">
          <slot></slot>
        </h2>
        <h3 v-else-if="tag === 'h3'">
          <slot></slot>
        </h3>
        <h4 v-else-if="tag === 'h4'">
          <slot></slot>
        </h4>
        <h5 v-else-if="tag === 'h5'">
          <slot></slot>
        </h5>
        <h6 v-else-if="tag === 'h6'">
          <slot></slot>
        </h6>
      `
    })
    var vm = new Vue({
      el: "#app"
    })
  </script>
</body>
</html>

この「chageable-header」というコンポーネントは、使うときにtag属性の属性値を「h1~h6」の中で好きなものに変えることで、コンポーネントの内容を切り替えることができるコンポーネントです。

コンポーネントの内容を切り替えるために、v-else-ifの条件式を何度も繰り返していることがわかります。

また、「<slot></slot>」という部分も何度も繰り返す必要があることがわかります。

これらの繰り返しは、templateプロパティにコンポーネントの内容を書く場合、行わなくてはいけなくなる繰り返しです。

そこで、描画関数を使って同じコンポーネントの内容を書いてみます。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>描画関数</title>
  <script src="https://unpkg.com/vue"></script>
</head>
<body>
  <div id="app">
    <changeable-header tag="h1">ヘッダ</changeable-header>
    <changeable-header tag="h2">ヘッダ</changeable-header>
    <changeable-header tag="h3">ヘッダ</changeable-header>
    <changeable-header tag="h4">ヘッダ</changeable-header>
    <changeable-header tag="h5">ヘッダ</changeable-header>
    <changeable-header tag="h6">ヘッダ</changeable-header>
  </div>
  <script>
    Vue.component ("changeableHeader", {
      props: [ "tag" ],
      render: function (createElement) {
        return createElement(this.tag, this.$slots.default)
      }
    })
    var vm = new Vue({
      el: "#app"
    })
  </script>
</body>
</html>

描画関数で書いたことで、非常にシンプルになったと思います。

コンポーネントの内容を設定している部分のコード量だけを比べてみると次のようになります。

templateプロパティに設定

template: `
  <h1 v-if="tag === 'h1'">
    <slot></slot>
  </h1>
  <h2 v-else-if="tag === 'h2'">
    <slot></slot>
  </h2>
  <h3 v-else-if="tag === 'h3'">
    <slot></slot>
  </h3>
  <h4 v-else-if="tag === 'h4'">
    <slot></slot>
  </h4>
  <h5 v-else-if="tag === 'h5'">
    <slot></slot>
  </h5>
  <h6 v-else-if="tag === 'h6'">
    <slot></slot>
  </h6>
`

描画関数で設定

render: function (createElement) {
  return createElement(this.tag, this.$slots.default)
}

条件式や、「<slot></slot>」の部分の繰り返しがなくなり、コード量も非常に少なくなりました。

最後になりましたが、描画関数の利点は、この例で作ったコンポーネントのように、使用する際に属性値を設定することで、コンポーネントの内容を変えるようなコンポーネントを作る際に、理解しやすいコードを書けるという点です。

後から切り替えられるコンポーネントの種類を増やす必要がなくなるため、コンポーネントの管理もしやすくなります。

まとめ

今回わかったこと

  • 使用時に内容を決められるようなコンポーネントを作る際には、描画関数を使うと便利
  • 描画関数を使うと、コンポーネントの管理もしやすくなる

コメント

タイトルとURLをコピーしました