20190529のvue.jsに関する記事は8件です。

[Vue.js] 複数の引数を持つfilterを使ってみたメモ

Filter.js

src直下にpluginsディレクトリを切り、その中にfilter処理だけを書くFilter.jsを置く

export default {
  install(vue) {
    vue.filter('decimalPointShaping', value => {
      if (!Number(value)) {
        return value
      }
      return Math.round(value)
    })

  // 複数の引数を持つfilterはこれ↓
    vue.filter('percentageCalculation', (value, sum) => {
        console.log('percentageCalculation',value,sum)
      return (value / sum) * 100
    })
  },
}

使い方

<p>
{{ 【value】 | percentageCalculation(【sum】) | decimalPointShaping }}%
</p>

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

【Vue.js】v-modelの基本的な使い方と、修飾子の使い方

本記事について

v-modelの挙動と、v-modelでのinputタグの値の取得のTipsを記載します。

目次

・v-modelとは
・v-modelを使ってみる
・v-modelで使う修飾子

v-modelとは

v-modelとはそもそも何なのか。
公式ドキュメントによると

form の input 要素 や textarea 要素、 select 要素に双方向 (two-way) データバインディングを作成するには、v-model ディレクティブを使用することができます。それは、自動的に入力要素のタイプに基づいて要素を更新するための正しい方法を選択します。

とのことです。うーん、ちょっとわかりにくい。。

とりあえず、コードを書いて理解してみましょう。

v-modelを使ってみる

とても基本的な使い方ですが、まずはHTMLに下記のように書きます。

index.html
<!-- Vue.jsが読み込まれている前提 -->
<div id="app">
  <input type="text" v-model="sample_v_model" placeholder="sample_v_model"><br>
  <p>ここにsample_v_modelの値をリアルタイムに表示: {{ sample_v_model }}</p>
</div>

<script>
new Vue({
  el: "#app",
  data: {
    sample_v_model: ''
  }
})
</script>

inputタグにv-model="sample_v_model"という記述があります。
そして、scriptタグの中身にsample_v_model: ''という記述があります。

new Vueとして、Vueインスタンスを作っているわけですが、それをマウントする先が#appで囲まれた箇所になるので、HTML側のv-model="sample_v_model"とjs側のsample_v_model: ''が紐づいているのですね。

公式ページに書いてあった、「双方向 (two-way) データバインディングを作成するには、v-model ディレクティブを使用することができます」という部分がこれに当たるのだと理解できました。

jsの方ではsample_v_modelというデータを持っていて、ページが読みこまれた表示された時にはその中身は空っぽ、そして、inputタグも空っぽという状態です。なので、ページが表示された時には

・inputタグの中身は空っぽ
・js上で定義されたデータの中身も空っぽ

ということになります。

↓こんな感じですね。

スクリーンショット 2019-05-29 16.12.03.png

これで、v-modelの基本的な使い方を理解することができました。

v-modelで使う修飾子

今回はinputタグの中身を計算する上で数値にする必要があり、そのデータをHTML上にも反映しようとしたところ、v-forの部分でそれがうまくいかず、「100」と入力すると。「1」「0」「0」と入力されたと見なされてしまったので、その解決のためにnumber修飾子を使いました。

その実際のコードがこちらです

<div class="">
  <label for="number_of_years">運用する年数</label>
  <input type="number" v-model.number="number_of_years" placeholder="運用する年数を入力してください"></div>

(略)

<tr v-for="number_of_year in number_of_years">
  <th>{{ number_of_year }}年後</th>
  <td>{{ Math.round(amountOfShare * Math.pow(rateOfIncrease, number_of_year)) }}</td>
</tr>

これで、無事に数値としてnumber_of_yearsをv-forのところで使う数値の部分に入れることができました。

今回はnumberを使いましたが、他にも修飾子があったので下記にまとめておきます。

修飾子 内容
lazy 入力ボックスに入力されたタイミングではなく、入力し終わったタイミングでデータを変更する。
number 入力した値の型変換を自動で数値にする。
trim 入力した値から自動で空白を削除する

