20200222のvue.jsに関する記事は13件です。

httpbinによる超簡単APIクライアントテスト

概要

外部のAPIモックサーバーhttpbinを利用して、axiosの動作テストをしてみる。

デモ

See the Pen axios test by らい さむ (@tyariponzu614) on CodePen.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

入れ子v-for内でselectを使う

概要

入れ子v-for中のselectタグの選択に応じて、表示を変えたい場合に詰まったのでメモ

デモ

See the Pen v-for usage by らい さむ (@tyariponzu614) on CodePen.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

入れ子v-forでselectを使う

概要

入れ子v-for中のselectタグの選択に応じて、表示を変えたい場合に詰まったのでメモ

デモ

See the Pen v-for usage by らい さむ (@tyariponzu614) on CodePen.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vuetifyに入門する

Vuetifyとは?

Vue.jsのUIライブラリーです。Googleが提唱したマテリアルデザインにのっとっており、直感的で使いやすいコンポーネントを利用することができます。

デザインの知識が全く無くても、簡単にUIを作れちゃいます?

プロジェクトを作成

まずはいつもどおりにvue createでプロジェクトを作成します。

vue create vuetify-project

今回はデフォルトでプロジェクトを作成します。

Vue CLI v4.2.2
? Please pick a preset: default (babel, eslint)
?  Successfully created project vuetify-project.
?  Get started with the following commands:

 $ cd vuetify-project
 $ npm run serve

vuetifyをインストール

プロジェクトの作成が完了したら、プロジェクトのディレクトリに移動して、vuetifyをインストールします。

cd vuetify-project
vue add vuerify

プリセットの選択を聞かれますが、ここもデフォルトを選択します。

? Choose a preset: (Use arrow keys)
❯ Default (recommended) 
  Prototype (rapid development) 
  Configure (advanced) 
✔  Successfully invoked generator for plugin: vue-cli-plugin-vuetify
 vuetify  Discord community: https://community.vuetifyjs.com
 vuetify  Github: https://github.com/vuetifyjs/vuetify
 vuetify  Support Vuetify: https://github.com/sponsors/johnleider

インストールが完了しました?
サーバーを起動してみましょう。

npm run serve

いつもと違う感じの表示になりましたね?

スクリーンショット 2020-02-22 19.11.47.png

実際に使ってみる

インストールが完了したので、実際に使ってみましょう!
基本的な使い方は、v-という前置詞がついたコンポーネントを組み合わせていきます。

使用可能なコンポーネントはすべて公式ドキュメントから確認することができます。
驚くほど種類が多いです。?

とりあえずカルーセルを設置してみましょう!

まずは公式ドキュメントからカルーセルのページを見つけてきます。

スクリーンショット 2020-02-22 20.21.40.png

左側のサイドメニューから探すこともできますし、ページを検索することもできます。
各コンポーネントのページから、イメージや使い方を確認することができます。

コンポーネントを実装する一番手っ取り早い方法はコピペですね!(笑)
公式のサンプルの右上のソースコードのアイコンをクリックすると、コードが表示されるのでそれをコピペしたら完成です!

スクリーンショット 2020-02-22 20.29.32.png
スクリーンショット 2020-02-22 20.29.52.png

vvv.gif

あとはAPIをみてpropsを自分好みに調整したり、コンポーネントを組み合わせたりすれば誰でも簡単にスタイリッシュな画面が作れます?

とりあえずこんな感じに

スクリーンショット 2020-02-22 21.14.56.png

App.vue
<template>
  <v-app>
    <v-app-bar
      app
      color="primary"
      dark
    />
    <v-card
      max-width="400"
      class="mx-auto my-auto"
      hover
    >
      <v-carousel
        cycle
        height="400"
        hide-delimiter-background
        show-arrows-on-hover
      >
        <v-carousel-item
          v-for="(slide, i) in slides"
          :key="i"
        >
          <v-sheet
            :color="colors[i]"
            height="100%"
          >
            <v-row
              class="fill-height"
              align="center"
              justify="center"
            >
              <div class="display-3">{{ slide }} Slide</div>
            </v-row>
          </v-sheet>
        </v-carousel-item>
      </v-carousel>
      <v-card-title>My Carousel</v-card-title>
      <v-card-subtitle class="font-italic font-weight-black">John</v-card-subtitle>
      <v-avatar class="mx-6">
        <img
          src="https://cdn.vuetifyjs.com/images/john.jpg"
          alt="John"
        >
      </v-avatar>
      <v-card-text>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</v-card-text>
    </v-card>
  </v-app>
</template>

<script>
  export default {
    data () {
      return {
        colors: [
          'indigo',
          'warning',
          'pink darken-2',
          'red lighten-1',
          'deep-purple accent-4',
        ],
        slides: [
          'First',
          'Second',
          'Third',
          'Fourth',
          'Fifth',
        ],
      }
    },
  }
</script>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vueデビューしてみた。

久しぶりの投稿です。
Vueを使い始めたので今回は前半はVueの環境構築・後半は私が思ったVueを使用して思った事を書きます。
長々書くのは嫌いなので早速環境を作成していきます。

環境構築

まずはCliをインストールします。

$ npm install -g @vue/cli

インストールが完了したら早速プロジェクトを作成しましょう。

$ vue create {{任意のプロジェクト名}}

作成したら、作成したファイル全てを一階層上のフォルダに移動します。
次に以下のコマンドで起動しましょう。

$ npm run serve

ブラウザで http://localhost:8080/ を開くと作成した画面に遷移できます。
これで基本の環境構築は完了しました。

+Vuetify

次にVueのマテリアルデザインライブラリVuetifyの加えた環境構築を書きます。
といっても上記とほとんど変わらず、プロジェクト作成後

$ vue add vuetify

このコマンドを打つとマテリアルデザインが適応されたページが作成出来てます。

VueとAngular

上記で環境構築は完了しました。
ここからは私が感じたVueとAngularについてつらつら書いていきます。

1. 構成

  初見で違いを感じたのは
  Angularはjs(ts)・html・cssが全て 別ファイル で管理されているのに対して
  VueはVueファイル内にjs・hrml・css全てが 同ファイル内 で管理されます。
  ※勿論Vueも別ファイルで管理できます。但しhtml→Vueファイルになります。

  実装していく上では対して影響はないですが、考え方の違いを感じました。

