Djangoroidの奮闘記

python,django,angularJS1~三十路過ぎたプログラマーの奮闘記

Vue.js 入門 vol.2

参考サイト

https://jp.vuejs.org/v2/guide/instance.html

コンストラクタ

  • vm (ViewModel の略) を Vue インスタンスの変数名としてよく使うらしい。

  • すべてのVue vmは、Vueコンストラクタ関数(new Vue)で、root Vue instance を作成することから始まる。root Vue instanceは、Vue instanceとはちょっと違うと思うので、注意。

  • Vue constructorを拡張することで、再利用可能な ComponentConstructorを生成できる。

var MyComponent = Vue.extend({
  //extendで、コンストラクタを拡張できる。
})

var MyComponentInstance = new MyComponent()
// MyComponentから、生成されるinstanceは、extendオプションで定義した拡張オプションを利用して生成される。

プロパティとメソッド

Vue インスタンスは、自身の data オブジェクトの全てのプロパティをプロキシします:

var data = { a: 1}
var vm = new Vue({
  data: data
})

vm.a === data.a // true になる

vm.a = 2
data.a // これは2になる

data.a = 3
vm.a // これは3にtなる
  • 上記のような状態を、dataオブジェクトのすべてのプロパティをプロキシする と表現するらしい(^^)ようは、どちらが変更するとそれに合わせてもう一方も変更するということか。
var data = {a: 1}
var vm = new Vue({
  el: '#example',
  data: data
})

vm.$data === data // true
vm.$el === document.getElementById('example') // true

vm.$watch('a', function(newVal, oldVal){
  // このコールバックは、'vm.a'の値が変わるときに呼ばれる。
})
  • 上記でvm.data, vm.el ではなく、vm.$data, vm.$elとなっている理由は、vue instanceの場合(javascriptでも同じなのか?)は、vm.dataで定義したプロパティ を呼び出すように設定されているので、vm.elではたぶん呼び出しができない。たぶん、vue instanceのプロパティ、メソッドの呼び出しには、デフォで、$が必要な気がする。

  • $watchは、指定した変数などに変更があったときに、コールバックするメソッドを指定する。

インスタンスライフサイクルフック

  • lifecycle hooks の呼び出し。createdは、instance生成後にコールされる。
var vm = new Vue({
  data: {
    a: 1
  },
  created: function(){ // created は、instance 生成後にコールされる!
    // 'this' は、vm インスタンスを指します。
    console.log('a is: ' + this.a)
  }
})
// -> "a is: 1"
  • mounted, updated, destroyed などがある。
  • すべてのlifecycle hooksは、thisがVueインスタンスを指す。

テンプレート構文

展開

  • テキストの場合
<span>Message: {{ msg }}</span>
<span v-once>This will never change: {{ msg }}</span>
<!-- v-once directiveは、1度だけ展開することができる -->
  • 生のhtml(基本使用しないのか?)
<div v-html="rawHtml"></div>
<!-- v-htmlを利用する -->
  • 属性 HTML属性の内部では、{{}}は使えないので、v-bindを使う。
<div v-bind:id="dynamicId"></div>
<button v-bind:disabled="someDynamicCondition">Button</button>
  • Javascript式の使用。{{}}の中で、javascriptの式を使える。v-bindでは、""の中で使える。
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id"></div>

<!-- 以下は動作しない。単一の式ではないため -->
<!-- これは文であり、式ではありません: -->
{{ var a = 1 }}
<!-- フロー制御もいずれも動作しません。三項演算子を使用してください -->
{{ if (ok) { return message } }}

ディレクティブ

  • v-if文の例
<p v-if="seen">Now you see me</p>
  • 引数
<a v-bind:href="url"></a>
<!-- href 属性に、urlを代入する -->

<a v-on:click="doSomething">
<!-- clickすろと、doSomethingメソッドを実行する -->
  • 修飾子(modifier)
<form v-on:submit.prevent="onSubmit"></form>
<!-- submitのときに、event.preventDefault()を呼び出して、onSubmitを実行する -->
<!-- preventDefault()は、本来の動作を停止して、別の動作を実行するときに使う -->
<!-- 例えば、入力フォームで、エラーを検知したときは、submitせずに、alertを表示させるなど -->
  • フィルタ(mustache 展開と v-bind 式)
{{ message | capitalize }}
<!-- in v-bind -->
<div v-bind:id="rawId | formatId"></div>
// * Vue instance内のフィルタ関数
new Vue({
  // ...
  filters: {
    capitalize: function (value) {
      if (!value) return ''
      value = value.toString()
      return value.charAt(0).toUpperCase() + value.slice(1)
    }
  }
})
  • フィルタの連結、引数
{{ message | filterA | filterB }}
{{ message | filterA('arg1', arg2) }}