それぞれ使うタイミングが出てきたら具体的な例も追記できればと思います。

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

Docker on Storybook@Vueを最小構成で動かす

何時もの備忘録として

  • docker-compose runの仕様にはまった

まずはチュートリアル通りに動かす

こちらを参照に進める

docker-compose.ymlの準備

version: '3'
services:
  node:
    image: node:12.3.1-alpine
    volumes: 
      - ./:/app
    working_dir: /app
    ports:
      - 9001:9001

モジュールをインストール

docker-compose run node npm init
docker-compose run node npm install @storybook/vue --save-dev
docker-compose run node npm install vue --save
docker-compose run node npm install vue-loader vue-template-compiler @babel/core babel-loader babel-preset-vue --save-dev

packeage.jsonの編集

以下を追加

packeage.json
{
  "scripts": {
    "storybook": "start-storybook --ci -p 9001 -c .storybook",
  }
}

設定ファイルを作成

.storybook/config.jsを作成 .storybookディレクトリに注意

storybook/config.js
import { configure } from '@storybook/vue';

function loadStories() {
  require('../stories/index.js');
}

configure(loadStories, module);

./stories/index.jsを作成

index.js
import Vue from 'vue';
import { storiesOf } from '@storybook/vue';
import MyButton from '../components/Button';

storiesOf('Button', module)
  .add('with text', () => '<my-button>with text</my-button>')
  .add('with emoji', () => '<my-button>? ? ? ?</my-button>')
  .add('as a component', () => ({
    components: { MyButton },
    template: '<my-button :rounded="true">rounded</my-button>'
  }));

./components/Button.vueを作成

Button.vue
//何でもいいので作る

<template>
  <button @click="hello">hello</button>
</template>

<script>
export default {
  methods: {
    hello: e => {
       alert('hello');
    }
  }
}
</script>

そして

docker-compose run run node run storybook

でブラウザが開かない。。。

docker-compose runの仕様でそのままだとportsのマッピングが効かない。知らなかった。。。

気を取り直して

docker-compose run --service-ports node npm run storybook

localhost:9001でStorybookが確認できる

スクリーンショット 2019-05-29 16.32.46.png

参考

チュートリアル
Issue

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

Vue-Tables2とScrollBoosterを組み合わせてみる

概要

Vue.jsを使って、テーブルタグからデータ明細を見せるようなWebアプリケーションをサクッと実装。
ダッシュボード的なアプリなどでデータを見せる際に便利ではないでしょうか。
タイトルにあるライブラリを使う際の注意点やノウハウを展開します。

ライブラリの紹介

ポイント

  • ScrollBoosterに渡すviewportとcontent
    • $refsから取得するのが楽
    • サンプルコードでは、Vue-Tables2が自動付与するtable-responsiveのclass名を使ってみた
  • updateMetrics()の呼び出し
    • Vue-Tables2にデータが入るとテーブルの幅部分のwidthが変わってしまうので、更新する必要がある
    • その際に使用するのがScrollBooster.updateMetrics()
    • Vue-Tables2が提供するイベント関数を使って、幅の更新をする
    • 設定したのは「ソート(sorted)」「ページネーション(pagenation)」「件数変更(limit)」
    • 「フィルタリング(filter)」でも幅変更があり得るが、幅が伸びる事は無いと思ったので設定してない
  • $nextTickの使用
    • 幅を更新する際、実DOMの更新がされてからでないと幅計算が正しくならないと思われるので、Vueの提供する$nextTickを使っている

サンプルコード

html
<div ref="table">
  <v-client-table :columns="vueTables.columns" :data="vueTables.data" :options="vueTables.options"
    @sorted="updateScrollBooster" @pagination="updateScrollBooster"
    @limit="updateScrollBooster">
  </v-client-table>
