Vue公式ガイド読解メモ-描画関数とJSX その2

今日は「描画関数とJSX」の続き

jp.vuejs.org

素の JavaScript によるテンプレートの書き換え

v-if, v-for

v-if, v-forはJavaScriptで普通にif/else/mapなどを使って書き換えられる

<ul v-if="items.length">
  <li v-for="item in items">{{ item.name }}</li>
</ul>
<p v-else>No items found.</p>
props: ['items'],
render: function (createElement) {
  if  (this.items.length) {
    return createElement('ul', this.items.map(function(item) {
       return createElement('li', item.name)
    }))
  } else {
     return createElement('p', 'No items found')
  }
}

なるほどね、普通のJS記法で分岐とか繰り返しを書いてしまえば良いと。 これも、テンプレートコンパイラのお仕事なのかな。

v-model

render関数に直接的なv-modelの対応はない。 つまり、v-modelがやっていることを自分で実装する必要がある。 ※この自分で実装する部分も、テンプレートからrender関数にコンパイルするときは、スニペットみたいなものが自動生成されているんだろうな。

props: ['value'],
render: function(createElement) {
   var self = this
   return createElement('input', {
      domProps: {
         value: self.value
      },
     on: {
        input: function(event) {
          self.$emit('input', event.target.value)
        }
     }
   })
}

なんかよくわからんコードだぞ。 createElement('input')で作ったvnodeのinputイベントにリスナー登録してて、イベントが発生したら、$emit('input')している。 $emit()はVueの機能だから。ネイティブイベントをVueイベントに変換しているイメージか。 domPropsは、domであるinputタグのvalue属性とのひも付きか。self.valueがこのコンポーネント自身が保持するvalueなので、domにコンポーネントvalueをセットしているよ、ということか。 これは、リアクティブに動作すると思うのだけど、この仕組はもっとコアなものなのかも。(ここには現れない) event.target.valueをself.valueにセットする仕組みがあるはずなんだよな。多分。それもdomPropsで指定しているから大丈夫なんかな。(違う気がする)

イベントとキー修飾

.passive, .capture, .once イベント修飾子は、onで使用できる接頭辞を提供している。

on: {
  '!click': this.doThisInCapturingMode,
  '~keyup': this.doThisOnce,
  '~!mouseover': this.doThisOnceInCapturingMode
}

ほー、onceとかって、一回しかイベント拾わない、みたいなやつだよね。.stopみたいに、event.stopPropagation()と簡単に代替できないから、接頭辞を提供してあげている、ってことかな。

一旦ここまで 次は「スロット」

追記

スロット

this.$slotsで、スロットの内容にアクセスできる。

render : function (createElement) {
    // <div><slot></slot></div>
    return createElement('div', this.$slots.default)
}

で囲まれているvnodeが、this.$slots.defaultで参照できるということだよな。

this.$scopedSlotsでvnodeを返す関数として、スコープ付きスロットにアクセスできると。

($scopedSlotsって使われてたのね、もしかして、v-slotが2.6で追加されたけど、render関数は変更が無いのかもしれない)

うーん、スコープ付きとは、slot内のコンテンツで参照できる値を親から渡せるみたいなイメージだよな。

なんで、$slotsと別にあるのか、やっぱりよくわからんな。$slotsに統合されててもいい気がするが。スコープ付きスロットとそうじゃないスロットで区別されているのは、なにか理由があるのか。ちょっと気になる。

今は、そういうものだと思っておこう。

JSX

render関数の中身をガチで実装するのはつらい。 つらいので、JSXで書けるbabelプラグインがあるとのこと。

テンプレートで良い気がするが。。。

new Vue({
   el : '#demo',
   render: function (h) {
      return (
         <AnchoredHeading level={1}>
              <span>Hello</span> world!
         </AnchoredHeading>
      )
    }
})

なぜわざわざ、render関数を噛ますのか。

createElementをhエイリアスするのは、Vueのエコシステムの中でよく見かける慣習らしい。たしかに、よく見る。なんでや。

このあたりで終わろう。 次は「関数型コンポーネントから」