2.  html記述方法

  htmlの記述方法はあまりAngularと違和感を感じませんでした。
  デフォルトの属性がng-xxxからv-xxxになった程度で直ぐに適応できます。
  バインディング方法も変わらず、js側の受け取りが多少違うだけで直ぐに適応できます。

3.  TypeScript

  個人的には静的型付けが好きなのでVueでもTypeScriptで書きたいです。(anyは絶対許しません。)
  Angularは公式にTypeScript推奨なのでTypeScriptの書き方さえ覚えてしまえば問題ありません。
  対してVueはJavaScript推奨なのでAngularと比べるとTypeScriptで書きにくいと感じてしまいます。

4.  マテリアルデザイン

  私はマテリアルデザインを好んで使っています。
  AngularはAngular Materialという王がいます。VueはVuetifyというマテリアルデザインが人気です。
  どちらも完成度が高く素晴らしいのですが、Vuetifyの方が様々なインターフェースを用意しており
  UIデザインに幅がでます。ただ、コピペしてすぐ確認できる最小構成のサンプルコードが無く、そこが残念に思います。
  Angular Materialはその逆です。

以上が私が数ヶ月Vueを使った感想です。
Angular系を半年以上使用していた人は3日もあればVueに適応出来ると思います。
評判通りVueは使いやすく、良いフレームワークです。新規製品を作る場合は大規模製品でも私はVueを押します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vueで「Hello Vue!!」を出力する

Hello Vueを出力する

Vue.jsは大きく分けて「出力の部分」と「スクリプト」の2か所から成り立っています。
「Hello Vue!!」を出力する方法を例に見ていきましょう。!

スクリーンショット 2020-02-22 19.24.32.png

ソースコードは以下の通りです。

<!DOCTYPE html>
<html>
    <head>
        <title>My first Vue app</title>
        <script src="https://unpkg.com/vue"></script>
    </head>

    <body>
        <h1>Vue.js</h1>
        <div id="app">
             {{ message}} <!--この中にはJsの式もかける -->
        </div>

        <script>
            // 連想配列(オブジェクト)
            var data = {
                message: 'hello Vue!'
            }

            //インスタンス化
            var app = new Vue({
                el: '#app',
                data: data,
            })

        </script>
    </body>
</html>

解説

表示部分

   <div id="app">
             {{ message}} <!--この中にはJsの式もかける -->
    </div>

上のコードのポイントは2つです。
・[id="app"]とcssセレクタを宣言している点。
・{{message}}で変数のmessageに値を入れている点。ちなみにこの構文をムスタシェ構文という。(らしい笑)

id="app"によりappインスタンスが指定されます。
{{message}}ではscript部分にて定義したデータが入ります。

script部分

<script>
            // 連想配列(オブジェクト)
            var data = {
                message: 'Hello Vue!!'
            }

            //インスタンス化
            var app = new Vue({
                el: '#app',
                data: data,
            })

  </script>

Vueインスタンス作成方法

Vueインスタンスの作成。
var 変数 = new Vue({オブジェクト})

オブジェクトの中身は以下の形で宣言します。
{el:対象,data:値(オブジェクト)}
対象:[タグにつけたセレクタ]
値:オブジェクトを配置

3行目~5行目:var data ={‥省略‥}:dataという変数にオブジェクトを作っています。
今回は「Hello Vue!!」と出力したいので、messageに与えるデータを
message: 'Hello Vue!!'としています。

目~11行目:var app = new Vue({‥}):Vueオブジェクトのインスタンスを作成しています。
el:''#appとする事でappインスタンスを作成し、data: data,とする事でdataにvar dataに定義した値を入れています。

これにて「Hello Vue!!」の出力完了となります!!
お疲れ様です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

vue cli のインストール

vue cliが使いたい(mac)

前提としてnodeがインストールされていること

npm install -g vue-cli

vue --version
記載時点では2.9.6がインストールされた。

vue createしたら
`$ vue create vue-app

vue create is a Vue CLI 3 only command and you are using Vue CLI 2.9.6.
You may want to run the following to upgrade to Vue CLI 3:

npm uninstall -g vue-cli
npm install -g @vue/cli
`
verが足りなかったのでやり直し

npm uninstall -g vue-cli
removed 240 packages in 6.14s

npm install -g @vue/cli

npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated core-js@2.6.11: core-js@<3 is no longer maintained and not recommended for usage due to the number of issues. Please, upgrade your dependencies to the actual version of core-js@3.
/Users/hoge/.nodebrew/node/v13.9.0/bin/vue -> /Users/hoge/.nodebrew/node/v13.9.0/lib/node_modules/@vue/cli/bin/vue.js

> fsevents@1.2.11 install /Users/hoge/.nodebrew/node/v13.9.0/lib/node_modules/@vue/cli/node_modules/fsevents
> node-gyp rebuild

No receipt for 'com.apple.pkg.CLTools_Executables' found at '/'.

No receipt for 'com.apple.pkg.DeveloperToolsCLILeo' found at '/'.

No receipt for 'com.apple.pkg.DeveloperToolsCLI' found at '/'.

gyp: No Xcode or CLT version detected!
gyp ERR! configure error 
gyp ERR! stack Error: `gyp` failed with exit code: 1
gyp ERR! stack     at ChildProcess.onCpExit (/Users/hoge/.nodebrew/node/v13.9.0/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:351:16)
gyp ERR! stack     at ChildProcess.emit (events.js:321:20)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:275:12)
gyp ERR! System Darwin 19.3.0
gyp ERR! command "/Users/hoge/.nodebrew/node/v13.9.0/bin/node" "/Users/hoge/.nodebrew/node/v13.9.0/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /Users/hoge/.nodebrew/node/v13.9.0/lib/node_modules/@vue/cli/node_modules/fsevents
gyp ERR! node -v v13.9.0
gyp ERR! node-gyp -v v5.0.7
gyp ERR! not ok 

> core-js@2.6.11 postinstall /Users/hoge/.nodebrew/node/v13.9.0/lib/node_modules/@vue/cli/node_modules/babel-polyfill/node_modules/core-js
> node -e "try{require('./postinstall')}catch(e){}"

