孤独プログラマー譚

孤独死が近い。

JavaScript オブジェクトの結合

オブジェクトの結合について、情報整理。
 
 
以下、既存のオブジェクトに、別のオブジェクトを結合する場合。
ES6で書けない時はjQueryを使う。

var nogizaka1 = {
  shiraishi: 'mai',
  akimoto: 'manatsu',
}
var nogizaka2 = {
  hori: 'miona',
  suzuki: 'ayane',
}

// jQueryのメソッド
$.extend(nogizaka1, nogizaka2)
console.log(nogizaka1)
// {shiraishi: "mai", akimoto: "manatsu", hori: "miona", suzuki: "ayane"}

// ES6
Object.assign(nogizaka1, nogizaka2)
console.log(nogizaka1)
// {shiraishi: "mai", akimoto: "manatsu", hori: "miona", suzuki: "ayane"}

 
 
以下、結合して新しいオブジェクトを生成する場合。

// jQueryのメソッド
var nogizaka3 = $.extend({}, nogizaka1, nogizaka2)
console.log(nogizaka3)
// {shiraishi: "mai", akimoto: "manatsu", hori: "miona", suzuki: "ayane"}

// ES6
var nogizaka3 = Object.assign({}, nogizaka1, nogizaka2)
console.log(nogizaka3)
// {shiraishi: "mai", akimoto: "manatsu", hori: "miona", suzuki: "ayane"}

// ES6 スプレッド演算子
var nogizaka3 = { ...nogizaka1, ...nogizaka2 }
console.log(nogizaka3)
// {shiraishi: "mai", akimoto: "manatsu", hori: "miona", suzuki: "ayane"}

スプレッド演算子を積極的に使いたい。

JavaScript プロパティの初期化

JavaScriptの小ネタ。

以下、よくあるインスタンス生成時のプロパティセット。

var personal_info = {
  name: 'Tom',
  age: '20',
}

function Person(personal_info) {
  this.name = personal_info.name
  this.age = personal_info.age
  this.indroduce_myself = function () {
    console.log(`私は${this.name}、${this.age}歳です。`)
  }
}

var person = new Person(personal_info)
person.indroduce_myself() // 私はTom、20歳です。

 
 
プロパティセット部分を Object.assign に置き換える。

function Person(personal_info) {
  Object.assign(this, personal_info)
  this.indroduce_myself = function () {
    console.log(`私は${this.name}、${this.age}歳です。`)
    // 私はTom、20歳です。
  }
}

だらだらと複数個のプロパティをセットしていく必要が無くなる。
玄人っぽくて良い!

Vue.js Ajaxを使った連動するセレクトボックス

1つ目のセレクトボックスの項目を非同期通信で取得。
そこで選択した項目を元に、2つ目のセレクトボックスの項目も非同期で取得する。

f:id:halation-summer:20190113232507g:plain

<div id="app">
  <select v-model="selected_category_id">
    <option v-for="item in category_list" :value="item.id">{{ item.name }}</option>
  </select>
  <div>{{ selected_category_id }}</div>
  <select v-model="selected_animal_id">
    <option v-for="item in animal_list" :value="item.id">{{ item.name }}</option>
  </select>
  <div>{{ selected_animal_id }}</div>
</div>


1つ目のセレクトボックス項目は created 内で取得。
2つ目のセレクトボックス項目は watch 内で取得。

new Vue({
  el: '#app',
  data: {
    category_list: [],
    selected_category_id: null,
    animal_list: [],
    selected_animal_id: null,
  },
  async created () {
    this.category_list = (await axios.get('http://localhost/animals/category/')).data
    this.selected_category_id = this.category_list[0].id
  },
  watch: {
    async selected_category_id () {
      this.animal_list = (await axios.get(`http://localhost/animals/animals/${this.selected_category_id}/`)).data
      this.selected_animal_id = this.animal_list[0].id
    },
  },
})


算出プロパティを使えるかと思ったけど、どうも非同期通信は使えないみたいで…。
そもそも算出プロパティは return で値を返すので、Promise では return を2回返すことはできないという…。

Vue.js 全て入力後に送信可能になるボタン

テキストフィールドに全て入力完了後、disabledが解除されて送信可能になるボタン。

f:id:halation-summer:20190112140948g:plain

<div id="app">
  <div><input v-model="field1"></div>
  <div><input v-model="field2"></div>
  <div><input v-model="field3"></div>
  <div>{{ entered_all }}</div>
  <button :disabled="!entered_all">submit</button>
</div>
new Vue({
  el: '#app',
  data: {
    field1: '',
    field2: '',
    field3: '',
  },
  computed: {
    entered_all () {
      const required_fields = [
        this.field1,
        this.field2,
        this.field3,
      ]
      return required_fields.indexOf('') === -1
    },
  },
})

jQueryはDOMからD0Mを直接触っていたが、
Vue.jsはViewModelを介す必要があるから、jQueryと考え方が違って面白い。

