JavaScript
Node.js
vue.js
pug

dotinstall で勉強している初心者がVue.jsの公式ガイドを勉強するメモ 宣言的レンダリング編

学習編

  • 前回の環境編でせっかく作った環境ですので、それを使って学習していきたいと思います。

宣言的レンダリング

<!DOCTYPE html>
<html>
<head>
  <title>Welcome to Vue</title>
  <script src="https://unpkg.com/vue"></script>
</head>
<body>
  <div id="app">
    <span v-bind:title="message">
       Hober ....
    </span>
  </div>

  <script>
    var app = new Vue({
      el: '#app',
      data: {
        message: 'You loaded this page on ' + new Date().toLocaleString()
      },
      methods: {
      }
    })
  </script>
</body>
</html>
  • リロードは手動で行なってください。
  • 画面に表示されている Hover..が表示されていますが、見る場所はconsole側です。
  • Elementsを開き、spanタグのtitle属性がリアクテブになっているのかを確認します。
  • ブラウザーのコンソールで確認します。
    • app.message = 'some new message' // 記述は若干違います
    • title属性が書き換わっているのが確認出来たのでokです。

node側

  • App.vue - 今後この記述は、node側の記述です。
<template lang="pug">
  #App
    span(v-bind:title="message") Hober.....
</template>

