※スマホ対応はしてません。

propsのvalidationをさらっと書けるvue-props-templateを作りました。(Vue.js始めるおれおれアドベントカレンダー2016 – 18日目)

カテゴリー: JavaScript

Vue.js始めるおれおれアドベントカレンダー2016 – 18日目

作りましたというか、まだもうちょっといじろうと思ってるんだけど、動きはします。

ginpei/vue-props-template: Write vue’s props through template literal.

Reactもそうなんだけど、オブジェクトを入れ子にしてく書き方、なかなか面倒じゃないですか。そういうのをなんかこう装飾子みたいにさらってできねえかなーそういやテンプレート文字列は改行も含められるんだなーあれでやれたらいいなーと考えて作ってみました。

propsの検証

Vueの機能として、型等を指定することができます。

こんな感じ。

const MyComponent = {
  props: {
    simpleString: { type: String },
    requiredNumber: { type: Number, required: true },
    defaultBoolean: { type: Boolean, default: true },
    validatedObject: {
      validator: function (value) {
        return (value.flag1 && value.flag2)
      }
    }
  }
}

vue-props-template

さっきの指定を、だいたいこう書けるようになります。

const pt = require('vue-props-template')

const MyComponent = {
  props: pt`
    string simpleString
    required number requiredNumber
    boolean defaultBoolean = true
  `
}

どうでしょうか、こういうの。

あとは validatedObject をどうしようかなあというところです。現状こんなん。

const pt = require('vue-props-template')

const MyComponent = {
  props: pt.extend(pt`
    object validatedObject
    `, {
      validatedObject: {
        validator: function (value) {
          return (value.flag1 && value.flag2)
        }
      }
    }
  }
}

よくわからないこと

便利?

個人的にはあんな風に書けたら便利だと思ってるんだけど、他の人はどうなんだろ。まあ自分で使う用でも構わないんだけど。

既存でこういうのないか?

ちょっと探して見つからなかったけどありそうで怖い。

validator の扱い

埋め込み値 ${…} の中に関数を書くのってどうかなあ。別に良いかなあ。例えばこういうの。

props: pt`
  validatedObject as ${function (value) {
    return (value.flag1 && value.flag2)
  }}
`

あーこういうのも悪くないかなあ。どうかなあ。

この場合、他の「型 名前」の順の書き方と違ってきちゃうけど、んーまあ良いか。

最近のライブラリの作り方

Vue本体を参考に、ブラウザで読み込んでもNode.js(vueify)経由でも動くようにはした。でも今はそれを直接元コードに書いてて、なんかこう「ビルド」をしてそういうのを出力するやり方の方が良いだろうか。

あとバージョン管理も実はあんまりよくわかってない。semverは良いんだけど、なんか手動でぽちぽちやるんじゃなくてnpm scriptに更新コマンドも用意して、なんて話を前聞いた気がする。

他にやること

これ全部終わったらv1.0.0ということにしようかなと思ってます。

  • validator の扱い
  • バベる
  • ドキュメントの見直し
  • GitHub pagesの充実
  • npm登録

そうか、要素に触るなら$refsとmountedを組み合わせれば良いのか。(Vue.js始めるおれおれアドベントカレンダー2016 – 16日目分)

カテゴリー: JavaScript

Vue.js始めるおれおれアドベントカレンダー2016 – 16日目分(24日公開)

しゅんしゅん動くよ。

アニメーション付きのナビバーを作ってみました、簡単でした。やったね。

基本的な作り方

  • location.hash を監視して情報更新
  • hashに該当する内容を表示
  • バー位置をhashの候補の順序から算出

簡単に作れたは良いんだけど、最後のやつどうしようかなと。

バー位置をhashの候補の順序から算出

最初に書いたコードはこう。

<nav>
  <a href="#">Home</a>
  <a href="#about">About</a>
  <a href="#contact">Contact</a>
  <span :style="underlineStyle"></span>
</nav>
const store = require('./store.js')

const hashes = ['', '#about', '#contact']

module.exports = {
  data () {
    return store.state
  },
  computed: {
    underlineStyle () {
      const itemWidth = 100
      const left = itemWidth * hashes.indexOf(this.hash)
      return {
        transform: 'translateX(' + left + 'px)'
      }
    }
  }
}

これで全然動くんだけど、疑問点が二つ。

  • 候補値 '', '#about', '#contact' をHTML側と共有しているの、どうにかならんかな
  • 項目の幅 100 をCSS側と共有しているの、どうにかならんかな

jQueryであれば実際の要素を見てあれこれするんだけど、Vueはそうはしないじゃないすか。普通。

$refs を使う?

