Motomichi Works Blog

モトミチワークスブログです。その日学習したことについて書いている日記みたいなものです。

vue.js 2.x その0004-02 アコーディオンを作る(jQueryのslideToggleみたいなものを作る)

はじめに

以下の記事で書いたコードを少しマシな感じに書き直しました。

vue.js 2.x その0004 アコーディオンを作る(jQueryのslideToggleみたいなものを作る) - Motomichi Works Blog

サーバーサイドから動的な値がwindow.itemsで書き出される想定で書いています。

rootコンポーネントから渡された値を更新したい場合は、rootコンポーネントが持っているstateを$emitなりで更新して、子供に渡しなおすと良さそうです。

そのとき、this.item.textをwatchしたり、computedの中で使うなどしないと子供のコンポーネントの状態は更新されないと思います。たぶん。

HTMLファイルサンプル

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Vue.jsのアコーディオンサンプル</title>
<meta charset="utf-8">
</head>
<body>
<style>
.accordion{}
.accordion__trigger{}
.accordion__contents-outer-wrap{
  transition: max-height 2s;
  max-height: 0;
  overflow: hidden;
  background: #eeeeff;
}
.accordion__contents-inner-wrap{
  padding: 100px 10px;
}
</style>

<div id="accordion-app">
  <ul>
    <li is="my-component" v-for="(item, index) in state.items" :item="state.items[index]" :index="index">
    </li>
  </ul>
</div>

<!-- x-templateを定義 -->
<script type="text/x-template" id="my-component">
<li class="accordion">
  <button class="accordion__trigger" v-on:click="slideToggle()">
    accordion-trigger-{{index}}
  </button>
  <div class="accordion__contents-outer-wrap" v-bind:style="state.style">
    <div class="accordion__contents-inner-wrap" ref="contentsInner">
      text : {{ state.text }}<br>
      index : {{ index }}
    </div>
  </div>
</li>
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<script>
// サーバーから渡されたデータなどを想定
window.items = [
  { text: '何か個別に渡したいデータがあれば'},
  { text: '何か個別に渡したいデータがあれば'},
];

// my-componentを作成
Vue.component('my-component', {
  template: '#my-component',
  props: ['item', 'index'],
  data: function(){
    return {
      state: {
        isOpen: false,
        text: this.item.text,
        style: {},
      },
    };
  },
  methods: {
    slideToggle: function(){
      this.state.isOpen = !this.state.isOpen;
      this.setStyle(this.state.isOpen);
    },
    setStyle: function(isOpen){
      this.state.style = isOpen ? { 'maxHeight': this.$refs.contentsInner.clientHeight + 'px' } : {};
    },
  },
  mounted: function(){
    this.setStyle(this.state.isOpen);
  },
});

// VM
var vueApp = new Vue({
  el: '#accordion-app',
  data: {
    state: {
      items: window.items,
    },
  },
});
</script>
</body>
</html>

RSpec+Capybaraその0002 radioやcheckboxの状態を検証する

参考にさせて頂いたページ

RSpecについて

Capybaraについて

radioやcheckboxがCapybara::ElementNotFoundになる

ラジオボタンチェックボックスは、デザインを適用するときにdisplay:none;にしたり、position:absolute;のlabelタグの下に隠したりすることがよくあります。

Capybara::ElementNotFound のエラーが表示されてラジオボタンチェックボックスが見つけられない場合はinputタグが表示状態か非表示状態か、まずは思い込みを捨ててCSSをきちんと確認することが大切です。

checkedかどうかを検証する

表示されているradioやcheckboxがcheckedであることを検証する

expect(page).to have_checked_field('ラベル文字列')

display:none;のradioやcheckboxがcheckedであることを検証する

visible:falseを第二引数に渡すとdisplay:none;の要素がcheckedかを検証できます。

expect(page).to have_checked_field('ラベル文字列', visible:false)

checkedでないことを検証する

checkedでないということを検証するには、to_notがあります。

expect(page).to_not

フィールド自体が表示されているかを検証する

checkedかどうかは関係なく、要素が表示されているかどうかを検証します。

expect(page).to have_field('ラベル文字列')

RSpec+Capybaraその0001 インデックス

参考にさせて頂いたページ

RSpecについて

Capybaraについて

はじめに

RSpecとCapybaraを使い始めたのでハマったことなどを少しずつ足していこうと思います。

状態を検証する

radioとcheckbox

railsその0003-011 第九章、第十章完了

rails 5のチュートリアルをやってみる日記です。

今日はここまで読んだとか、ここまでやったとかそんな感じの日記です。

