週休七日

趣味のこととか、技術のこととか、読書感想文とか

Vue.jsを再入門する 4

前回記事

luca3104.hatenablog.com

今回は編集機能と削除機能を実装します。

モーダルを発生させる

ボタンの設置

タスクの横にボタンを置き、押下時にモーダルが発生するようにします。
b-checkboxの後ろに

            <button
                class="button is-primary"
                v-on:click="editTask()">Edit</button>

を記述します。

モーダルの設置

モーダルを発生させるにはb-modalを使用します。

          <b-modal :active.sync="isModalActive" has-modal-card>
          </b-modal>

has-modal-cardを設定するとその中に設定したモーダルの中身がモバイルでも崩れずに見れるらしいです。とりあえず設定しておきます。

:active.syncでモーダルをON/OFFします。
トリガーとなるisModalActiveはdata内に定義します。

  data() {
    return {
      taskText: '',
      tasks: [],
      isModalActive: false
    }
  }

タスクの編集

editTask()の実装をします。 この関数が呼ばれたらisModalActivetrueにします。

    editTask() {
      this.isModalActive = true
    }

これでモーダルが発生するようになりました!
実際に確認します。
f:id:luca3104:20180306095631g:plain

モーダルの上にフォームを作る

今回は別Componentとして作っていきたいと思います。

ファイル作成

src/components 配下にEditModal.vue というファイルを作ります。

Buefyのモーダルサンプルを見よう見まねでフォームを作ります。

    <form action="">
        <div class="modal-card" style="width: auto">
            <header class="modal-card-head">
                <p class="modal-card-title">Edit</p>
            </header>
            <section class="modal-card-body">
                <b-field label="Task">
                    <b-input
                        type="task"
                        :value="task"
                        placeholder="タスクを入力してください"
                        required>
                    </b-input>
                </b-field>
            </section>
            <footer class="modal-card-foot">
                <button class="button" type="button">削除</button>
                <button class="button is-primary">完了</button>
            </footer>
        </div>
    </form>

modal-cardの詳細仕様がどこに書いてあるのか不明なのでサンプルを見ながら解説していきます。

modal-card以下にはmodal-card-headmodal-card-bodymodal-card-footがあります。

Modal Card API

modal-card-head

下の画像の上段のLoginの部分がmodal-card-headです。

modal-card-body

次にフォームが並んでいる中段がmodal-card-bodyです。

modal-card-foot

ボタンが並んでいる下段がmodal-card-footです。

f:id:luca3104:20180306223612p:plain

中には通常通りのhtmlを書いていきます。
見た目はこれで完了です。

削除ボタンを押下時の呼び出す関数をdeleteTask()、完了ボタンを押下時に呼び出す関数をeditedTask()とします。

コンポーネントを読み込む

コンポーネント(ここではToDo.vue)内で作成したコンポーネント(ここではEditModal)を読み込みます。
<script>内に

import EditModal from '@/components/EditModal'

と記述し、コンポーネントを読み込みます。
@はsrcまでのパスです。