省略記法

  • v-bind と v-on は省略できる。
<!-- 完全な構文 -->
<a v-bind:href="url"></a>
<!-- 省略記法 -->
<a :href="url"></a>

<!-- 完全な構文 -->
<a v-on:click="doSomething"></a>
<!-- 省略記法 -->
<a @click="doSomething"></a>

算出プロパティとウォッチャ

  • 複雑なロジックには、算出プロパティを使う。

  • 基本的な例

<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // 算出 getter 関数
    reversedMessage: function () {
      // `this` は vm インスタンスを指します
      return this.message.split('').reverse().join('')
    }
  }
})
  • 算出プロパティ vs メソッド. メソッドでも同じように設定できる。
<p>Reversed message: "{{ reverseMessage() }}"</p>
// コンポーネント内
methods: {
  reverseMessage: function () {
    return this.message.split('').reverse().join('')
  }
}
  • 結論的には、キャッシュを使うので、算出プロパティの方が早いかもしれないらしい。

算出プロパティ vs 監視プロパティ

  • 結論的には、多くのケースでは、算出プロパティを使おうとのこと。
<div id="demo">{{ fullName }}</div>
// こっちは、watch propertyを使った場合
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  },
  watch: {
    firstName: function (val) { // firstNameに変更があった場合に、full nameを変更する。
      this.fullName = val + ' ' + this.lastName
    },
    lastName: function (val) { // lastNameに変更があった場合に、fullNameを変更する。
      this.fullName = this.firstName + ' ' + val
    }
  }
})
// こっちが算出プロパティを使った場合
var vm = new Vue({
    el: '#demo',
    data: {
        firstName: 'Foo',
        lastName: 'Bar',
    },
    computed: {
      fullName: function(){
        return this.firstName + ' ' + this.lastName
      }
    }  
})

算出 Setter 関数

  • 算出プロパティはデフォルトでは getter 関数のみですが、必要があれば setter 関数も使えます(getter functionは、vm.fullNameのように、プロパティから値を取り出す関数のこと。setter functionは、vm.fullName = ‘Joe Yabuki'のように、プロパティに値をsetする関数のこと)
//...
computed: {
  fullName: {
    //getter
    get: function(){
      return this.firstName + ' ' + this.lastName
    },
    //setter
    set: function(newValue){
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}

watch(ウォッチャ)

  • 多くのケースでは、算出プロパティを使ったほうがいいんだけど、watch オプションも豊富のよう。ajaxを利用するときは、watchオプションを使うことが多いのかな。
<div id="watch-example">
  <p>
    Ask a yes/no question:
    <input v-model="question">
  </p>
  <p>{{ answer }}</p>
</div>
<!-- ajax ライブラリの豊富なエコシステムや、汎用的なユーティリティ -->
<!-- メソッドがたくさんあるので、Vue のコアはそれらを再発明せずに       -->
<!-- 小さく保たれています。この結果として、慣れ親しんでいるものだけを   -->
<!-- 使えるような自由さを Vue は持ち合わせています。           -->
<script src="https://unpkg.com/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://unpkg.com/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
  el: '#watch-example',
  data: {
    question: '',
    answer: 'I cannot give you an answer until you ask a question!'
  },
  watch: {
    // この関数は question が変わるごとに実行されます。
    question: function (newQuestion) {
      this.answer = 'Waiting for you to stop typing...'
      this.getAnswer()
    }
  },
  methods: {
    // _.debounce は特にコストの高い処理の実行を制御するための
    // lodash の関数です。この場合は、どのくらい頻繁に yesno.wtf/api
    // へのアクセスすべきかを制限するために、ユーザーの入力が完全に
    // 終わるのを待ってから ajax リクエストを実行しています。
    // _.debounce (とその親戚である _.throttle )  についての詳細は
    // https://lodash.com/docs#debounce を見てください。
    getAnswer: _.debounce(
      function () {
        if (this.question.indexOf('?') === -1) {
          this.answer = 'Questions usually contain a question mark. ;-)'
          return
        }
        this.answer = 'Thinking...'
        var vm = this
        axios.get('https://yesno.wtf/api')
          .then(function (response) {
            vm.answer = _.capitalize(response.data.answer)
          })
          .catch(function (error) {
            vm.answer = 'Error! Could not reach the API. ' + error
          })
      },
      // ユーザーの入力が終わるのを待つ時間をミリ秒で指定します。
      500
    )
  }
})
</script>

まとめ

  • 算出プロパティ超便利