</div>
script
// 一部、ここに書いてない定数があるのでそのままは使えない。注意
    new Vue({
      el: '#app',
      data: {
        // vue-tables-2用定義
        vueTables: {
          columns: [
            'acceptDate',
            'validStartDate',
            'validEndDate',
            'productName',
          ],
          data: [],
          options: {
            headings: VUE_TABLES_HEADINGS,
            sortable: [
              'acceptDate', 'validStartDate', 'validEndDate', 'productName',
            ],
            orderBy: { column: 'acceptDate' },
            skin: 'table-striped table-bordered table-hover table-sm',
            texts: VUE_TABLES_TEXTS,
            perPage: 50,
            perPageValues: [50, 100, 500, 1000],
            sortIcon: VUE_TABLES_SORTICON
          },
        },
        scrollBoosterNormal: null,
      },
      mounted() {
        // ScrollBoosterを設定
        let viewport = this.$refs.table.querySelector('.table-responsive');
        let content = viewport.querySelector('table');
        this.scrollBooster = setScrollBooster(viewport, content);
      },
      methods: {
        updateScrollBooster() {
          // ScrollBoosterのviewport幅を更新する(検索結果に合わせて)
          this.$nextTick(function () {
            // nextTickでDOMの幅が確定した状態でupdateMetricsを実行する
            this.scrollBooster.updateMetrics();
          });
        },
      },
    })

補足

Vue-Tables2で横スクロールを有効にするために、実際にはCSS定義も行ってある(overflow-x: scroll)

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

Vuetify と Vue Router でレスポンシブなナビゲーションを作ってみました

はじめに

最初に作ったものを載せておきます。

デモ

https://upbeat-nobel-068b4d.netlify.com/

vuetify.gif

コード

https://github.com/youbeer/vuetify-vuerouter-navbar-example

事前準備

VueCLI3 のインストールを行なってください

【Vue】プロジェクトの作成

terminal
$ vue create vuetify-vuerouter-navbar-example

いくつか質問が表示されるので

  • Manually select features を選択肢し
  • Router を追加してください

その他はお好みでどうぞ

terminal
Vue CLI v3.7.0
┌───────────────────────────┐
│  Update available: 3.8.2  │
└───────────────────────────┘
? Please pick a preset:
  default (babel, eslint)
❯ Manually select features
terminal
? Please pick a preset: Manually select features
? Check the features needed for your project:
 ◉ Babel
 ◯ TypeScript
 ◯ Progressive Web App (PWA) Support
❯◉ Router
 ◯ Vuex
 ◯ CSS Pre-processors
 ◉ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

Vuetify を追加

プロジェクト直下に移動し Vuetify をインストールします。

terminal
$ cd vuetify-vuerouter-navbar-example
$ vue add vuetify

preset は Default (recommended)を選択してください

terminal
? Choose a preset:
❯ Default (recommended)
  Prototype (rapid development)
  Configure (advanced)

サーバを起動

terminal
$ yarn serve

http://localhost:8080/ をブラウザで開いて
Welcome to Vuetify の文字が出てくれば OK です

Screen Shot 2019-05-29 at 10.34.49.png

プロジェクトを確認

plugins ディレクトリに vuetify.js が作られていて
それを main.js でインポートしているようです。

src/plugins/vuetify.js
import Vue from "vue";
import Vuetify from "vuetify/lib";
import "vuetify/src/stylus/app.styl";

Vue.use(Vuetify, {
  iconfont: "md"
});
src/main.js
import Vue from "vue";
import "./plugins/vuetify";

// ... 略

コンポーネントの作成

ここからいよいよ本題です。
Header.vue を作成しナビゲーションの内容を記述します。