Vue.js 複数チェックボックスを全て選択で切り替え

よくある「全て選択」チェックボックス

f:id:halation-summer:20190112075758g:plain

<div id="app">
  <div v-for="(item, index) in items">
    <input type="checkbox" :value="item" v-model="checked_items">{{ labels[index] }}
  </div>
  <div>{{ checked_items }}</div>
  <input type="checkbox" v-model="checked_all">check_all<br>
  <div>{{ checked_all }}</div>
</div>
new Vue({
  el: '#app',
  data: {
    items: ['value1', 'value2', 'value3'], // 全てのvalue値
    labels: ['label1', 'label2', 'label3'],
    checked_items: ['value2'], // 初期値
  },
  computed: {
    checked_all: {
      get () {
        return this.checked_items.length === this.items.length
      },
      set (checked) {
        this.checked_items = checked ? this.items : []
      },
    },
  },
})


以下の部分は、サーバーサイドレンダリングで配列に値をつっこんでもいいし、
AJAXで取得してきてもいい。

data: {
  items: ['value1', 'value2', 'value3'], // 全てのvalue値
  labels: ['label1', 'label2', 'label3'],
  checked_items: ['value2'], // 初期値
},

Vue.js 単一ファイルコンポーネントと通常使用の併用

通常使用とは何なのかというと、HTMLのscriptタグ内で、new Vue() してやること…ということにします。

単一ファイルコンポーネントは使いたい。
でも、他のHTML要素の方も、Vue.jsで制御したい。
その場合、どうすればいいか、調べてもよく分からなった。

例えば、ボタンを押した時にアラートメッセージを出す…等の小さい制御も、Vue.jsで書きたい。
でもそれは、単一ファイルコンポーネントにする程ではない。
かと言って、大きめの動的な要素は、単一ファイルコンポーネントを使いたい。

そこで、以下の方法でやることにした。

main.js
Webpack等でバンドルする際のエントリーポイント。
Vue.extend()は、再利用可能なコンストラクタを生成するらしい。
components や data をVueコンストラクタに登録しつつも、新たなコンストラクタを作る。
それを、global.Vue …要はグローバル変数に入れてやる。
これで、各HTMLファイルから、new Vue() してやることが出来る。

global.Vue = Vue.extend({
  components: {
    menulist: Menu,
    detail: Detail,
  },
  data () {
    return {
      foo: 'foo'
    }
  },
  router,
})

以下、HTMLファイル。
Vueコンストラクタからインスタンスを生成している。

<div id="app">
  <div>{{ foo }}</div>
  <div>{{ bar }}</div>
</div>
<script src="bundle.js"></script>
<script>
new Vue({
  el: '#app',
  data: {
    bar: 'bar',
  },
})
</script>

Webアプリ共通の設定 → エントリーポイントで登録
各HTMLページ毎の設定 → scriptタグ内で登録

という感じで作ってやる。今のところこれが一番スッキリしてると思う。

Windows+PHP+Vdebug ブレイクポイントで止まらない

Vimを使う者として、IDE統合開発環境)に負けたくないという気持ちはある。

だが、さすがにログや画面にvar_dump()し続けることに疲れてきてしまった。

ということで、vdebug(ステップ実行できるVimプラグイン)を使うことにした。

環境:
Windows10
Docker
PHP7
Xdebug
Gvim(Kaoriya)

・vdebugの設定
let g:vdebug_options['path_maps'] = {"/var/www/html": "C:/Users/me/my_project/html"}

バックスラッシュで「C:\Users\me\my_project\html」と指定すると、動かない。
「C:/Users/me/my_project/html」通常スラッシュにすると、動く。

しかし、なぜかブレイクポイントで止まらない。ブレイクポイントを設定しても無視される。なぜ?

PHPStormだと、正常にブレイクポイントで止まる。でもvdebugだと止まらない。このままだと…IDEに負けてしまう!?

Xdebugのログを比べてみた。

(一部略)
・PHPStorm
breakpoint_set -f file:///var/www/html/index.php


・vdebug
breakpoint_set -f "file:///C:\Users\me\my_project\html\index.php"

ファイルの指定部分がローカルになっている…?

仕方なく、プラグインのソースを追ってみる。
うっ、Pythonで書かれてる…勉強せねば…。

・変数
remote : file:///var/www/html
local : C:/Users/me/my_project/html
filename : C:\Users\me\my_project\html\index.php


filename = filename.replace(local, remote)

どうも、/ と \ の違いが原因で、置換が上手くいってないっぽい。

/vdebug/python3/vdebug/util.py


def _create_remote(f):
 ret = f
 ret = ret.replace('\\', '/') ← 追加

これで、正常に置換できて、ブレイクポイントでも止まるようになった。

今日一日が無駄にならず済みました。

これからは「Vimでもステップ実行できる」と胸張って言えるぞ~。