そしてexport default {以下に

  components: {
    'edit-modal': EditModal
  },

を記述することで、コンポーネント内で<edit-modal>タグとして扱うことができます。

最後にb-modal以下にedit-modalを記述し、見た目の完成です。

          <b-modal :active.sync="isModalActive">
              <edit-modal></edit-modal>
          </b-modal> 

実際にこうなります。
f:id:luca3104:20180306225626g:plain

親子の連携

以上で見た目は完了しましたが、実際に値が移動していません。
コンポーネントから値の送信、子コンポーネントでの値の当て込み、子コンポーネントから親コンポーネントの関数実行まで一気にやります。

親から子へ

コンポーネントから子コンポーネントへ値を渡すために子コンポーネントにpropsを設定します。
今回は配列のindexとtaskが export default {以下にこちらを追記します。

  props: {
    'task': String
  },

そして親コンポーネントに送るための値を設定し、v-bindで子コンポーネントに値を渡します。
今回はformPropsという名前でモデルを用意しました。

          <b-modal :active.sync="isModalActive">
              <edit-modal v-bind="formProps" ></edit-modal>
          </b-modal>
      formProps: {
          task: ''
      }

次にeditTask()を修正し、editTask呼び出し時に編集対象のTaskの文字をeditingTextに代入するようにします。

    editTask(task, index) {
      this.formProps.task = task
      this.isModalActive = true
    },

モーダルを発生させるボタンは以下のようにします。

            <button
                class="button is-primary"
                v-on:click="editTask(task.message)">Edit</button>

これで親から子への送信は完了です。

コンポーネントでの値の当て込み

次に受け取った値をモーダル内のテキストフィールドに入るようにします。
data内にtaskTextを記述し、初期値としてpropsで受け取ったtaskを代入します。

  data() {
    return {
      taskText: this.task
    }
  },

そして前回と同様にb-inputv-model="taskText"を設定するとモーダル発生時にテキストフィールドにtaskTextの値が入って表示されます。

この時点で実行すると、以下のようになります。

f:id:luca3104:20180308095718g:plain

これで完了です

子から親の関数実行

次に子から親の関数を実行します。
これはカスタムイベントハンドラーを使用して実現します。

jp.vuejs.org

v-onを使用してイベントを購読します。

          <b-modal :active.sync="isModalActive">
              <edit-modal v-bind="formProps" v-on:edited="editedTask" v-on:delete="deleteTask"></edit-modal>
          </b-modal>

editedというイベントが発火した時にeditedTaskが実行され、deleteが発火した時にdeleteTaskを実行します。

editedTaskdeleteTaskは一旦モーダルを消す実装のみをします。

    editedTask() {
      this.isModalActive = false
    },
    deleteTask() {
      this.isModalActive = false
    }

次に子にて、ボタンを押下された際に親のイベントを発火するようにします。
まずmodal-foot内のボタンにv-on:clickを記述します。

            <footer class="modal-card-foot">
                <button class="button" type="button" v-on:click="deleteTaskChild()">削除</button>
                <button class="button is-primary" v-on:click="editedTaskChild()">完了</button>
            </footer>

次にdeleteTaskChildeditedTaskChildを実装します。

    editedTask() {
      this.$emit('edited')
    },
    deleteTask() {
      this.$emit('delete')
    }

$emitを使用することで親で購読しているイベントを発火することができます。

実行してみます。

f:id:luca3104:20180308104025g:plain

モーダルを消すことに成功しました。

削除を実装する。

次に削除の関数を実装します。
現在tasksという配列を持っていますが、編集時のindexが判断できないため、editingIndexdata内に宣言します。
次にリスト描画時のv-forindexを取得するように追記します。

          <div
              class="field task-field"
              v-for="(task, index) in tasks"
              v-bind:data="task"
              v-bind:key="task.text">

次にeditTask関数内でeditingIndexindexを代入するように追記します。

    editTask(task, index) {
      this.formProps.task = task
      this.editingIndex = index
      this.isModalActive = true
    },

次に編集ボタンが呼び出すeditTaskの引数にindexを追加します

            <button
                class="button is-primary"
                v-on:click="editTask(task.message, index)">Edit</button>

最後にdeleteTaskを実装して終わりです。
編集中のIndexの場所にあるtasks内の要素を削除し、保存します。

    deleteTask() {
      this.tasks.splice(this.editingIndex, 1)
      this.storeTasks()
      this.isModalActive = false
    }

これで削除機能が実装できました。

実行してみます。

f:id:luca3104:20180308105018g:plain

削除ができました!

編集を実装する

編集機能の実装をします。
編集中の文字列は子がtaskTextという変数で持っているのでこれを親に渡します。
$emit内で値を渡すには、this.$emit('イベント名', 値)という風にします。
今回は親にtaskTextを渡すのみなので以下のようになります。

    editedTaskChild() {
      this.$emit('edited', this.taskText)
    },

親のeditedTask()は引数をもつようにeditedTask(task)とします。
最後に、編集後のjson配列、置き換え、保存をしています。

    editedTask(task) {
      var editedData = { message : task, done: this.tasks[this.editingIndex].done}
      this.tasks[this.editingIndex] = editedData
      this.storeTasks()
      this.isModalActive = false
    },

これで全部の機能が揃いました。
実行してみます。

f:id:luca3104:20180308110416g:plain

再入門をして

Vue.jsの色々な機能を使用してみました。

まだまだ他にも色々な機能があり使いきれてはいないですが、今後も色々触っていきたいと思います。

今後、vuexも触っていきます。

Vue.jsを再入門する 3

前回記事

luca3104.hatenablog.com

今回はLocalStorageを使用し、データの永続化を実装します。

LocalStorageとは

HTML5から導入されたWebStorage APIです。
ブラウザに組み込まれたデータベースと言うとわかりやすいかもしれません。
今回はToDoの一覧を永続的に保存したいけどサーバーまで実装する必要ないと言うことで使って行きたいと思います。

vue-ls

Vue.jsでLocalStorageを楽に使用するためにvue-lsというプラグインを使用します。

github.com

npm install vue-lsでインストール後、main.js内に

import VueLocalStorage from 'vue-ls'

Vue.use(VueLocalStorage)

と記述し使用します。

保存する

localStorage.setItem('task', JSON.stringify(this.tasks))

これだけで実装終わりです。

セットする

このままだと再読み込みなどをしたときに表示されません。
export default内に mounted()を定義し、読み込み時の動作を指定します。
今回は取得して表示するだけなので以下のようになります。

  mounted() {
    this.tasks = JSON.parse(localStorage.getItem('tasks')) || []
  },

完了時もセットする

完了時にも保存します。 考え方的にはtasksを常に監視して、変更があった場合保存するようにします。 ここでwatchを使用します。

jp.vuejs.org

今回はオブジェクト内にネストされた値の変更を検知するために上リンクのcのパターンを利用します。

  watch: {
    tasks: {
      handler: function(){
        this.storeTasks()
      },
      deep: true,
    }
  },

これで完了時にも保存されます。
このあとに実装する編集後にも保存されるのでこのwatchはとても便利ですね。

実際に動作を見てみましょう。
入力 → 完了 → リロードをしてみます。

(リロードがとてもわかりづらいですが、カクッとなってる時がリロード時です)

f:id:luca3104:20180304225309g:plain

次回

次回は編集・削除機能をつけてこのシリーズを終わらせたいと思います。

Vue.jsを再入門する 2

前回記事

luca3104.hatenablog.com

設計

どんなアプリにするか簡易的な設計書を書きます。

前回定めた機能を満たすように作ります。

f:id:luca3104:20180303195652j:plain

レスポンシブ対応がしやすいようにこのような形にしました。

機能一覧

追加

追加機能はアプリケーション上段で行います。
入力し、+ボタン押下で追加します。

完了

完了機能はタスクセルの左側にある○を押下することで実現します。
今回完了を取り消す行為は仕様の範囲外としますが、気が向いたら実装します。

編集・削除

編集・削除機能はタスクセルの右側にあるペンを押下することで実現します。
ダイアログが発生し、テキストの編集ができます。
削除する場合は左下のボタン、完了する場合は編集後に右側のボタンを押下します。
テキストを全部削除した状態で完了を押した場合は削除します。

開発開始

今回、CSSフレームワークはBuefyを使ってみたいと思います。

github.com

過去にbootstrap-vueを使用していましたが、今回はお試しということで。

npm install buefy を実行し、完了後 src/main.js に以下を追記します。

import Buefy from 'buefy'
import 'buefy/lib/buefy.css'

Vue.use(Buefy)

ベースを作る

アプリケーションのベースとなる部分を作ります。
components ディレクトリ以下に ToDo.vue というファイルを作成します。
中身は以下のようにします。

<template>
  <div class="todo">
  </div>
</template>

<script>
export default {
  name: 'ToDo'
}
</script>

<style scoped>

</style>

<div class="todo"></div> 内にHTMLを書いていきます。

入出力パーツを設置する

タスクを入力するパーツ、出力するパーツ(+チェックボックス)をコンポーネント内に設置します。
Buefyのドキュメントを読みながら実際に使うパーツを選定します。
入力はb-input、出力はb-checkboxv-forでタスク分出力します。
コードは以下の通りです。

          <b-input
                minlength="1"
                maxlength="30"
                placeholder="タスクを入力してください"></b-input>
          <p class="control">
            <button
                class="button is-primary"
                v-on:click="addTodo()"></button>
          </p>
        </b-field>


        <section>
          <div
              class="field"
              v-for="task in tasks"
              v-bind:data="task"
              v-bind:key="task.text">
            <b-checkbox>
              {{ task.message }}
            </b-checkbox>
          </div>
        </section>

data内にtasksを定義し、出力確認用に二個くらい入れておきます。

export default {
  name: 'ToDo',
  data() {
    return {
      tasks: [
        { message: 'タスク1' },
        { message: 'タスク2' }
      ]
    }
  }
}

この状態でhttp://localhost:8080にアクセスし、以下のように表示されたらOKです。   
f:id:luca3104:20180304173649p:plain

タスク追加機能

タスクを追加する機能を実装します。
イメージとしては

  1. バインディングするmodelを作る
  2. inputタグにv-modelを設定
  3. addTaskメソッドを実装する
  4. buttonタグにv-on:click="addTask()"でメソッドを呼び出す

です。 

まずはバインディングするmodelをdata内に定義します。
変数名はtaskTextとします。

  data() {
    return {
      taskText: '',
      tasks: [
        { message: 'タスク1' },
        { message: 'タスク2' }
      ]
    }
  }

次にinputタグにv-modelを設定します。
v-modelバインディングのために使用します。
こうすることでinputタグ内で入力された値がリアルタイムでtaskText内に代入されます。
inputタグの部分は以下のようになります

          <b-input
                v-model="taskText"
                minlength="1"
                maxlength="30"
                placeholder="タスクを入力してください"></b-input>

次にタスクを追加するメソッドを実装します。
json文字列を定義し、tasksに追加します。
最後にtaskTextを空文字にするとinputタグ内の入力文字も消えます。 実装は以下のようになります。

  methods: {
    addTask() {
      var addData = { message : this.taskText }
      this.tasks.push(addData)
      this.taskText = ''
    }
  }

最後にbuttonタグにv-on:clickを設定し、押下時にaddTaskが呼び出されるようにします。

            <button
                class="button is-primary"
                v-on:click="addTask()"></button>

これでタスクの追加機能の実装は一旦終わりです。
実際に動かしてみると以下のようになります f:id:luca3104:20180304190531g:plain

これで入出力のパーツの設置が終了しました。

タスクを完了にする。

次にタスクを完了する処理を実装していきます。
以下のような構想で作ります

  1. tasksのデータモデルにdoneを追加し、それぞれのタスクを判断できるようにする
  2. b-checkboxv-modelを設定し、task.doneがtrue<->falseで書き換わるようにする
  3. doneになったときのcssを書く
  4. doneになったときに、テキストにclass=donev-bindで設定する

まず、tasksのデータモデルにdoneを追加します。
addTaskを以下のように修正します。

    addTask() {
      var addData = { message : this.taskText, done: false }
      this.tasks.push(addData)
      this.taskText = ''
    }

次にb-checkbocxv-model を設定します。

            <b-checkbox v-model="task.done">

これでtask.doneが動的に変更されます。

次にdoneになったときのcssを書きましょう。 styleタグ内に以下のcssを書きます。

  .done {
    text-decoration: line-through;
    color: grey;
  }

これでdoneになったときに打ち消し線がつき、テキストの色が灰色になるようになりました。

最後にタスクのテキストにv-bindするようにします。 現在のままだとテキストがタグで囲まれていないのでspanタグをつけ、そこにv-bindします。

              <span v-bind:class="{'done': task.done}">
                {{ task.message }}
              </span>

これでチェックボックスが操作されたときにタスクの完了/未完了が変更されるようになりました。

実際に動作確認してみましょう。

f:id:luca3104:20180304203854g:plain

以上でタスクを完了する実装の終了です。

次回

次回はタスク一覧をlocal storageに保存するようにします。
時間があったら番外編でcssをいじっていこうと思います。

余談

iPadでメモを取るときにこのアプリを使用しています。
ノートがこれ一冊で完結できて、手書きの温もりの残るのでとてもおすすめです!

GoodNotes 4

GoodNotes 4

  • Time Base Technology Limited
  • 仕事効率化
  • ¥960

(なぜかiPadから画像書き出ししても白紙なのでスクショで書き出してます…)

Vue.jsを再入門する 1

Vue.js

jp.vuejs.org

なぜ再入門?

仕事で業務システムのUI側をメインに開発した経験はあるけれども、詳しいところまで調査せずに使ってました。
これを気に色々と調べてもっとまともに使っていけるようになればと思います。

作るもの

ToDoアプリを作ります。
(だいたいToDoアプリを入門で作るので)

Project 作成

vue-cliを使ってプロジェクトを作成します。(リンク参照)

jp.vuejs.org

作成し終わったら npm run dev を実行して起動。

ブラウザから http://localhost:8080/#/ へアクセスし、 f:id:luca3104:20180301124207p:plain このようなページが表示されたら完了です。

開発は src ディレクトリの中でしていきます。

プロジェクト生成後の構成は以下の通りです。

f:id:luca3104:20180301124345p:plain:w300

assets

assets ディレクトリ内はアプリケーションに組み込む画像などの素材ファイルを入れます。

components

components ディレクトリ内はコンポーネントとして作成したファイルを入れます。
拡張子は .vue を使用します。

router

router/index.js はルーティングと表示するコンポーネントを定義しています。

App.vue

アプリケーションとなる部分となります。

main.js

Vueインスタンスを作成し、App.vueと紐づけています。

ToDoアプリ

ToDoアプリの仕様を決めます。

機能一覧

以下が機能です。

機能名 概要
追加 ToDoの追加ができる。
削除 ToDoの削除ができる。
完了 ToDoの完了ができる。
編集 ToDoの編集ができる。

すごいシンプルなToDoアプリを作ります。

UI

特にここには拘らず、ただのリストを作っていきます。

サーバー

今回はモックでやりますが気が向いたらサーバー側も書いていきたいと思います。
最近興味があるGoとかで書きたいなあ・・・

次回

準備が完了したので今回はここまでにします。
次回から実際にToDoアプリを作りながらVueの色々なところを深く探っていけたらと思います。

一週間カリブ海一周旅行をして必須だったものコレクション

カリブ海とは

f:id:luca3104:20180218191706p:plain ココらへん。 行ったところは、マイアミ → ジャマイカ → コズメル (メキシコ) → コスタマヤ (メキシコ) です。
クルーズで行ったので備忘録も含め書きます。

必要なもの

圧縮袋

確実に服だけで荷物がパンパンになります。
服は圧縮して持っていきましょう。
これが一番オススメの圧縮袋です。


チャックを簡単に締めるスライダーがついていて、簡単に締めることができます。
また、チャックの力も強いので空気を抜くときや、運搬中に開くことはありません。
 

ウェストポーチ

パスポートを守るバッグです。
今まで、確実に守るためウェストポーチをつけて服の中に隠して行動してました。 この方法が一番安全と思います。

自分の場合はこれを持っていて、中にクレジットカード、現金、スマホ、船のカードを入れて行動してました。

日焼け止め

めちゃくちゃ日差しが強いので日焼け止めは必須です。
痛いくらい強いです。

SPFPAが高いものを持っていきましょう。

運動着

これは自分がクルーズで旅をしたから特殊かもしれませんが、運動着が必須です。 船内にはジムがあり、毎日運動して汗を流します。 一番のおすすめのコスパがいいのはこれです。

アクティビティに参加する場合は持っていて損は無いです。

水着

どこに行っても海です。
アクティビティも水に入るものが多いので絶対に水着を持っていきましょう。
冬 (2月) でも余裕で海に入れます。 f:id:luca3104:20180218194323j:plain

現金

どこも米ドルで決済できました。
レストランはクレジットカードで大丈夫ですが、露天などでは現金しか受け付けないので現金を持っていきましょう。

最後に

冬のカリブ海は避寒になってとても良いです!
現地には大量のボッタクリがいるので気をつけながら買い物をしましょう。
基本的に、もうお金使い切っちゃったよ!って言うとスルーされます。

マネージャーとしてTeam Geakを読んだ

Team Geek ―Googleのギークたちはいかにしてチームを作るのか

Team Geek ―Googleのギークたちはいかにしてチームを作るのか

過去に一度読みましたが、マネージャーになってからもう一度目を通そうと思い、再読しました。

はじめに」の「対象読者」に書いてありますが、「マネジメント」する人は対象読者ではありません。
しかし内容はマネジメントをする人にとっても重要なことが多く書かれているので読むことを推奨します。

良いなと思う部分をかいつまんで紹介します。

HRT

1章内で何度も書かれている「謙虚・尊敬・信頼」です。
この章では、チームで成功するには「謙虚・尊敬・信頼」の3つが大切だということを伝えています。
マイケル・ジョーダンや様々な名誉あるエンジニアを例に出し、一人では超人的な偉業を達成できるわけではない。としています。
むしろ「一人で仕事するほうがリスクが高い」と。

チーム開発がすべてで、「ソフトウェア開発はチームスポーツである。」と例えています。

そしてその「チーム」で働くときに3つのポイントがあると言います。 それが「謙虚・尊敬・信頼」です。
HRTとはそれぞれの頭文字です。

謙虚 = Humility
尊敬 = Respect
信頼 = Trust

2章ではこのHRTを使ったチームづくりについて書いてあるので是非読んでみてください!

リーダーシップパターン

本書は「マネジメント」をする人は対象ではないとしていますが、3章はエンジニアチームをマネジメントする人には重要な章となります。
特に本書が重要だと伝えたいのは エゴをなくす ということです。
その エゴをなくす 方法も幾つか紹介されています。

解雇されるのを待とう。

これは個人的に面白いなと思いました。 5章の 5.5 プランB:逃げる の章で書かれているものです。

Googleの新しい従業員からどうすれば仕事をうまくやれるのかとよく聞かれる。私は半分冗談でこう答えている。簡単なことだ。私はGoogleと世界にとって「正しいこと」をしている。あとは座って解雇されるのを待つだけだ。解雇されなければ、「正しいこと」ができたことになる。解雇されたら雇用主を間違えたのだ。いずれにしても私は正しいことをしている。これが私のキャリア戦略だ。

この気持ちで働けば解雇されない限りうまく仕事をしているって気持ちになれますねw

4月以降からiOSアプリを審査にiPhone Xの対応が必要に

タイトルの通りです。
Submitting iOS apps to the App Store - Apple Developer

Update your app for iPhone X. Test your apps to make sure they are ready to take advantage of the Super Retina display by respecting safe areas, supporting adaptive layouts, and more. Find and address UI issues in your app before testing on a device to make sure your app looks great on iPhone X.

翻訳すると、

iPhone Xに対応したアプリのアップデートが必要です。Safe Areaを考慮し、アダプティブレイアウトに対応するなど、Super Retinaディスプレイを最大限に活かしましょう。デバイスでテストする前にUIの問題点を見つけて解決し、iPhoneX上で良い見た目のアプリにしましょう。

iPhone X流行らないと思ってそこまで対応しなくていいかなと思ってましたが・・・

 
こちらは日本語で書かれているiPhone Xに対応するためのページです。
iPhone X用にアプリケーションをアップデートする - iOS - Apple Developer