Ruby on Rails + Slim 環境で Vue.js の Slot を使う。

2021/12/18に公開

バージョン情報

Ruby 2.7.1
Rails 6.0.2.2
Vue 2.6.11
vue-turbolinks 2.2.2

解決したい問題

Ruby on Rails + Slim 環境で Vue の Slot を使いたい。
ネット上で情報が少なったので、記録しようと思う。
試行錯誤して、動いたものを以下記載する。

Vue公式 名前付きスロット

https://jp.vuejs.org/v2/guide/components-slots.html#名前付きスロット

Slim
https://github.com/slim-template/slim/blob/master/README.jp.md

実装

Vue の単一ファイルコンポーネント

これは、公式にある通りに実装する。

app/javascript/vue-components/SampleAbc.vue
<template>
  <div>
    <transition name="abc">
      <slot name="sample-slot-abc"></slot>
    </transition>
  </div>
</template>

<script>
// 任意の処理
</script>

<style>
// 任意のstyle
</style>

Vue の単一ファイルコンポーネントを読み込むJavaScriptファイル

ここでの留意点は、コンポーネント名は、「SampleAbc」などのパスカルケースだが、コンポーネント名が、パスカルケースだと、Slim 側でレンダリングできない。
そのため、「sample-abc」などのケバブケースの名に命名しなおす。

app/javascript/packs/sample_vue_render.js
import Vue from 'vue/dist/vue.esm'

import TurbolinksAdapter from 'vue-turbolinks'
Vue.use(TurbolinksAdapter)

import SampleAbc from '../vue-components/SampleAbc.vue'

/**
 * @description  Vue の単一ファイルコンポーネントのルート。
 * @param {void}
 * @returns {void}
 */
const sampleVueRender = () => {
  const rootElement = document.getElementById('js-vue-root')

  if (rootElement === null) {
    return
  }

  Vue.component('sample-abc', SampleAbc)

  new Vue({
    el: rootElement
  })
}

document.addEventListener('turbolinks:load', sampleVueRender)

ここでは、仮に、application.js でグローバルに読み込むものとする。

app/javascript/packs/application.js
+ require('packs/sample_vue_render')

Slim側

sample-abcコンポーネントは、単に sample-abc で良いようだ。
また、<template> も同様に、templateと書く。
名前付きスロットは、slot="sample-slot-abc" で動作した。
Vue 2.6.0 で v-slot ディレクティブが導入され、slot 属性は、非推奨のようだ。
しかし、v-slotだと、どうしても Rails + Slim 環境で動かすことができなかった。
何かご存じの方がいらっしゃれば、コメント欄でお教えいただけるとありがたい。

app/views/shared/_test.html.slim
#js-vue-root
  sample-abc
    template slot="sample-slot-abc"
      // ここにSlotに入れる要素が入ります。
      p
        | Hello World

[1]

以上で、ブラウザには、「Hello World」と表示される。
あとは、Vue の transition でアニメーションをつけたり、クリック等のアクションで、動的に表示非表示を切り替えたり、など自由に処理を追加する。


まとめ

主なポイントは、

  • コンポーネント名は、JavaScript のパスカルケースから、Slim でレンダリングできるようにケバブケースにリネームする。
  • Slim 側では、template slot="sample-slot-abc"のように、記述する。

であると思う。
2点目は、別解があるかもしれない。

脚注
  1. Slim で syntax highlight ができないため、pug で syntax highlight を入れている。 ↩︎

Discussion