<script>
export default {
  name: 'app',
  data () {
    return {
      message: 'You loaded this page on ' + new Date().toLocaleString()
    }
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>


  • こちらは、オートリロードで便利ですね。
  • こちらも、ブラウザーのコンソールで確認してみますが。。。
    • app.message = 'some new message'ではないですね。。。 参照エラーですね
  • App.setAttribute('title','some new message') でtitleを書き換えできますが、これは本来の趣旨と違うんでしょうね。
  • わかる方教えてもらえると助かります。 Question 01

条件分岐とループ

  • index.html
<!DOCTYPE html>
<html>
<head>
  <title>Welcome to Vue</title>
  <script src="https://unpkg.com/vue"></script>
</head>
<body>
  <div id="app">
   <span v-if="seen">Now you see me</span>
  </div>

  <script>
    var app = new Vue({
      el: '#app',
      data: {
        seen: true
      },
      methods: {
      }
    })
  </script>
</body>
</html>
  • ブラウザーコンソールでapp.seen = falseと叩くと、spanタグ自体が無くなっているので、OKですね。

node側

  • App.vue
<template lang="pug">
  #app
    button(v-on:click="seen = !seen") toggle
    div(v-if="seen") Now you see me
</template>

<script>
export default {
  name: 'app',
  data () {
    return {
      seen: false,

    }
  }
}
</script>

<style lang="scss">
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

  • コンソールで書き換えがわからないので、違う方法で確認してみます。
  • ここでは、ボタンで true / false を切り替えて見ます。
  • seen の値で、v-if が切り替わっているのがわかります。
    • ここでは、div属性自体が無くなっていることもブラウザーのデベロッパーツールで確認して見てください。

v-for

  • index.html
<!DOCTYPE html>
<html>
<head>
  <title>Welcome to Vue</title>
  <script src="https://unpkg.com/vue"></script>
</head>
<body>
  <div id="app">
    <ol>
      <li v-for="todo in todos">
        {{ todo.text }}
      </li>
    </ol>
  </div>

  <script>
    var app = new Vue({
      el: '#app',
      data: {
        todos: [
          { text: 'Learn JavaScript' },
          { text: 'Learn Vue' },
          { text: 'Build something awesome' }
        ]
      },
      methods: {
      }
    })
  </script>
</body>
</html>
  • コンソールで追加もしてみます。
    • app.todos.push({text: 'new item'})
    • 追加されているので、OKです。

node

  • App.vue
<template lang="pug">
  #App
    ol
      li(v-for="todo in todos") {{ todo.text }}
</template>

<script>

export default {
  name: 'app',
  data () {
    return {
      todos: [
        { text: 'Learn JavaScript' },
        { text: 'Learn Vue' },
        { text: 'Build something awesome' }
      ]
    }
  }
}


</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  /* display: inline-block; */
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>
  • こちらも、表示されているのでOKです。
  • リアクティブ確認の追加は、buttonで追加してみます。

  • App.vue

<template lang="pug">
  #app
    button(v-on:click="todos.push({ text: 'new item' })") 追加
    ol
     li(v-for="todo in todos")
       | {{ todo.text }}
</template>

<script>
export default {
  name: 'app',
  data () {
    return {
      todos: [
        { text: 'Learn JavaScript' },
        { text: 'Learn Vue' },
        { text: 'Build something awesome' }
      ]
    }
  }
}
</script>

<style lang="scss">
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>


  • ボタンで追加されているのがブラウザーで確認できるのでOKですね。
  • 次に行く前に、両環境ともGitコミットしておきましょう

  • atomでコミットするほうが簡単ですがターミナルでコミットしておきます。

  • git add .

  • git commit -m "v-forまで完了"

  • もう一度最初のコミット位置から勉強するには、コミットを巻き戻します.

  • git log でコミット一覧を確認します。

commit d9b322b983728c3f012d3a8474973309d72184b4
Date:   Wed Jan 24 16:44:52 2018 +0900
    v-forまで完了

commit 6177e20641048db29f582adf4bf8ec8cada4f01a
Date:   Wed Jan 24 01:37:40 2018 +0900
    first

  • 最初のコミットまで巻き戻します.
  • git reset --hard 6177e20641048db29f582adf4bf8ec8cada4f01a
    • 尚commit番号は最初の6桁ほどがあれば大丈夫みたいです。
  • 今回は、そのまま次の記事に行きますので、戻しておきます。
  • git reflog で巻き戻しの履歴を確認します
  • git reset --hard d9b322

ユーザー入力の制御

  • index.html
<!DOCTYPE html>
<html>
<head>
  <title>Welcome to Vue</title>
  <script src="https://unpkg.com/vue"></script>
</head>
<body>
  <div id="app">
    <p>{{ message }}</p>
    <button v-on:click="reverseMessage">Reverse Message</button>
  </div>

  <script>
    var app = new Vue({
      el: '#app',
      data: {
        message: 'Hello Vue'
      },
      methods: {
        reverseMessage () {
          this.message = this.message.split('').reverse().join('')
        }
      }
    })
  </script>
</body>
</html>
  • ボタンを押すと関数が走り、messageの値を書き換えて、書き換わったmessageをVueが検知して、画面描画をしている感じですかね。

  • App.vue

<template lang="pug">
  #App
    p {{ message }}
    button(v-on:click="reverseMessage") Reverse Message
</template>

<script>

export default {
  name: 'app',
  data () {
    return {
      message: 'Hello Vue'
    }
  },
  methods: {
    reverseMessage () {
      this.message = this.message.split('').reverse().join('')
    }
  }
}


</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  /* display: inline-block; */
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>
  • こちらも、問題なく動いていますね。

v-model

  • index.html
<!DOCTYPE html>
<html>
<head>
  <title>Welcome to Vue</title>
  <script src="https://unpkg.com/vue"></script>
</head>
<body>
  <div id="app">
    <input type="text" v-model="message"/>
    <p>{{ message }}</p>
  </div>

  <script>
    var app = new Vue({
      el: '#app',
      data: {
        message: 'Hello Vue'
      },
      methods: {
      }
    })
  </script>
</body>
</html>
  • App.vue
<template lang="pug">
  #App
    input(v-model="message")
    p {{ message }}
</template>

<script>

export default {
  name: 'app',
  data () {
    return {
      message: 'Hello Vue'
    }
  },
  methods: {
  }
}

</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  /* display: inline-block; */
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>
  • input など特定のときしか使えないみたいですが、Vueなら簡単にできますよ。 みたいな感じの機能ですね。
  • 次に行く前に、必要ならバックアップ(commit)しておいてください。

コンポーネントによる構成

  • index.html
<!DOCTYPE html>
<html>
<head>
  <title>Welcome to Vue</title>
  <script src="https://unpkg.com/vue"></script>
</head>
<body>
  <div id="app">
    <ol>
      <todo-item></todo-item>
      <todo-item></todo-item>
      <todo-item></todo-item>
    </ol>
  </div>

  <script>
    Vue.component('todo-item', {
      template: '<li>This is a todo</li>'
    })
    var app = new Vue({
      el: '#app',
      data: {
      },
      methods: {
      }
    })
  </script>
</body>
</html>

  • 独自タグで書けるようになるみたいですね。

  • App.vue

<template lang="pug">
  #App
    ol
      todo-item
      todo-item
      todo-item
</template>

<script>

export default {
  name: 'app',
  data () {
    return {
      message: 'Hello Vue'
    }
  },
  methods: {
  }
}

</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  /* display: inline-block; */
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>
  • main.js
import Vue from 'vue'
import App from './App.vue'


Vue.component('todo-item', {
  template: '<li>This is a todo</li>'
})

 new Vue({
  el: '#app',
  render: h => h(App)
})
  • component はどこに書くのがいいのか迷いました。 とりあえず、jsの元締めである、main.jsに書きました。
  • いい場所がみつかったら、その時移動します。

props

  • componentへの値の引き渡しの為に利用するみたいです。

  • index.html

<!DOCTYPE html>
<html>
<head>
  <title>Welcome to Vue</title>
  <script src="https://unpkg.com/vue"></script>
</head>
<body>
  <div id="app">
    <ol>
      <todo-item v-for="item in list" v-bind:todo='item'></todo-item>
    </ol>
  </div>

  <script>

    Vue.component('todo-item', {
      props: ['todo'],
      template: '<li>{{ todo.text }}</li>'
    })
    var app = new Vue({
      el: '#app',
      data: {
        list: [
          { id: 0, text: 'Vegetables' },
          { id: 1, text: 'Cheese' },
          { id: 2, text: 'Whatever else humans are supposed to eat' }
        ]
      },
      methods: {
      }
    })
  </script>
</body>
</html>
  • v-for と v-bind のあわせ技ですね。 違いはv-bindの行き先が,appのdataではなく、componentのpropsであるtodoになるところですね。

  • App.vue

<template lang="pug">
  #App
    ol
      todo-item(v-for="item in list" v-bind:todo="item")
</template>

<script>

export default {
  name: 'app',
  data () {
    return {
        list: [
          { id: 0, text: 'Vegetables' },
          { id: 1, text: 'Cheese' },
          { id: 2, text: 'Whatever else humans are supposed to eat' }
        ]
    }
  },
  methods: {
  }
}

</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  /* display: inline-block; */
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>
  • main.js
import Vue from 'vue'
import App from './App.vue'


Vue.component('todo-item', {
  props: ['todo'],
  template: '<li>{{ todo.text }}</li>'
})

 new Vue({
  el: '#app',
  render: h => h(App)
})
  • componentを書いている場所が違うだけで、内容は一緒です。
  • 初心者向け同士なので、抜き出さず全掲載していますが、どこを書き換えているかわかりづらいですね。 どうしたら、わかりやすく書けるのか慣れないと難しいです。
  • atomの拡張パッケージである,split-diffを入れると、見比べできるので違いがわかりやすいです。 重宝してます
  • とりあえず、変化の少ないstyleタグは、次回から省略して掲載していきます。
  • 今回は、ここで終了です。 git commitして終わります
  • 次回は、インスタンス編ですが 現時点でまだ書くかどうか決めていません(笑)。