Thank you for using core-js ( https://github.com/zloirock/core-js ) for polyfilling JavaScript standard library!

The project needs your help! Please consider supporting of core-js on Open Collective or Patreon: 
> https://opencollective.com/core-js 
> https://www.patreon.com/zloirock 

Also, the author of core-js ( https://github.com/zloirock ) is looking for a good job -)


> core-js@2.6.11 postinstall /Users/hoge/.nodebrew/node/v13.9.0/lib/node_modules/@vue/cli/node_modules/babel-runtime/node_modules/core-js
> node -e "try{require('./postinstall')}catch(e){}"


> core-js@3.6.4 postinstall /Users/hoge/.nodebrew/node/v13.9.0/lib/node_modules/@vue/cli/node_modules/core-js
> node -e "try{require('./postinstall')}catch(e){}"


> @apollo/protobufjs@1.0.3 postinstall /Users/hoge/.nodebrew/node/v13.9.0/lib/node_modules/@vue/cli/node_modules/@apollo/protobufjs
> node scripts/postinstall


> nodemon@1.19.4 postinstall /Users/hoge/.nodebrew/node/v13.9.0/lib/node_modules/@vue/cli/node_modules/nodemon
> node bin/postinstall || exit 0

Love nodemon? You can now support the project via the open collective:
 > https://opencollective.com/nodemon/donate


> ejs@2.7.4 postinstall /Users/hoge/.nodebrew/node/v13.9.0/lib/node_modules/@vue/cli/node_modules/ejs
> node ./postinstall.js

Thank you for installing EJS: built with the Jake JavaScript build tool (https://jakejs.com/)

npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.11 (node_modules/@vue/cli/node_modules/fsevents):
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.11 install: `node-gyp rebuild`
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: Exit status 1

+ @vue/cli@4.2.2
added 1105 packages from 648 contributors in 238.581s

gyp: No Xcode or CLT version detected!
が出ていたのでnode-gypをいれて
npm install node-gyp

xcode command line toolを使うように設定
sudo xcode-select --switch /Applications/Xcode.app
一度アンインストール
npm uninstall -g @vue/cli
もうちいどやってみる
npm install -g @vue/cli
今度はエラーなく成功。
XCodeのCommand line toolも必要のようですが、それは入れてあったのでnode-gypをいれただけで大丈夫だった

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue + Ionic つまずかない環境構築

はじめに

環境構築でつまずいてしまったので、情報共有のために
2020/2/22現在の環境構築手順の解説をします

vueのプロジェクト作成

vue create {プロジェクト名}

typescriptを追加するとIonicとnamespaceがかぶるためなるべく選ばないが吉
それ以外はお好みで

作成したら

cd {プロジェクト名}

でディレクトリを移動

Ionicの追加

(1)~(4)の順番はどうでもいいです

vue add ionic
npm i @ionic/vue vue-router @capacitor/core @capacitor/cli ionicons@4.5.9-1

yarnよりnpmの方がいいらしいのでnpmで追加

(1) main.jsに追加

main.js
import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import router from './router'
import store from './store'
import './plugins/ionic.js'
+ import Ionic from '@ionic/vue';

+ Vue.use(Ionic);
Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

この二つをmain.jsに追加

(2) app.vue

app.vue
<template>
  <div id="app">
    <ion-app>
      <ion-vue-router />
    </ion-app>
  </div>
</template>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

を追加
後述するがroutingもionic-vue-routerを使用するため変更

(3) Home.vueとAbout.vueを変更(確認のため)

Home.vue
<template>
  <div class="ion-page">
    <ion-header>
      <ion-toolbar>
        <ion-title>About Page</ion-title>
      </ion-toolbar>
    </ion-header>
    <ion-content class="ion-padding">
      <h1>Welcome To @ionic/vue</h1>
      <img alt="Vue logo" src="../assets/logo.png" />
      <div>
        <ion-button @click="onClick()" full>Go to About Page</ion-button>
      </div>
    </ion-content>
  </div>
</template>

<script>
export default {
  name: "home",
  methods: {
    onClick () {
      this.$router.push('about')
    }
  }
}
</script>
About.vue
<template>
  <div class="about">
    <ion-header>
      <ion-toolbar>
        <ion-buttons slot="start">
          <ion-back-button></ion-back-button>
        </ion-buttons>
        <ion-title>Hello World</ion-title>
      </ion-toolbar>
    </ion-header>
    <ion-content class="ion-padding">
      <h1>This is an about page</h1>
    </ion-content>
  </div>
</template>

(4) routerをionic-vue-routerに変更

router.js
import Vue from 'vue'
import Home from '../views/Home.vue'
import About from '../views/About.vue'
import { IonicVueRouter } from '@ionic/vue'

Vue.use(IonicVueRouter)

export default new IonicVueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (about.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: About
    }
  ]
})


開発用サーバーを立てる

npm run serve

するとerrorが出てしまう
Ionicのbugが原因らしい

詳しくはここで
bug: Ionic/vue ionicons error

バグを解決するために@Ionic/vueのバージョンを更新する

npm install @ionic/vue@0.0.9

すると解決して
無事構築完了

Feb-22-2020 18-03-56.gif

動きが気持ちいいね!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vuetify2系のグリッドシステムの属性について

はじめに

以前Vuetifyのグリッドシステムがよく分からなかったので調査した記事を作成したが、Vuetifyのメジャーバージョンアップ(1.5→2.x)により内容が古くなってしまった。
バージョンアップ自体は結構前でもう古いバージョンのVuetifyは使われなさそうだし、色々属性名も変わったりしたようなので、調査のために再度まとめた。

確認のために作成したコード

https://nulltemp.github.io/vuetify2-test/
https://github.com/nulltemp/vuetify2-test

基本的な変更点

https://vuetifyjs.com/ja/components/grids
v-containerはそのままだが、v-layoutv-rowに、v-flexv-colに変わっている。

各属性について

v-containerの属性

fluid

See the Pen qBdZRRm by nulltemp (@nulltemp) on CodePen.

要素の最大幅に絡む設定。元の説明だとビューポートの最大幅を削除するとか書いてある。倍率変えたりCodePenのリンク直接見たりすると効果が分かる。
実はいまだに使い道をよく分かっていない。

v-rowの属性

align

See the Pen vuetify2 align by nulltemp (@nulltemp) on CodePen.

start, center, end, baseline, stretchの5つがあり、各要素の位置の基準をどこに置くかが変わる。stretchは2系で新しく追加されたもので、高さがなんか引き延ばされる。
詳細はこの辺りを参照。
また、align-<xx>という属性もあり、画面サイズによってalignの値を変化させることが出来る。一番下は一見align="center"だが、align-xl="stretch"を指定しているため、大画面で見るとstretchを指定したときと同じ振る舞いになる。