とか言いつつ要素を見てあれこれするやつ、使ったらできるにはできた。

<nav ref="list">
  <a href="#">Home</a>
  <a href="#about">About</a>
  <a href="#contact">Contact</a>
  <span :style="underlineStyle"></span>
</nav>
computed: {
  /**
   * 項目の幅の実測値を返す。
   */
  itemWidth () {
    const elList = this.$refs.list
    const elItem = elList.firstElementChild
    return elItem.clientWidth
  },

  /**
   * 項目の `href` からhash候補値を得る。
   */
  hashes () {
    const elList = this.$refs.list
    const elItems = elList.children
    const hashes = Array.from(elItems).map(elItem => {
      let hash = elItem.getAttribute('href')
      if (hash === '#') {
        hash = ''
      }
      return hash
    })
    return hashes
  },

  underlineStyle () {
    let left

    // 最初のDOM構築の際には当然underlineStyleは呼ばれるが、
    // 最初だからDOMがまだないので、 `$refs` が使えない。
    if (this.$refs.list) {
      left = this.itemWidth * this.hashes.indexOf(this.hash)
    } else {
      // `hash` 変更時にキャッシュ値を更新するよう、
      // ここで呼んで記憶してもらう
      left = this.hash.length * 0
    }

    return {
      transform: 'translateX(' + left + 'px)'
    }
  }
},

うわあ、すごく危険な香りがする。

実際公式ガイドにもやめてねって書いてあるし。

$refs はコンポーネントが描画された後にのみ追加されます。そしてそれはリアクティブではありません。直接子コンポーネントを操作するための最終手段としての意味しかありません。テンプレートまたは算出プロパティの中での $refs の使用は避けるべきです。

うん。

テンプレートまたは算出プロパティの中での $refs の使用は避けるべきです。

そう思います。

マウントのタイミングで確認したい……

……マウント……ライフサイクル……ん?

module.exports = {
  data () {
    return {
      itemWidth: 999,
      hashes: [],
      state: store.state
    }
  },
  mounted () {
    const elList = this.$refs.list
    const elItems = elList.children

    this.itemWidth = elItems[0].clientWidth

    this.hashes = Array.from(elItems).map(elItem => {
      let hash = elItem.getAttribute('href')
      if (hash === '#') {
        hash = ''
      }
      return hash
    })
  },
  computed: {
    underlineStyle () {
      const left = this.itemWidth * this.hashes.indexOf(this.state.hash)
      return {
        transform: 'translateX(' + left + 'px)'
      }
    }
  }
}

なるほど、こういう感じか。これなら良さそう。

バンクーバーの電車遅延情報をSlackで流すよ。(Frog Advent Calendar 2016 – 16日目)

カテゴリー: JavaScript

Frog Advent Calendar 2016 – 16日目

カナダの西海岸に位置する、海も山も和食もある街バンクーバーのFrog Houseからお届けします。

技術の話ですが、せっかくなのでバンクーバーの紹介もさせて頂こうかと思います。

概要

  • シェアハウス内はSlackで連絡を取っている
  • バンクーバーの電車遅延はウェブページで公開されている
  • ページをスクレイピング、加工して情報取得
  • Slack botで定期的に情報を取得、問題があれば通知する

こんな感じ。チュートリアルではないのであんまり細かい手順やコードは載せてません、各種公式ドキュメントや実装コードをご確認願います。

遅延と回復を検知して通知。

フロッグハウス

Frog Houseというシェアハウスがバンクーバーにございまして、私ギンペイは現在そこに在住しております。住人は七名、うち私を含む五名がウェブ制作方面の人間です。

Slack

かつてはFacebookメッセージで家の中の連絡をしていたんですが、なかなか煩雑なのと検索性能が低いことから、Slackを導入しました。今のところうまく回っているようです。Slackはいいぞ。

最近二軒目Frog House 2ndも統合して、別チャンネル同チームで運用しております。なんか家賃とかそういうアレの管理をまとめてしたかったんですって。

現在チームには20のチャンネルが作成されていまして、全体用 #general と一軒目用 #general-1 みたいに分けて運用してます。まあ各自で適当に作ったりしてもらえれば良いかと。

先に申し上げた通りウェブ系の人が多いので、 #webdev チャンネルを設けて情報共有したりもしてます。たのしい。

とまあそんな感じで、日常生活にSlackを組み込んだ感じですね。

バンクーバーの交通事情

割と北米は車文化が根強い感じはあるんですが、バンクーバーでは “SkyTrain” という呼称で電車が走ってます。バンクーバーのダウンタウン(中心街)を軸に三本の路線が稼働中です。

ちなみに電車、無人運転です

東京のゆりかもめ線みたいな感じ。すげーぞカナダ人。

