はじめに

 Deepblueでは、「キメタビ」という好きな観光地をピックアップし、最適なルートを提案するサービスを運営しています。その中で、ユーザがランダムに表示される観光地の写真を直感的に選択できるUIとして、カードスワイプできるTinder風のデザインを実装しました。
 スマートフォンアプリ用の実装例、ライブラリは豊富にあるのですがWebでの実装例は少ないためLaravel + Vue での事例をご紹介します。

Laravel + Vueを利用する準備

まずは、Laravel + Vueの環境構築を行います。
今回はVueでSPAを作成する前提での環境です。

Laravelプロジェクトの作成

まずは、新規のLaravelプロジェクトを作成します。
任意の場所で下記コマンドを実行します。


composer create-project --prefer-dist laravel/laravel sample-project
cd sample-project
php artisan serve

http://127.0.0.1:8000
にアクセスし、ウェルカムページが表示されるか確認してください。

laravel/uiのインストール、vueを利用するための準備

(参考:https://github.com/laravel/ui


composer require laravel/ui
php artisan ui vue
npm install

/node_modules が作成されます。
gitignoreされているためコミットされないと思いますが、入ってない場合は.gitignoreに追加しましょう。


npm install --save vue-router
npm run dev

(参考: https://router.vuejs.org/ja/

最後にVue Routerというパッケージを追加して準備完了です。

npm run devすることで、フロントエンドのソースコードがビルドされます。
開発中はnpm run watchを実行しておくとソースコードの変更を監視して自動でビルドしてくれます。

補足


> @ watch /Users/yutaseto/sample-project
> mix watch

    Additional dependencies must be installed. This will only take a moment.

    Running: npm install vue-loader@^15.9.5 --save-dev --legacy-peer-deps

    Finished. Please run Mix again.

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! @ watch: mix watch
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the @ watch script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/hoge/.npm/_logs/2021-04-30T13_32_39_629Z-debug.log

というエラーが出る場合があります。その場合は上記のメッセージにあるように、
npm install vue-loader@^15.9.5 --save-dev --legacy-peer-deps
を実行しましょう。

Vur Routerの設定とページの作成

routes/web.php


use IlluminateSupportFacadesRoute;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/{any}', function () {
    return view('app');
})->where('any', '.*');

resouces/views/app.blade.php (新規)

<head>
    <meta charset="utf-8">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <link href="{{ mix(&#039;/css/app.css&#039;) }}" rel="stylesheet">
</head>
<body>
<div id="app">
    <router-view></router-view>
</div>
<script src="{{ mix(&#039;/js/app.js&#039;) }}" defer></script>
</body>
</html>

resources/js/components/SampleComponent.vue (新規)

    <p>テストページ</p>
</template>

<script>
    export default {}
</script>

resources/js/app.js


import Vue from 'vue';
import VueRouter from 'vue-router'
import SampleComponent from "./components/SampleComponent"

require('./bootstrap');

window.Vue = require('vue').default;

Vue.use(VueRouter)

const router = new VueRouter({
    mode: 'history',
    routes: [{
        path: '/',
        name: index,
        component: SampleComponent
    }]
})

const app = new Vue({
    el: '#app',
    router
});

http:/127.0.0.1:8000
にアクセスして「テストページ」と表示されたらページ作成完了です。
npm run dev もしくは、 npm run watch を忘れないようにしましょう。

VueTinderのインストールとセットアップ

VueTinderをインストールします。
npmもしくはyarnでインストールできます。


npm install vue-tinder --save
# or
yarn add vue-tinder

インストールできたら、まずは公式ドキュメントに従って、まずはカードだけを表示させてみましょう。
公式ドキュメントではbingイメージを利用しています。

  <div id="app">
    <Tinder key-name="id" :queue.sync="queue" :offset-y="10" @submit="onSubmit">
      <template slot-scope="scope">
        <div
          class="pic"
          :style="{
            &#039;background-image&#039;: `url(https://cn.bing.com//th?id=OHR.${scope.data.id}_UHD.jpg&pid=hp&w=720&h=1280&rs=1&c=4&r=0)`
          }"
        />
      </template>
      <img class="like-pointer" slot="like" src="/assets/like-txt.png">
      <img class="nope-pointer" slot="nope" src="/assets/nope-txt.png">
      <img class="super-pointer" slot="super" src="/assets/super-txt.png">
    </Tinder>
  </div>
</template>

bing.js

export default [
  "AdelieBreeding_ZH-CN1750945258",
  "BarcolanaTrieste_ZH-CN5745744257",
  "RedRocksArches_ZH-CN5664546697",
  "NationalDay70_ZH-CN1636316274",
  "LofotenSurfing_ZH-CN5901239545",
  "UgandaGorilla_ZH-CN5826117482",
  "FeatherSerpent_ZH-CN5706017355",
  "VancouverFall_ZH-CN9824386829",
  "WallofPeace_ZH-CN5582031878",
  "SanSebastianFilm_ZH-CN5506786379",
  "CommonLoon_ZH-CN5437917206",
  "SunbeamsForest_ZH-CN5358008117",
  "StokePero_ZH-CN5293082939",
  "Wachsenburg_ZH-CN5224299503",
  "SurfboardRow_ZH-CN5154549470",
  "ToothWalkingSeahorse_ZH-CN5089043566",
  "midmoon_ZH-CN4973736313",
  "MilkyWayCanyonlands_ZH-CN2363274510",
  "DaintreeRiver_ZH-CN2284362798"
];
      <img src="/images/rewind.png" @click="decide(&#039;rewind&#039;)" />
      <img src="/images/nope.png" @click="decide(&#039;nope&#039;)" />
      <img src="/images/love.png" @click="decide(&#039;like&#039;)" />
      <img src="/images/info.png" />

この画像がなければエラーが出ます。
フリー素材などで探してみてください。

カードが表示されたら無事導入完了です!
次回はカスタマイズについてご説明します。

VueTinderでできることについて、キメタビもぜひご参考ください。