align-content

See the Pen vuetify2 align-content by nulltemp (@nulltemp) on CodePen.

start, center, end, space-between, space-around, stretchの6つがあり、各要素が複数行に分かれたときの配置を決定する。stretchは2系で新しく追加されたもので、高さがなんか引き延ばされる。
詳細はこの辺りを参照。
また、align-content-<xx>という属性もあり、画面サイズによってalign-contentの値を変化させることが出来る。一番下は一見align-content="center"だが、align-content-xl="stretch"を指定しているため、大画面で見るとstretchを指定したときと同じ振る舞いになる。

dense

See the Pen vuetify2 dense by nulltemp (@nulltemp) on CodePen.

多分1系にはなかった属性。分かり辛いが恐らくpaddingに絡む設定で、trueにするとpaddingが小さくなる。

justify

See the Pen vuetify2 justify by nulltemp (@nulltemp) on CodePen.

start, center, end, space-between, space-aroundの5つがあり、各要素の配置に絡む設定になる。
詳細はこの辺りを参照。
また、justify-<xx>という属性もあり、画面サイズによってjustifyの値を変化させることが出来る。一番下は一見justify="center"だが、justify-xl="space-between"を指定しているため、大画面で見るとspace-betweenを指定したときと同じ振る舞いになる。

no-gutters

See the Pen KKpzqzL by nulltemp (@nulltemp) on CodePen.

多分1系にはなかった属性。denseと同じくpaddingに絡む設定のようで、こちらはtrueにするとpaddingが0になるらしい。

v-colの属性

align-self

See the Pen vuetify2 align-self by nulltemp (@nulltemp) on CodePen.

alignの値を上書きする属性。上記はv-rowalignstartを指定しているが、最後のv-colだけalign-self="end"を指定しているため、ほかと振る舞いが異なっている。

cols

See the Pen JjdbOBd by nulltemp (@nulltemp) on CodePen.

1系だと(size)(1-12)xs2とか)で指定していた各グリッドのサイズだが、2系だとcols="5"等のやり方で指定するようになった。また、値にはautoという値が指定できるようになり、どうも内部の値によって幅が可変になるらしい。
例として以前のxs12は今回だとcols="12"になり、その他sm12xl12はそれぞれsm="12"xl="12"になる。

offset

See the Pen vuetify2 offset by nulltemp (@nulltemp) on CodePen.

各グリッド間のオフセットを指定することが出来る。
また、offset-<xx>という属性もあり、画面サイズによってoffsetの値を変化させることが出来る。一番下は一見offset="1"だが、offset-xl="5"を指定しているため、大画面で見るとoffset="5"を指定したときと同じ振る舞いになる。

order

See the Pen vuetify2 order by nulltemp (@nulltemp) on CodePen.

各グリッドの並び順を指定できる。詳細はこの辺りを参照。
値は-1~12およびfirst, lastが使えるらしいが、-1だけちょっとうまくいかなかった。
また、order-<xx>という属性もあり、画面サイズによってorderの値を変化させることが出来る。一番下の緑のグリッドは一見order="1"だが、order-xl="last"を指定しているため、大画面で見るとorder="last"を指定したときと同じ振る舞いになる。

その他

1系では要素をinlineにするかどうか等を指定するd-{type}や要素の改行?に関するwrap、要素の並び方を指定するcolumn等の属性があったが、これらはクラスとして指定する形になったらしい(未確認)。
https://vuetifyjs.com/ja/styles/flex/

また、各要素間のpaddingを指定するgrid-list-{xs through xl}という属性があったが、こちらは{property}{direction}-{size}という形式の新しい属性で対応するようになったらしい新しい属性かと思ったら前からあったやつだった。ただ完全に同一の属性が存在するかどうか分からなかったので、やはりこの属性で対応することになりそう(未確認)。細かい説明は以下に書いてある。
https://vuetifyjs.com/ja/styles/spacing/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vueの練習がてら作ったSNS風な爆簡易アプリを解説する�。

前提

こんにちは、Vue初心者です。(いまさら。)
ドットインストールのVueの基礎講座でVueについて勉強してみて、この知識だけで作れそうな爆簡易アプリを作ってみました。

処理をただ書いているだけなので綺麗じゃないのかもですが、春を感じさせるあたたかさを持ってご覧ください。

なお、コードの解説を加えていきますが、Vueについてのみ解説入れますので

  • HTMLとCSSは最低限理解している

必要はあるかと思います。(念の為)

完成形

ソースコード

ソースはGithubにアップしています。

view部分となるindex.html

Vue.jsに関係がある部分のみを抜き出しています。