車両の先頭はこんな景色。あ、わかりづらいこれ……

あと改札も無人。前は性善説もとい諸事情により扉もなく開放されていたんですが、最近はSuicaみたいな “Compass” というカードが導入されまして、通るたびにピッピッとやります。オートチャージはなくて、駅に設置の機械でチャージしてやります。

(さらに…)

短縮記法でちゃちゃっと書こう。(Vue.js始めるおれおれアドベントカレンダー2016 – 15日目)

カテゴリー: JavaScript

Vue.js始めるおれおれアドベントカレンダー2016 – 15日目

テンプレートの短縮記法

よく使う v-bind と v-on は短く書けます。

<!-- 完全な構文 -->
<a v-bind:href="url"></a>
<a v-on:click="doSomething"></a>

<!-- 省略記法 -->
<a :href="url"></a>
<a @click="doSomething"></a>

JavaScript

Vueは割と先進的なJS構文を使ってる場合が多いすね。

オブジェクト

一部のチュートリアルでオブジェクト作るときにこういうの書いてるのをみかけるかもしれません。

const state = require('./store.js')
const mutations = require('./mutations.js')

module.exports = { store, mutations }

この { store } なんですが、 { store: store } の省略です。プロパティ名と変数名が同じ場合にこう書けます。つまりこういうこと。

const store = require('./store.js')
const mutations = require('./mutations.js')

module.exports = {
  store: store,
    mutations: mutations
}

関数

一部のチュートリアルでオブジェクト作るときにこういうの書いてるのもみかけるかもしれません。

new Vue({
  computed: {
    sayHello () {
      return 'Hello'
    }
  }
})

function が書いてないけど、関数です。つまりこういうこと。

new Vue({
  computed: {
    sayHello: function () {
      return 'Hello'
    }
  }
})

getter/setter

もしかしたらこういうのもあるかも。

const obj = {
  get fullName () {
    return this.firstName + ' ' + this.lastName
  },
  set fullName (name) {
    const [ firstName, lastName ] = name.split(' ')
    this.firstName = firstName
    this.lastName = lastName
  }
}

これは短縮記法とは違う気もするんだけど、getter, setterをちゃちゃっと作る構文です。

ついでに [ a, b ] = array も短縮記法ですね。こんな風に書けます。

const obj = { a: 123, b: 234 }
const { a } = obj
console.log(a)  // => 123

const arr = [ 11, 22 ]
const [ first ] = arr
console.log(first)  // => 11

よくわからないこと

HTML的に妥当?

先の公式ガイドによると、以下。

これらは普通の HTML とはちょっと違うように見えるかもしれません。ですが、 : や @ は属性名に利用可能な文字です。

ほんと?

原文の方でもvalid chars for attribute namesだから誤訳でもなさそう。

いやまあ別に妥当じゃなくても個人的には構わないんだけど。

VueでAjaxやるときはaxiosがおすすめなんだって。(Vue.js始めるおれおれアドベントカレンダー2016 – 14日目)

カテゴリー: JavaScript

Vue.js始めるおれおれアドベントカレンダー2016 – 14日目

Vueあんまり関係ない感じだけど、全く関係ないわけでもないので良しとしてください。

VueでAjax

かつては公式で vue-resource というライブラリを用意していたけれど、今は axios というライブラリが公式推奨であるらしい。

axios

使い方も簡単そう。

IE 8+で動作。手厚い。(ちなみにVue.js v2はIE 9+。) もちろん昔の環境で動かすには最近の書き方は通じませんので、なんかまあバベるとか何とかしてください。

インストール

$ npm i -S axios
const axios = require('axios')

使い方

axios.get(url) みたいにして送信、戻り値はPromise。

res.data に応答内容が入ってるみたい。

data: {
  sending: false
},
methods: {
  form_submit (event) {
    this.sending = true

    axios.get(url, data)
      .then(res => {
        this.sending = false
        console.log(res.status, res.statusText, res.data)
        // => 200, "OK", { message: "You just sent the data!" }
      })
      .catch(error => {
        this.sending = false
        throw error
      })
  }
}

もっとVueに繋げる

vue-resourceはVueと密に繋がって、 this.$http.get() みたいな感じで使うそうだ。

axiosは完全に独立しているけれど、 this から参照できるようにしたい場合用に、vue-axiosというものを用意している人がいた。

これを導入すると this.axios.get() が使えるようになるとか。(試してません。)

長所は require() を省けることくらい? んーでも省かない方が思想的に良いのでは。

よくわからないこと

公式推奨って

何だろ? どこかに一覧とかあるのかな?

原文の表現は、引用符付きで “official recommendation” 。