378 lines
9.7 KiB
Markdown
378 lines
9.7 KiB
Markdown
|
+++
|
||
|
date = "2020-04-11JST"
|
||
|
tags = ["vue"]
|
||
|
title = "vueのhooperでスライドを実装する"
|
||
|
slug = "vue"
|
||
|
+++
|
||
|
|
||
|
qiitaを書いていたら思った以上の分量になったので、ブログにも投稿しておきます。
|
||
|
|
||
|
vueでスライドを実装するにはhooperというlibraryが便利でした。
|
||
|
|
||
|
https://github.com/baianat/hooper
|
||
|
|
||
|
### 前提
|
||
|
|
||
|
今回使用するのは、vue-cli4とhooperです。
|
||
|
|
||
|
まず、vue-cli4を使えるようにします。最新を入れればいいですが、この情報が古くなった場合、4です。次に、hooperをpackage.jsonに追加します。
|
||
|
|
||
|
```sh
|
||
|
$ yarn global add @vue/cli
|
||
|
$ vue create sample-vue-project
|
||
|
$ cd sample-vue-project
|
||
|
$ yarn add hooper
|
||
|
|
||
|
$ cat package.json
|
||
|
```
|
||
|
|
||
|
package.jsonはこんな感じです。コピーして、`yarn install`してもいいです。これで`yarn install`とかすると、依存関係がインストールできます。
|
||
|
|
||
|
```json:package.json
|
||
|
{
|
||
|
"name": "sample-vue-project",
|
||
|
"version": "0.1.0",
|
||
|
"private": true,
|
||
|
"scripts": {
|
||
|
"serve": "vue-cli-service serve",
|
||
|
"build": "vue-cli-service build",
|
||
|
"lint": "vue-cli-service lint"
|
||
|
},
|
||
|
"dependencies": {
|
||
|
"core-js": "^3.6.4",
|
||
|
"hooper": "^0.3.4",
|
||
|
"vue": "^2.6.11"
|
||
|
},
|
||
|
"devDependencies": {
|
||
|
"@vue/cli-plugin-babel": "~4.3.0",
|
||
|
"@vue/cli-plugin-eslint": "~4.3.0",
|
||
|
"@vue/cli-service": "~4.3.0",
|
||
|
"babel-eslint": "^10.1.0",
|
||
|
"eslint": "^6.7.2",
|
||
|
"eslint-plugin-vue": "^6.2.2",
|
||
|
"vue-template-compiler": "^2.6.11"
|
||
|
},
|
||
|
"eslintConfig": {
|
||
|
"root": true,
|
||
|
"env": {
|
||
|
"node": true
|
||
|
},
|
||
|
"extends": [
|
||
|
"plugin:vue/essential",
|
||
|
"eslint:recommended"
|
||
|
],
|
||
|
"parserOptions": {
|
||
|
"parser": "babel-eslint"
|
||
|
},
|
||
|
"rules": {}
|
||
|
},
|
||
|
"browserslist": [
|
||
|
"> 1%",
|
||
|
"last 2 versions",
|
||
|
"not dead"
|
||
|
]
|
||
|
}
|
||
|
```
|
||
|
|
||
|
### vue
|
||
|
|
||
|
まず、vueの使い方を簡単に説明します。
|
||
|
|
||
|
vueは`src/main.js`と`src/App.vue`,`src/index.html`などを書いてbuildします。
|
||
|
|
||
|
```sh
|
||
|
$ yarn serve
|
||
|
$ yarn build
|
||
|
```
|
||
|
|
||
|
デフォルトでは、`dist`にファイルが置かれます。なお、root pathは`public`になっています。例えば、`https://example.com/path/to/img.png`を使いたければ、`public/path/to/img.png`にファイルを置いて、App.vueには`/path/to/img.png`と記述します。
|
||
|
|
||
|
次に、vue-cliですが、env(環境変数)を使う際は、`.env`に`VUE_APP_XXX=10`などと書いて、App.vueなどには`process.env.VUE_APP_XXX`とすることで環境変数を使えます。
|
||
|
|
||
|
### hooper
|
||
|
|
||
|
https://baianat.github.io/hooper/
|
||
|
|
||
|
docsのexampleがわかりやすいですね。最小構成は以下です。大体わかると思いますが、オプションなども用意されていますので、そのあたりは後述します。
|
||
|
|
||
|
```html:src/App.vue
|
||
|
// https://baianat.github.io/hooper/examples.html#default-example
|
||
|
<template>
|
||
|
<hooper>
|
||
|
<slide>
|
||
|
slide 1
|
||
|
</slide>
|
||
|
<slide>
|
||
|
slide 2
|
||
|
</slide>
|
||
|
<hooper-navigation slot="hooper-addons"></hooper-navigation>
|
||
|
</hooper>
|
||
|
</template>
|
||
|
|
||
|
<script>
|
||
|
import {
|
||
|
Hooper,
|
||
|
Slide,
|
||
|
Navigation as HooperNavigation
|
||
|
} from 'hooper';
|
||
|
|
||
|
export default {
|
||
|
components: {
|
||
|
Hooper,
|
||
|
Slide,
|
||
|
HooperNavigation
|
||
|
}
|
||
|
}
|
||
|
</script>
|
||
|
```
|
||
|
|
||
|
```js:src/mani.js
|
||
|
import Vue from 'vue'
|
||
|
import App from './App.vue'
|
||
|
|
||
|
Vue.config.productionTip = false
|
||
|
|
||
|
new Vue({
|
||
|
render: h => h(App)
|
||
|
}).$mount('#app')
|
||
|
```
|
||
|
|
||
|
|
||
|
#### hooperでの実装例
|
||
|
|
||
|
私の場合は、画像をスライドさせているので以下のような感じになりました。後で個別に解説します。
|
||
|
|
||
|
```html:src/App.vue
|
||
|
<template>
|
||
|
<hooper :settings="hooperSettings">
|
||
|
<slide v-for="(n,index) of products" :key="n">
|
||
|
<img :src="'/manga/'+ (index) +'.png'" />
|
||
|
<div class="page_n">{{ n }}</div>
|
||
|
</slide>
|
||
|
<hooper-navigation slot="hooper-addons"></hooper-navigation>
|
||
|
<hooper-pagination slot="hooper-addons"></hooper-pagination>
|
||
|
<hooper-progress slot="hooper-addons"></hooper-progress>
|
||
|
</hooper>
|
||
|
</template>
|
||
|
|
||
|
<script>
|
||
|
import {
|
||
|
Hooper,
|
||
|
Slide,
|
||
|
Progress as HooperProgress,
|
||
|
Pagination as HooperPagination,
|
||
|
Navigation as HooperNavigation
|
||
|
} from 'hooper';
|
||
|
|
||
|
import 'hooper/dist/hooper.css';
|
||
|
|
||
|
export default {
|
||
|
name: 'App',
|
||
|
components: {
|
||
|
Hooper,
|
||
|
Slide,
|
||
|
HooperProgress,
|
||
|
HooperPagination,
|
||
|
HooperNavigation
|
||
|
},
|
||
|
data() {
|
||
|
return {
|
||
|
products: [...Array(Number(process.env.VUE_APP_PAGE)).keys()],
|
||
|
hooperSettings: {
|
||
|
itemsToShow: 1,
|
||
|
centerMode: true
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
};
|
||
|
</script>
|
||
|
|
||
|
<style>
|
||
|
.hooper {
|
||
|
height: 100%;
|
||
|
}
|
||
|
button.hooper-indicator {
|
||
|
background-color: #000;
|
||
|
}
|
||
|
img {
|
||
|
width:640px;
|
||
|
}
|
||
|
.page_n {
|
||
|
text-align: center;
|
||
|
height: 50px;
|
||
|
}
|
||
|
</style>
|
||
|
```
|
||
|
|
||
|
#### hooperのslideをloopで書く
|
||
|
|
||
|
わざわざslideを一つずつ用意するのは面倒ですので、通常はfor,bindなどでloop処理を書くことになると思います。あるいは配列を持ってくるなど。以下は必要な部分の記述です。
|
||
|
|
||
|
```html:src/App.vue
|
||
|
<template>
|
||
|
<hooper :settings="hooperSettings">
|
||
|
<slide v-for="(n,index) of products" :key="n">
|
||
|
<img :src="'/manga/'+ (index) +'.png'" />
|
||
|
<div class="page_n">{{ n }}</div>
|
||
|
</slide>
|
||
|
</hooper>
|
||
|
</template>
|
||
|
|
||
|
export default {
|
||
|
name: 'App',
|
||
|
components: {
|
||
|
Hooper
|
||
|
},
|
||
|
data() {
|
||
|
return {
|
||
|
products: [...Array(Number(process.env.VUE_APP_PAGE)).keys()]
|
||
|
};
|
||
|
}
|
||
|
};
|
||
|
```
|
||
|
|
||
|
何をしているのかというと、環境変数の`VUE_APP_PAGE`から`data{products}`にページ数を入れます。文字列なので数字に変換、それをslideにてループ。
|
||
|
|
||
|
スライドするのは、対応した画像ファイル、`/manga/0.png`,`/manga/1.png`などを順番にスライドさせます。画像ファイルは、`/public/manga/0.png`などの場所に置きます。
|
||
|
|
||
|
v-forは`(n,index) of products`のように書きますが、(n,index)の部分は、`n of products`でもいいです。indexにも数が入ってます。ここで`n,`に続く記述はvueのオプション(vueが用意する変数)のようなものです。
|
||
|
|
||
|
#### hooperのoption
|
||
|
|
||
|
hooperには様々なbarなどが用意されています。基本的にはこんな感じで使います。
|
||
|
|
||
|
```html:src/App.vue
|
||
|
<template>
|
||
|
<hooper :settings="hooperSettings">
|
||
|
// 上の全体位置を示すバー
|
||
|
<hooper-navigation slot="hooper-addons"></hooper-navigation>
|
||
|
// ページ、戻る、進むのボタン
|
||
|
<hooper-pagination slot="hooper-addons"></hooper-pagination>
|
||
|
// 下の全体位置を示す個別ボタン
|
||
|
<hooper-progress slot="hooper-addons"></hooper-progress>
|
||
|
</hooper>
|
||
|
</template>
|
||
|
|
||
|
import {
|
||
|
Hooper,
|
||
|
Slide,
|
||
|
Progress as HooperProgress,
|
||
|
Pagination as HooperPagination,
|
||
|
Navigation as HooperNavigation
|
||
|
} from 'hooper';
|
||
|
```
|
||
|
|
||
|
#### hooperのslideにて指定コンテンツを使う
|
||
|
|
||
|
この場合のスライド出力は、0 - Foo, 1 - Barとなります。`data{items}`を変更すればいいでしょう。vueのexampleを参考にしましょう。
|
||
|
|
||
|
https://jp.vuejs.org/v2/guide/list.html
|
||
|
|
||
|
```html:App.vue
|
||
|
<template>
|
||
|
<hooper :settings="hooperSettings">
|
||
|
<slide v-for="(item, index) in items">
|
||
|
{{ index }} - {{ item.message }}
|
||
|
</slide>
|
||
|
</hooper>
|
||
|
</template>
|
||
|
|
||
|
<script>
|
||
|
import {
|
||
|
Hooper,
|
||
|
Slide
|
||
|
} from 'hooper';
|
||
|
|
||
|
import 'hooper/dist/hooper.css';
|
||
|
|
||
|
export default {
|
||
|
name: 'App',
|
||
|
components: {
|
||
|
Hooper,
|
||
|
Slide
|
||
|
},
|
||
|
data() {
|
||
|
return {
|
||
|
items: [
|
||
|
{ message: 'Foo' },
|
||
|
{ message: 'Bar' }
|
||
|
]
|
||
|
};
|
||
|
}
|
||
|
};
|
||
|
</script>
|
||
|
```
|
||
|
|
||
|
### gh-pages + hugoとの連携
|
||
|
|
||
|
build後のファイルはデフォルトでハッシュ値をつけるので、`vue.config.js`で固定したあとに、gh-actionsを書いていきます。
|
||
|
|
||
|
```js:vue.config.js
|
||
|
module.exports = {
|
||
|
configureWebpack: {
|
||
|
output: {
|
||
|
filename: '[name].js',
|
||
|
chunkFilename: '[name].js'
|
||
|
}
|
||
|
},
|
||
|
css: {
|
||
|
extract: {
|
||
|
filename: '[name].css',
|
||
|
chunkFilename: '[name].css'
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
```
|
||
|
|
||
|
私の場合は、非常にシンプルに、こんな感じになります。これはhugoを使っている場合で少し特殊ですが、ようは、VUE_APP_XXXに自動で画像ファイル数を入れる処理を書いて、build後に出力される必要なファイルを必要な場所にコピーしています。もちろん、buildオプションを指定して直接置くようにしてもいいです。その場合、コピー処理は不要です。
|
||
|
|
||
|
```yml:.github/workflows/gh-pages.yml
|
||
|
run: |
|
||
|
echo VUE_APP_PAGE=`ls ./static/manga/*.png|wc -l` > .env
|
||
|
yarn build
|
||
|
cp -rf ./dist/*.js ./static/manga
|
||
|
cp -rf ./dist/*.css ./static/manga
|
||
|
cp -rf ./dist/*.map ./static/manga
|
||
|
```
|
||
|
|
||
|
私は、hugoを使っているので、以下のように構成しています。
|
||
|
|
||
|
```md:content/manga.md
|
||
|
---
|
||
|
title: "yui | MANGA"
|
||
|
type: manga
|
||
|
page_image : "https://syui.cf/icon/ai.png"
|
||
|
description: "惑星で暮らすドラゴンと少女のお話"
|
||
|
---
|
||
|
|
||
|
<div id=app></div>
|
||
|
<script src=/manga/chunk-vendors.js></script>
|
||
|
<script src=/manga/app.js></script>
|
||
|
```
|
||
|
|
||
|
```html:layouts/manga/single.html
|
||
|
{{ partial "head-blog.html" . }}
|
||
|
{{ partial "header.html" . }}
|
||
|
{{ partial "manga-css.html" . }}
|
||
|
<main>
|
||
|
{{ .Content }}
|
||
|
</main>
|
||
|
</div>
|
||
|
{{ partial "footer.html" . }}
|
||
|
</body>
|
||
|
</html>
|
||
|
```
|
||
|
|
||
|
```html:layouts/partials/manga-css.html
|
||
|
<link href=/manga/app.css rel=preload as=style>
|
||
|
<link href=/manga/app.js rel=preload as=script>
|
||
|
<link href=/manga/chunk-vendors.css rel=preload as=style>
|
||
|
<link href=/manga/chunk-vendors.js rel=preload as=script>
|
||
|
<link href=/manga/chunk-vendors.css rel=stylesheet>
|
||
|
<link href=/manga/app.css rel=stylesheet>
|
||
|
```
|
||
|
|
||
|
つまり、`yarn build`してできた`dist/index.html`の内容をhugoの必要な場所に置き換えます。`dist/index.html`は通常、buildしても内容が変わるものではありません。よって、hugoのほうに記述しても問題ないのです。
|
||
|
|
||
|
|