index.html
<div id="app" class="containier">
    <div v-if="chackers.length">
        <section class="card" v-for="(chacker, index) in chackers">
            <div class="text">
                <p>{{ chacker.text }}</p>
            </div>
            <div class="option">
                <span class="setting" @click="openSetting(index)"></span>
                <div class="reaction" @click="addFire(index)">
                    <svg version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
                        y="0px" width="100%" height="100%" viewBox="0 0 512 512" xml:space="preserve">
                        <g>
                            <path class="fire" v-bind:class="{burn: chackers[index].fire}"  d="M332.16,104.596c-34.594-27.688-48.125-58.25-53.328-79.969c-4.172-17.453-1.953-19.328-1.953-19.328
                            c-0.219-2.078-1.5-3.875-3.406-4.75c-1.875-0.875-4.094-0.703-5.797,0.484c0,0-6.703,1.453-17.641,12.063
                            c-24.875,24.156-53.031,64.469-34.469,119.578c19.891,59.125,9.375,71.5-1.047,70.688c-13.516-1.031-15.609-9.359-13.438-35.266
                            c2.516-30.281-24.953-56.141-24.953-56.141s-42.672,67.844-75.953,116.375c-19.672,28.688-29.109,65.141-29.109,98.406H70.41
                            c0,102.313,82.938,185.266,185.25,185.266s185.25-82.953,185.25-185.266C447.941,237.893,399.691,158.611,332.16,104.596z
                            M255.988,459.83c-56.422,0-102.188-45.75-102.188-102.188c0-19.219,5.328-37.188,14.547-52.547
                            c7.938,29.563,34.906,51.328,66.969,51.328c38.281,0,69.344-31.047,69.344-69.344c0-7.297-1.156-14.359-3.25-20.969
                            c33.656,16.719,56.766,51.422,56.766,91.531C358.175,414.08,312.425,459.83,255.988,459.83z"></path>
                        </g>
                    </svg>
                    <span  v-bind:class="{turnRed: chackers[index].fire}">{{chacker.fire}}</span>
                </div>
            </div>
            <div class="settingModal" v-bind:class="{settingOpen: chacker.setting}">
                <span @click="closeSettingModal">×</span>
                <p @click="deleteChacker(index)" >Delete this FIRE</p>
            </div>
        </section>
    </div>
    <div v-else>
        <p class="noFire">NO Chaker<br>NO FIRE</p>
    </div>
    <button class="new" @click="openFormModal">
        <svg version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
        y="0px" width="100%" height="100%" viewBox="0 0 512 512" xml:space="preserve">
            <g>
                <path class="fire" d="M332.16,104.596c-34.594-27.688-48.125-58.25-53.328-79.969c-4.172-17.453-1.953-19.328-1.953-19.328
                                        c-0.219-2.078-1.5-3.875-3.406-4.75c-1.875-0.875-4.094-0.703-5.797,0.484c0,0-6.703,1.453-17.641,12.063
                                        c-24.875,24.156-53.031,64.469-34.469,119.578c19.891,59.125,9.375,71.5-1.047,70.688c-13.516-1.031-15.609-9.359-13.438-35.266
                                        c2.516-30.281-24.953-56.141-24.953-56.141s-42.672,67.844-75.953,116.375c-19.672,28.688-29.109,65.141-29.109,98.406H70.41
                                        c0,102.313,82.938,185.266,185.25,185.266s185.25-82.953,185.25-185.266C447.941,237.893,399.691,158.611,332.16,104.596z
                                        M255.988,459.83c-56.422,0-102.188-45.75-102.188-102.188c0-19.219,5.328-37.188,14.547-52.547
                                        c7.938,29.563,34.906,51.328,66.969,51.328c38.281,0,69.344-31.047,69.344-69.344c0-7.297-1.156-14.359-3.25-20.969
                                        c33.656,16.719,56.766,51.422,56.766,91.531C358.175,414.08,312.425,459.83,255.988,459.83z"></path>
            </g>
        </svg>
    </button>
    <div class="new-form" v-bind:class="{modalOpen: formModal}">
        <span @click="closeFormModal">×</span>
        <form @submit.prevent="addChacker">
            <textarea v-model="newChacker"></textarea>
            <button type="submit">
                <svg version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
                    y="0px" width="100%" height="100%" viewBox="0 0 512 512" xml:space="preserve">
                    <g>
                        <path class="burn" d="M332.16,104.596c-34.594-27.688-48.125-58.25-53.328-79.969c-4.172-17.453-1.953-19.328-1.953-19.328
                                                                c-0.219-2.078-1.5-3.875-3.406-4.75c-1.875-0.875-4.094-0.703-5.797,0.484c0,0-6.703,1.453-17.641,12.063
                                                                c-24.875,24.156-53.031,64.469-34.469,119.578c19.891,59.125,9.375,71.5-1.047,70.688c-13.516-1.031-15.609-9.359-13.438-35.266
                                                                c2.516-30.281-24.953-56.141-24.953-56.141s-42.672,67.844-75.953,116.375c-19.672,28.688-29.109,65.141-29.109,98.406H70.41
                                                                c0,102.313,82.938,185.266,185.25,185.266s185.25-82.953,185.25-185.266C447.941,237.893,399.691,158.611,332.16,104.596z
                                                                M255.988,459.83c-56.422,0-102.188-45.75-102.188-102.188c0-19.219,5.328-37.188,14.547-52.547
                                                                c7.938,29.563,34.906,51.328,66.969,51.328c38.281,0,69.344-31.047,69.344-69.344c0-7.297-1.156-14.359-3.25-20.969
                                                                c33.656,16.719,56.766,51.422,56.766,91.531C358.175,414.08,312.425,459.83,255.988,459.83z"></path>
                    </g>
                </svg>
            </button>
        </form>
    </div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="./static/js/main.js"></script>

Vue.jsの全文

全然たいした量じゃないんです。

main.js
(function(){
    'use strict';

    let vm = new Vue({
        el: '#app',
        data: {
            formModal: false,
            newChacker: '',
            chackers:[
            ]
        },
        methods:{
            openFormModal: function(){
                this.formModal = true
            },
            openSetting: function(index){
                this.chackers[index].setting = true
            },
            closeFormModal: function () {
                this.formModal = false
            },
            closeSettingModal: function () {
                this.chackers[index].setting = false
            },
            addChacker: function(){
                let item = {
                    text: this.newChacker,
                    fire: 0,
                    setting: false
                }
                this.chackers.push(item);
                this.newChacker='';
                this.formModal=false;
            },
            addFire: function(index){
                this.chackers[index].fire++
            },
            deleteChacker: function(index){
                this.chackers.splice(index, 1);
            }
        }
    });
})();

解説するざます。

個人的な解釈で言葉が実際の定義と違ったり、わかりにくかったりするかもしれませんが、ご了承くださいませ

1.htmlにVue.jsを反映させる

index.html
<div id="app" class="containier"> <!--id="app"のdivを後ほどVueで使うよと定義します。-->
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!--Vue.jsを使うために必要です。bodyを閉じる直前で呼び出せばOK-->
<script src="./static/js/main.js"></script><!--自分で書くVue.jsを呼び出します。-->
main.js
(function(){ //即時関数ってやつです。
    'use strict'; //厳密なエラーチェックを可能に

    let vm = new Vue({ //Vue.jsを使うよと宣言します。
        el: '#app' //vmという変数に入れるVueの処理はhtmlのid="app"の要素(今回はdivですね)に使うよと宣言します。
        });
})();

2.Vueで管理するデータを定義