src/components/Header.vue
<template>
  <div>
    <v-navigation-drawer v-model="drawer" absolute temporary>
      <v-list class="pa-1">
        <v-list-tile avatar>
          <v-list-tile-avatar>
            <img src="https://randomuser.me/api/portraits/men/85.jpg" />
          </v-list-tile-avatar>
          <v-list-tile-content>
            <v-list-tile-title>John Leider</v-list-tile-title>
          </v-list-tile-content>
        </v-list-tile>
      </v-list>
      <v-list>
        <v-text-field
          clearable
          flat
          label="Search"
          prepend-inner-icon="search"
          solo
          single-line
          hide-details
        ></v-text-field>
      </v-list>
      <v-list class="pt-0" dense>
        <v-divider></v-divider>
        <v-list-tile v-for="item in items" :key="item.title" :to="item.to">
          <v-list-tile-action>
            <v-icon>{{ item.icon }}</v-icon>
          </v-list-tile-action>
          <v-list-tile-content>
            <v-list-tile-title>{{ item.title }}</v-list-tile-title>
          </v-list-tile-content>
        </v-list-tile>
      </v-list>
    </v-navigation-drawer>
    <v-toolbar dark color="primary" clipped-left fixed app>
      <v-toolbar-side-icon
        @click.stop="drawer = !drawer"
        class="hidden-md-and-up"
      ></v-toolbar-side-icon>
      <v-toolbar-title class="headline text-uppercase white--text">
        <span>Vuetify</span>
        <span class="font-weight-light">MATERIAL DESIGN</span>
      </v-toolbar-title>
      <v-spacer></v-spacer>
      <v-expand-x-transition>
        <v-text-field
          class="hidden-sm-and-down"
          clearable
          flat
          label="Search"
          prepend-inner-icon="search"
          solo-inverted
          single-line
          hide-details
          v-show="showSearchInput"
        ></v-text-field>
      </v-expand-x-transition>
      <v-toolbar-items class="hidden-sm-and-down">
        <v-btn icon @click="showSearchInput = !showSearchInput">
          <v-icon>search</v-icon>
        </v-btn>
        <v-btn flat to="/">Home</v-btn>
        <v-btn flat to="/about">About</v-btn>
      </v-toolbar-items>
    </v-toolbar>
  </div>
</template>

<script>
export default {
  name: "Header",
  data() {
    return {
      drawer: null,
      showSearchInput: false,
      items: [
        { title: "Home", icon: "dashboard", to: "/" },
        { title: "About", icon: "question_answer", to: "/about" }
      ]
    };
  }
};
</script>

ナビゲーションとサイドパネル

下記を参考にしました。

アニメーション

<v-expand-x-transition>で検索 box の表示切替のときにアニメーションを付けています。

v-expand-x-transition
<v-expand-x-transition>
  <v-text-field
    class="hidden-sm-and-down"
    clearable
    flat
    label="Search"
    prepend-inner-icon="search"
    solo-inverted
    single-line
    hide-details
    v-show="showSearchInput"
  ></v-text-field>
</v-expand-x-transition>

ブレークポイント

hidden-md-and-up と
hidden-sm-and-down
で画面サイズによって表示切替をするブレークポイントをつけています。

hidden-md-and-up
<v-toolbar-side-icon
  @click.stop="drawer = !drawer"
  class="hidden-md-and-up"
></v-toolbar-side-icon>
hidden-sm-and-down
<v-toolbar-items class="hidden-sm-and-down">
  <v-btn icon @click="showSearchInput = !showSearchInput">
    <v-icon>search</v-icon>
  </v-btn>
  <v-btn flat to="/">Home</v-btn>
  <v-btn flat to="/about">About</v-btn>
</v-toolbar-items>

App.js で Header.vue を呼び出す

src/App.vue
<template>
  <v-app>
    <Header />
    <v-content>
      <v-container fluid fill-height>
        <v-layout justify-center align-center>
          <router-view></router-view>
        </v-layout>
      </v-container>
    </v-content>
  </v-app>
</template>

<script>
import Header from "@/components/Header";
export default {
  name: "App",
  components: {
    Header
  }
};
</script>

さて、完成したので再度 http://localhost:8080/ へアクセスして確認してみましょう
こんな表示になっていれば OK です。
Screen Shot 2019-05-29 at 12.30.24.png

おわりに

最後まで読んでいただきありがとうございました。
Vuetify は Theme も公開されているようですね
中には無料の物もあるようなので試してみてはいかがでしょうか
Free / Premium Themes — Vuetify.js