昨日と今日で第九章、第十章のコード書き終えました。

永続的ログイン、ユーザー情報の更新、ユーザーの削除などができるようになりました。

第八章あたりからか、ただコピペして、動くかとかテストがGREENになるかだけで精一杯な感じになりつつあるのでいよいよつらい。

一通りやり終えたらコピペしてきたコードを読んで理解しないと意味無いけど、まずは先に進みます。

railsその0003-010 第七章、第八章完了

rails 5のチュートリアルをやってみる日記です。

今日はここまで読んだとか、ここまでやったとかそんな感じの日記です。

第七章、第八章のコード書き終えました。

会員登録、ログイン、ログアウトができるようになりました。

railsその0003-009 第六章完了

今日の日記

rails 5のチュートリアルをやってみる日記です。

今日はここまで読んだとか、ここまでやったとかそんな感じの日記です。

第六章のコード書き終えました。

Userモデルを作成して、name、email、passwordフィールドのバリデーションとそのtestを作成やパスワードのハッシュ化など実装しました。

webpack3.x+vue.js 2.x+vue-loaderでビルド環境を構築する

参考にさせて頂いたページ

過去に書いたhtml-loaderを使う記事

webpackを使ってES2015、Vue.jsのビルド環境を構築する - Motomichi Works Blog

今日の環境

  • Windows10
  • node v8.9.3
  • npm 5.6.0
  • webpack 3.10.0

プロジェクトディレクトリを作成

任意のディレクトリ名で良いのですが、frontendディレクトリを作成することにします。

mkdir frontend

以降のコマンドはfrontendディレクトリで実行していきます。

npm init

まずnpm initして、適当にenterしますが、エントリーポイントだけmain.jsにしました。
以下のような感じにしています。

{
  "name": "frontend",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this ok? (yes) yes

グローバルにインストール

npm install -g webpack babel

プロジェクトにインストール

npm install --save-dev webpack@3 vue-loader vue-template-compiler babel-core babel-loader babel-preset-es2015
npm install --save vue

今回frontendディレクトリ内に作成するディレクトリ構造とファイル

  • index.html
  • package.json
  • package-lock.json
  • webpack.config.js
  • node-modules/*
  • src/main.js
  • src/App.vue
  • src/components/HelloWorld.vue
  • result/bundle.js

webpack.config.jsの作成とその記述内容

const path = require('path');

module.exports = {
  entry: './src/main.js',
  output: {
    path: `${__dirname}/result`,
    filename: 'bundle.js'
  },
  module: {
    loaders: [
      {
        loader: 'babel-loader',
        exclude: /node_modules/,
        test: /\.js[x]?$/,
        query: {
            cacheDirectory: true,
            presets: ['es2015']
        }
      },
      {
        test: /\.vue$/,
        loader: "vue-loader"
      },
    ]
  },
  resolve: {
    // モジュールを読み込むときに検索するディレクトリ
    modules: [path.join(__dirname, 'src'), 'node_modules'],
    // importするときに省略できる拡張子
    extensions: ['.js', '.vue'],
    alias: {
      // 例えばmain.js内で `import Vue from 'vue';` と記述したときの`from vue`が表すファイルパスを指定
      'vue$': 'vue/dist/vue.esm.js'
    },
  },
  plugins: []
}

./src/main.jsの作成とその記述内容

import Vue from 'vue';
import App from './App';

Vue.config.productionTip = false;

/* eslint-disable no-new */
new Vue({
  el: '#app',
  template: '<App/>',
  components: { App },
});

./src/App.vueの作成とその記述内容

<template>
  <div id="app">
    <HelloWorld/>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld'

export default {
  name: 'app',
  components: {
    HelloWorld
  }
}
</script>

./src/components/HelloWorld.vueの作成とその記述内容

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>

index.htmlの作成とその記述内容

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<title>vue-tutorial</title>
</head>
<body>
<div id="app">
</div>

<script type="text/javascript" src="result/bundle.js"></script>
</body>
</html>

watchしてコンパイルしてみる

webpack -d --watch

ここまでやってのpackage.jsonの内容

{
  "name": "frontend",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-es2015": "^6.24.1",
    "vue-loader": "^13.6.1",
    "vue-template-compiler": "^2.5.13",
    "webpack": "^3.10.0"
  },
  "dependencies": {
    "vue": "^2.5.13"
  }
}

ページを見てみる

index.htmlをブラウザで開いて確認します。

Welcome to Your Vue.js Appという文字列が表示されました。

今日はここまで。