main.js
(function(){
    'use strict';

    let vm = new Vue({
        el: '#app',
        data: {
            formModal: false, //投稿用フォームをモーダル表示させるのですが、デフォルトは非表示に
            newChacker: '', //新しい投稿フォームには空を設定
            chackers:[ //投稿はオブジェクトとして管理
            ]
        },

3.htmlに投稿表示欄をつくる

index.html
<div id="app" class="containier">
    <div v-if="chackers.length"> <!--もし投稿があれば(投稿オブジェクト数が1以上なら)-->
        <section class="card" v-for="(chacker, index) in chackers"> <!--オブジェクトの数だけ繰り返し処理-->
            <div class="text">
                <p>{{ chacker.text }}</p> <!--投稿内容を表示-->
            </div>
            <div class="option">
                <span class="setting" @click="openSetting(index)"></span> <!--消すためのモーダルを表示するメソッドを呼び出す-->
                <div class="reaction" @click="addFire(index)"> <!--いいねを押せるメソッドを呼び出す-->
                    <svg version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
                        y="0px" width="100%" height="100%" viewBox="0 0 512 512" xml:space="preserve">
                        <g> <!--v-binde:classでこの投稿のfireが1以上なら(=クリックされたことがあるなら)burnクラスをつける-->
                            <path class="fire" v-bind:class="{burn: chackers[index].fire}"  d="M332.16,104.596c-34.594-27.688-48.125-58.25-53.328-79.969c-4.172-17.453-1.953-19.328-1.953-19.328
                            c-0.219-2.078-1.5-3.875-3.406-4.75c-1.875-0.875-4.094-0.703-5.797,0.484c0,0-6.703,1.453-17.641,12.063
                            c-24.875,24.156-53.031,64.469-34.469,119.578c19.891,59.125,9.375,71.5-1.047,70.688c-13.516-1.031-15.609-9.359-13.438-35.266
                            c2.516-30.281-24.953-56.141-24.953-56.141s-42.672,67.844-75.953,116.375c-19.672,28.688-29.109,65.141-29.109,98.406H70.41
                            c0,102.313,82.938,185.266,185.25,185.266s185.25-82.953,185.25-185.266C447.941,237.893,399.691,158.611,332.16,104.596z
                            M255.988,459.83c-56.422,0-102.188-45.75-102.188-102.188c0-19.219,5.328-37.188,14.547-52.547
                            c7.938,29.563,34.906,51.328,66.969,51.328c38.281,0,69.344-31.047,69.344-69.344c0-7.297-1.156-14.359-3.25-20.969
                            c33.656,16.719,56.766,51.422,56.766,91.531C358.175,414.08,312.425,459.83,255.988,459.83z"></path>
                        </g>
                    </svg>
                    <span  v-bind:class="{turnRed: chackers[index].fire}">{{chacker.fire}}</span><!--いいねの数を表示する(この投稿のfireが1以上なら(=クリックされたことがあるなら)turnRedクラスをつける。)-->
                </div>
            </div>
            <div class="settingModal" v-bind:class="{settingOpen: chacker.setting}"><!--投稿のsettingの値がtrueならsettingOpenクラスをつける。-->
                <span @click="closeSettingModal">×</span><!--投稿削除のためのモーダルを非表示にする-->
                <p @click="deleteChacker(index)" >Delete this FIRE</p><!--投稿を削除する-->
            </div>
        </section>
    </div>
    <div v-else> //もし投稿がなければ
        <p class="noFire">NO Chaker<br>NO FIRE</p>
    </div>
</div>

4.Vue.jsでメソッドをつくる

今回つくるメソッド

3.htmlに投稿表示欄をつくるで呼び出されていたメソッドは以下です。
これらを2.Vueで管理するデータを定義でつくったファイルに加えていきます。

openSetting //投稿を削除するためのモーダルを表示する
closeSettingModal //投稿を削除するためのモーダルを非表示にする
addFire //いいねを押す
deleteChacker//投稿を削除する

それでは加えていきます。

main.js
(function(){
    'use strict';

    let vm = new Vue({
        el: '#app',
        data: {
            formModal: false,
            newChacker: '',
            chackers:[
            ]
        },
        methods:{ //メソッドを定義するエリア
            openSetting: function(index){
                this.chackers[index].setting = true //index番目(forの繰り返し処理で渡されてくる値)の投稿のsettingをtrueにします。
            },
            closeSettingModal: function () {
                this.chackers[index].setting = false //index番目の投稿のsettingをfalseにします。
            },
            addFire: function(index){
                this.chackers[index].fire++ //index番目の投稿のfireに1を加えます。
            },
            deleteChacker: function(index){
                this.chackers.splice(index, 1); //index番目の投稿から数えて1つ目の投稿を削除します。(つまりindex番目の投稿だけが削除されます)
            }
        }
    });
})();

5.htmlに投稿フォームをつくる

index.html
<div id="app" class="containier">
    <div v-if="chackers.length">
        <section class="card" v-for="(chacker, index) in chackers">
            <div class="text">
                <p>{{ chacker.text }}</p>
            </div>
            <div class="option">
                <span class="setting" @click="openSetting(index)"></span>
                <div class="reaction" @click="addFire(index)">
                    <svg version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
                        y="0px" width="100%" height="100%" viewBox="0 0 512 512" xml:space="preserve">
                        <g>
                            <path class="fire" v-bind:class="{burn: chackers[index].fire}"  d="M332.16,104.596c-34.594-27.688-48.125-58.25-53.328-79.969c-4.172-17.453-1.953-19.328-1.953-19.328
                            c-0.219-2.078-1.5-3.875-3.406-4.75c-1.875-0.875-4.094-0.703-5.797,0.484c0,0-6.703,1.453-17.641,12.063
                            c-24.875,24.156-53.031,64.469-34.469,119.578c19.891,59.125,9.375,71.5-1.047,70.688c-13.516-1.031-15.609-9.359-13.438-35.266
                            c2.516-30.281-24.953-56.141-24.953-56.141s-42.672,67.844-75.953,116.375c-19.672,28.688-29.109,65.141-29.109,98.406H70.41
                            c0,102.313,82.938,185.266,185.25,185.266s185.25-82.953,185.25-185.266C447.941,237.893,399.691,158.611,332.16,104.596z
                            M255.988,459.83c-56.422,0-102.188-45.75-102.188-102.188c0-19.219,5.328-37.188,14.547-52.547
                            c7.938,29.563,34.906,51.328,66.969,51.328c38.281,0,69.344-31.047,69.344-69.344c0-7.297-1.156-14.359-3.25-20.969
                            c33.656,16.719,56.766,51.422,56.766,91.531C358.175,414.08,312.425,459.83,255.988,459.83z"></path>
                        </g>
                    </svg>
                    <span  v-bind:class="{turnRed: chackers[index].fire}">{{chacker.fire}}</span>
                </div>
            </div>
            <div class="settingModal" v-bind:class="{settingOpen: chacker.setting}">
                <span @click="closeSettingModal">×</span>
                <p @click="deleteChacker(index)" >Delete this FIRE</p>
            </div>
        </section>
    </div>
    <div v-else>
        <p class="noFire">NO Chaker<br>NO FIRE</p>
    </div>
    <button class="new" @click="openFormModal"> <!--投稿フォームのモーダルを開くメソッドを呼び出す-->
        <svg version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
        y="0px" width="100%" height="100%" viewBox="0 0 512 512" xml:space="preserve">
            <g>
                <path class="fire" d="M332.16,104.596c-34.594-27.688-48.125-58.25-53.328-79.969c-4.172-17.453-1.953-19.328-1.953-19.328
                                        c-0.219-2.078-1.5-3.875-3.406-4.75c-1.875-0.875-4.094-0.703-5.797,0.484c0,0-6.703,1.453-17.641,12.063
                                        c-24.875,24.156-53.031,64.469-34.469,119.578c19.891,59.125,9.375,71.5-1.047,70.688c-13.516-1.031-15.609-9.359-13.438-35.266
                                        c2.516-30.281-24.953-56.141-24.953-56.141s-42.672,67.844-75.953,116.375c-19.672,28.688-29.109,65.141-29.109,98.406H70.41
                                        c0,102.313,82.938,185.266,185.25,185.266s185.25-82.953,185.25-185.266C447.941,237.893,399.691,158.611,332.16,104.596z
                                        M255.988,459.83c-56.422,0-102.188-45.75-102.188-102.188c0-19.219,5.328-37.188,14.547-52.547
                                        c7.938,29.563,34.906,51.328,66.969,51.328c38.281,0,69.344-31.047,69.344-69.344c0-7.297-1.156-14.359-3.25-20.969
                                        c33.656,16.719,56.766,51.422,56.766,91.531C358.175,414.08,312.425,459.83,255.988,459.83z"></path>
            </g>
        </svg>
    </button>
    <div class="new-form" v-bind:class="{modalOpen: formModal}"> <!--formModalがtrueのときmodalOpenクラスをつける-->
        <span @click="closeFormModal">×</span> <!--投稿フォームモーダルを閉じるメソッドを呼び出す-->
        <form @submit.prevent="addChacker"> <!--投稿内容を反映するためのメソッドを呼び出す。-->
            <textarea v-model="newChacker"></textarea> <!--投稿内容とnewChackerというモデルを紐付ける-->
            <button type="submit">
                <svg version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
                    y="0px" width="100%" height="100%" viewBox="0 0 512 512" xml:space="preserve">
                    <g>
                        <path class="burn" d="M332.16,104.596c-34.594-27.688-48.125-58.25-53.328-79.969c-4.172-17.453-1.953-19.328-1.953-19.328
                                                                c-0.219-2.078-1.5-3.875-3.406-4.75c-1.875-0.875-4.094-0.703-5.797,0.484c0,0-6.703,1.453-17.641,12.063
                                                                c-24.875,24.156-53.031,64.469-34.469,119.578c19.891,59.125,9.375,71.5-1.047,70.688c-13.516-1.031-15.609-9.359-13.438-35.266
                                                                c2.516-30.281-24.953-56.141-24.953-56.141s-42.672,67.844-75.953,116.375c-19.672,28.688-29.109,65.141-29.109,98.406H70.41
                                                                c0,102.313,82.938,185.266,185.25,185.266s185.25-82.953,185.25-185.266C447.941,237.893,399.691,158.611,332.16,104.596z
                                                                M255.988,459.83c-56.422,0-102.188-45.75-102.188-102.188c0-19.219,5.328-37.188,14.547-52.547
                                                                c7.938,29.563,34.906,51.328,66.969,51.328c38.281,0,69.344-31.047,69.344-69.344c0-7.297-1.156-14.359-3.25-20.969
                                                                c33.656,16.719,56.766,51.422,56.766,91.531C358.175,414.08,312.425,459.83,255.988,459.83z"></path>
                    </g>
                </svg>
            </button>
        </form>
    </div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="./static/js/main.js"></script>

6.Vue.jsで更にメソッドをつくる

今回つくるメソッド

5.htmlに投稿フォームをつくるで新たに呼び出されていたメソッドは以下です。
これらを4.Vue.jsでメソッドをつくるで編集したファイルに加えていきます。

openFormModal //投稿フォームのモーダルを表示する
closeFormModal //投稿フォームのモーダルを非表示にする
addChacker //投稿内容を反映する

それでは加えていきます。

main.js
(function(){
    'use strict';

    let vm = new Vue({
        el: '#app',
        data: {
            formModal: false,
            newChacker: '',
            chackers:[
            ]
        },
        methods:{
            openFormModal: function(){ //formModalの値をtrueにします。
                this.formModal = true
            },
            openSetting: function(index){
                this.chackers[index].setting = true 
            },
            closeFormModal: function () {
                this.formModal = false //formModalの値をfalseにします。
            },
            closeSettingModal: function () {
                this.chackers[index].setting = false
            },
            addChacker: function(){ //投稿内容を反映します。
                let item = { //itemという変数に入れたいデータを入れていきます。

                    text: this.newChacker, //投稿内容をいれ、
                    fire: 0, //いいね数を0にし、
                    setting: false //設定はデフォルトでは開いていない状態にします。
                }
                this.chackers.push(item); //投稿内容のオブジェクトにitemの内容をいれ、
                this.newChacker=''; //用済みの投稿内容を空にし、
                this.formModal=false; //投稿フォームのモーダルを閉じてあげます。
            },
            addFire: function(index){
                this.chackers[index].fire++
            },
            deleteChacker: function(index){
                this.chackers.splice(index, 1);
            }
        }
    });
})();

\ 完成です /

感想、Vue楽しい。

Vueを勉強してまだ日が浅いのですが、こんなに簡単で、こんなにサクサク動いて楽しいのか
というのが今のところの感想です。

次はcomponentを使って何か作ってみたいと思うざますヽ(`▽´)/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

vueでariaをv-bindする時に気をつけること

なにもかんがえずにv-bindする

<div class="js-drawer" :aria-expanded="isOpen">

これだとfalseの場合、aria-expanded属性自体が消えてしまう。

解決

<div class="js-drawer" :aria-expanded="isOpen ? 'true' : 'false'">

これだisOpenがfalseでもaria-expanded属性が保持される。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

そのVueのページ、本当に非同期コンポーネントで高速化できてる?

はじめに

この記事では、Vue.js(+ TypeScript)で作ったSPAページの初期描画の速度を改善したい時の取り組みの1つが紹介しています。

非同期コンポーネントという考えは理解できていたのですが、実際に試すと何だか遅くなったように感じられ、断念していました。
実は使い方が上手くなかったようで、その対処法が分かったのでまとめておきたいと思います。

prefetchを使うとコンポーネントがすでに読み込まれているのでページ遷移は速くなりますが、SPAサイトの初期描画が遅くなってしまうというトレードオフがありそうですね。
今回は、初期描画を高速化することにスポットを当てています。

TL;DR;

  • 公式ページにあるように、コンポーネントを非同期に呼び出して描画を高速化できるぞ!
  • それだけだとprefetchが行われて高速化しないので、vue.config.jsに1行追加するんやで!

非同期コンポーネント呼び出し

SPAのサイトですが、初期描画を改善したいので何か無いかなといろいろ試していたところでした。

非同期コンポーネントという考え方を発見し、公式ページを見た通りに試してみる。

まずは、これはTypeScriptでのオーソドックスな呼び出し方(たぶん)。

コンポーネントの同期読み込み
import MyComponent from "./MyComponent";

@Component({
  components: {
    MyComponent
  }
})

それに対して、次のように変更するだけで非同期コンポーネントが使用できますね。コードの変更は本当にこれだけ。

非同期読み込みに変更
- import MyComponent from "./MyComponent";

@Component({
  components: {
-     MyComponent
+     MyComponent: () => import("./MyComponent")
  }
})

という変更を行って、いざSPAページをリロードして表示してみると、今までには無かった謎のjsファイルの読み込みが。
どうやらこれが非同期読み込みすると起こるっぽい。

非同期コンポーネントの数だけ、jsが分割されてprefetchされる。(加えて、実際にコンポーネントが使用される時に prefetchじゃなく読み込まれる)
これで速くなったの、、、かな?

でも実際にロード時間を見てみると、何か体感遅くなってる???
並列読み込みが足りないのか?HTTP2 を使えという無言の圧力??

という感じで、良く分からなくなってしまったので一旦保留にして、作ったPRは閉じておきました。

prefetchを行わないようにする

それからしばらくして、ある記事を見つけました。こちらです。
How to make lazy loading actually work in Vue (CLI 3)

これや!これが欲しかったんや!
actually-workとか書いてあるし、記事のタイトルを見た瞬間にピーんと来てました、まじで。

ということで、記事にも書いてあるようにvue.config.jsにprefetchを制限するための1行を追加しましょう。

vue.config.js
chainWebpack: (config) => {
  config.plugins.delete("prefetch");
  ...
}

この変更を適用させると、非同期コンポーネントのprefetchが無くなり、必要な時になったら必要なコンポーネントが読み込まれる仕組みにできました。

Matias Rodalさん、ありがたや。

おわりに

ということで、気になっていた非同期コンポーネントを使うと遅くなる問題が解決できたかなと思います。

必要な時に必要なものを用意する、というモノを持たない現代的な生き方にマッチした実装が出来そうです。

私生活でもミニマリスト的に暮らしてみたい。断捨離しよ。

以上

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

そのVue.jsのページ、本当に非同期コンポーネントで高速化できてる?

はじめに

この記事では、Vue.js(+ TypeScript)で作ったSPAページの初期描画の速度を改善したい時の取り組みの1つが紹介しています。

非同期コンポーネントという考えは理解できていたのですが、実際に試すと何だか遅くなったように感じられ、断念していました。
実は使い方が上手くなかったようで、その対処法が分かったのでまとめておきたいと思います。

prefetchを使うとコンポーネントがすでに読み込まれているのでページ遷移は速くなりますが、SPAサイトの初期描画が遅くなってしまうというトレードオフがありそうですね。
今回は、初期描画を高速化することにスポットを当てています。

TL;DR;

  • 公式ページにあるように、コンポーネントを非同期に呼び出して描画を高速化できるぞ!
  • それだけだとprefetchが行われて高速化しないので、vue.config.jsに1行追加するんやで!

非同期コンポーネント呼び出し

SPAのサイトですが、初期描画を改善したいので何か無いかなといろいろ試していたところでした。

非同期コンポーネントという考え方を発見し、公式ページを見た通りに試してみる。

まずは、これはTypeScriptでのオーソドックスな呼び出し方(たぶん)。

コンポーネントの同期読み込み
import MyComponent from "./MyComponent";

@Component({
  components: {
    MyComponent
  }
})

それに対して、次のように変更するだけで非同期コンポーネントが使用できますね。コードの変更は本当にこれだけ。

非同期読み込みに変更
- import MyComponent from "./MyComponent";

@Component({
  components: {
-     MyComponent
+     MyComponent: () => import("./MyComponent")
  }
})

という変更を行って、いざSPAページをリロードして表示してみると、今までには無かった謎のjsファイルの読み込みが。
どうやらこれが非同期読み込みすると起こるっぽい。

非同期コンポーネントの数だけ、jsが分割されてprefetchされる。(加えて、実際にコンポーネントが使用される時に prefetchじゃなく読み込まれる)
これで速くなったの、、、かな?

でも実際にロード時間を見てみると、何か体感遅くなってる???
並列読み込みが足りないのか?HTTP2 を使えという無言の圧力??

という感じで、良く分からなくなってしまったので一旦保留にして、作ったPRは閉じておきました。

prefetchを行わないようにする

それからしばらくして、ある記事を見つけました。こちらです。
How to make lazy loading actually work in Vue (CLI 3)

これや!これが欲しかったんや!
actually-workとか書いてあるし、記事のタイトルを見た瞬間にピーんと来てました、まじで。

ということで、記事にも書いてあるようにvue.config.jsにprefetchを制限するための1行を追加しましょう。

vue.config.js
chainWebpack: (config) => {
  config.plugins.delete("prefetch");  # この行を追加
  ...
}

この変更を適用させると、非同期コンポーネントのprefetchが無くなり、必要な時になったら必要なコンポーネントが読み込まれる仕組みにできました。

Matias Rodalさん、ありがたや。

おわりに

ということで、気になっていた非同期コンポーネントを使うと遅くなる問題が解決できたかなと思います。

必要な時に必要なものを用意する、というモノを持たない現代的な生き方にマッチした実装が出来そうです。

私生活でもミニマリスト的に暮らしてみたい。断捨離しよ。

以上

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む