Vue.js は至れり尽くせりですね ?

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

[Vue.js]Vue.jsでChart.jsのoptionsの渡し方についてのメモ

はじめに

vue.jsでchart.jsを使うとき、opitonsの書き方をよく忘れてしまうのでメモ。
構成としては、グラフそのものを表示させる「TheRerdarGraph.vue」と、
その設定をしてある「TheRerdarGraphSetting.vue」を用いる。

memo

TheRardarGraph.vue

<template>
  <div class="small">
    <the-big5-graph-setting :chart-data="datacollection" :options="options" />  /*** ←★opitonsをバインドさせる ***/
  </div>
</template>

<script>
import TheBig5GraphSetting from '@/components/object/project/TheBig5GraphSetting'

export default {
  name: 'TheBig5Graph',
  components: {
    TheBig5GraphSetting,
  },
  props: {
    analysisResult: {
      type: Object,
      required: true,
    },
  },
  data() {
    // @todo this.analysisResult.big5_** の値をグラフ用の datacollection に変換する
    // console.log('big5', this.analysisResult)
    return {
      datacollection: null,
      big5_neurotic_ism: this.analysisResult.big5_neurotic_ism,
      big5_extra_version: this.analysisResult.big5_extra_version,
      big5_openness: this.analysisResult.big5_openness,
      big5_agreeableness: this.analysisResult.big5_agreeableness,
      big5_conscientiousness: this.analysisResult.big5_conscientiousness,
/************************* ★optionsの書き方★ *************************/
      options: {
        scale: {
          ticks: { //http://www.chartjs.org/docs/#scales-radial-linear-scale
            stepSize: 10, // 目盛の間隔
            max: 100, //最大値
          }
        },
        legend: {
          display: false,
        },
      },
    }
/************************* ★optionsの書き方★ *************************/
  },
  mounted() {
    this.fillData()
  },
  methods: {
    fillData() {
      this.datacollection = {
        labels: ['感情性', '外向性', '開放的', '協調性', '誠実性'],
        datasets: [
          {
            label: '1',
            backgroundColor: 'rgba(244, 40, 88,0.3)',
            data: [
              this.big5_neurotic_ism,
              this.big5_extra_version,
              this.big5_openness,
              this.big5_agreeableness,
              this.big5_conscientiousness,
            ],
          },
        ],
      }
    },
    getRandomInt() {
      return Math.floor(Math.random() * (50 - 5 + 1)) + 5
    },
  },
}
</script>

<style>
.small {
  max-width: 300px;
}
</style>

TheRardarGraphSetting.vue

<script>
import { Radar, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins

export default {
  name: 'TheBig5GraphSetting',
  extends: Radar,
  mixins: [reactiveProp],
  props: ['options', 'chartData'],
  mounted() {
    // this.chartData is created in the mixin.
    // If you want to pass options please create a local options object
    this.renderChart(this.chartData, this.options)
  },
}
</script>

<style></style>

最後に

dataにopitonsの内容をオブジェクトとして格納し、
それを

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

IntelliJ (or WebStorm) + Vue.js + TypeScriptで書いたコードのデバッグをする

console.log() での出力がつらくなって来たのでメモ。下記のようにするとブレークポイントで実行が止まります。

  1. yarn run serve --debug もしくは直接 vue-cli-service serve --debug などでデバッグモードでVueアプリをサーブ
  2. (IntelliJでブレークポイントをはっておく)
  3. IntelliJの Run > Debug... > Edit Configurations... でデバッグ実行の設定画面を開く
  4. 左上の +ボタン > JavaScript Debug を選ぶ
  5. URLの欄に http://localhost:8080/#/... などVueアプリのURL(デバッグしたいもの)を入力
  6. Debugボタン(右下の)を押す
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

vue-cli無しでvueの単一コンポーネントファイルを使用する。scssも。

経緯

よくvue関連の情報で「単一ファイルコンポーネントを使用するにはvue-cliが必要」と目にする気がします。
情報例:
https://jp.vuejs.org/v2/guide/single-file-components.html 
 (「これはあなたがまだ使ったことのない、いくつかの追加ツールの使い方を学ぶことを意味します。」「Vue CLI 3 を確認することをお勧めします。」)

単一ファイルコンポーネントはとても便利なのですが、vue-cliは学習敷居が高いので以下のような困った場面があります。
・手早く単一ファイルコンポーネントを学習したい。
・既存のwebシステムにvueを適応させたい。単一ファイルコンポーネントありで。
・開発メンバーにvueを普及させたい。

「node.jsとかnpmとかwebpackとかvue-cliとか使用せずに単純にhtmlからvueファイルを使用したい」「できれば、スタイルシートもscssで記述したい」と思っていたところ、http-vue-loaderというものがあるそうです。
@horikeso様の記事で知りました。

サンプル1

これで単一ファイルコンポーネントを使用できました。

index-1.html
<!DOCTYPE html>
<html>

<head>
</head>

<body>
    <div id="app">
        <vc-main-1></vc-main-1>
    </div>

    <!-- promise (IEに必要) -->
    <script src="https://unpkg.com/es6-promise"></script>

    <!-- vue -->
    <script src="https://unpkg.com/vue"></script>

    <!-- http-vue-loader -->
    <script src="https://unpkg.com/http-vue-loader"></script>

    <script type="text/javascript">
        //メインコンポーネント
        var vue = new Vue({
            el: '#app',
            components: {
                'vc-main-1': httpVueLoader('vc-main-1.vue') //他階層にあるなら、('js/components/vc-main-1.vue')の様な指定も可能
            }
        });
    </script>
</body>

</html>
vc-main-1.vue
<template>
  <div class="vc-main-1">
    <h1>Hello</h1>
    <p>{{message}}</p>
  </div>
</template>

<script>
module.exports = {
  data: function() {
    return {
      message: 'こんにちは'
    }
  }
}
</script>

<style>
.vc-main-1 h1{
    font-size: 3.5rem;
}
.vc-main-1 p{
    font-weight: bold;
}
</style>

サンプル1の注意点

「module.exports = {」の箇所が「export default {」だとダメな様子です。

サンプル2 scssを使用する

こんな風にするとscssも使用できるみたいです。

index-2.html
<!DOCTYPE html>
<html>

<head>
</head>

<body>
    <div id="app">
        <vc-main-2></vc-main-2>
    </div>

    <!-- promise (IEに必要) -->
    <script src="https://unpkg.com/es6-promise"></script>

    <!-- sass -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.10.13/sass.sync.min.js"></script>

    <!-- vue -->
    <script src="https://unpkg.com/vue"></script>

    <!-- http-vue-loader -->
    <script src="https://unpkg.com/http-vue-loader"></script>

    <script type="text/javascript">
        //set sass to http-vue-loader
        httpVueLoader.langProcessor.scss = function(scssText) {
            return new Promise(function(resolve, reject) {
                Sass.compile(scssText, function(result) {
                    if (result.status === 0)
                        resolve(result.text)
                    else
                        reject(result)
                });


            });
        }

        //メインコンポーネント
        var vue = new Vue({
            el: '#app',
            components: {
                'vc-main-2': httpVueLoader('vc-main-2.vue')
            }
        });
    </script>
</body>

</html>
vc-main-2.vue
<template>
  <div class="vc-main-2">
    <h1>Hello</h1>
    <p>{{message}}</p>
  </div>
</template>

<script>
module.exports = {
  data: function() {
    return {
      message: 'こんにちは'
    }
  }
}
</script>

<style lang="scss">
.vc-main-2 {
  h1{
    font-size: 3.5rem;
  }
  p{
    font-weight: bold;
  }
}
</style>

サンプル2の注意点

IEだとできませんでした。。。
なにか方法があるかもしれませんが。

以上です。
vue-cliが使用できない場合にとても便利かも。

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