20200916のvue.jsに関する記事は6件です。

Vue/Nuxtを使っている開発チームへ参画するまでの学習ロードマップ

はじめに

今回はVue.js/Nuxt.jsを用いて開発しているプロジェクトへ参画するまでに、どういったことを学習すれば良いかについて話していこうと思います。
私自身、8月からVue.js/Nuxt.jsを用いて開発しているチームへ配属されフロントエンドの開発をさせていただいておりますので、実際にどういった勉強をしてきたのかを書いていきます。

また、私の場合はVue/Nuxtチームに参画することになると概ね決まったのが参画の1ヶ月前でしたので、約1ヶ月間の学習となります。

さて、何からはじめよう?

最初どの教材で勉強するかについては、私的には特にこだわりはなかったので、周りで良い評判を聞いていた下記のUdemyの講座を購入して学習しました。

超Vue.js 2 完全パック - もう他の教材は買わなくてOK! (Vue Router, Vuex含む)

上記でVue.jsについてざーっと勉強した後は、下記のUdemy講座でNuxt.jsについても軽く勉強しました。

Nuxt JS入門決定版!Vue.jsのフレームワークNuxt JSの基本からFirebaseと連携したSPAの開発まで

※ 一応知らない方のために言っておきますと、Udemyは月に2,3回程セールをやっている期間がありますので、購入する際はその期間に買いましょう。めちゃめちゃ安くなります。

実際の現場ではどういう手法で開発しているかを知ろう

実際に参画することになるチームの方と連絡をとることができないのであれば仕方ありませんが、連絡可能であるならば事前にどういった勉強をすれば良いか聞いてみると良いでしょう。
そこで色々とリサーチすることができたら、あとはそのことについてひたすら勉強していきましょう。
(上記のUdemy講座などで学習する前に先に聞いても、順番はどちらでも構いません。)

私のチームの場合は、Atomic Designをベースに開発していて、UIフレームワークにはVuetifyを使っていたり、細かいところで言うとstoreへのアクセスはヘルパー関数を使っているということを聞いたので、その部分について学習していきました。
また、「Vue/Nuxtを使って2画面くらいの何かしらのツールを作ってみてください」と課題までくださったので、簡単なTodoアプリの作成も行いました。
そして作ったTodoアプリをレビューしていただいてアドバイスをもらい、修正などを行うことで、より理解を深めることができました。
(流石にここまでやってくださる会社さんはあまりないかも知れませんが。。)

そうして勉強しているうちにチームに参画されました。

さいごに

結局のところ、チームに参画してスムーズに開発を始めていくには、そのチームの方に聞いて教えていただいた内容を学習することだと思います。
私はこれで、Vue/Nuxtを全く知らないところからかなりスムーズに開発に混ざることができたかなと思います。

以上で短いですが、ご参考になれば幸いです。
最後までお読みくださりありがとうございます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

イチから始めるVueJS

カスタムディレクティブを使いこなす

Vueではv-modelv-showなど以外にも、自分でディレクティブを定義することができる

<!-- HTML -->
<div id="hoge">
  もしかして<span v-highlight>ほげぇ</span>ですか?
</div>

<!-- Vue -->
<script>
Vue.directive('highlight', {
    inserted: (el) => {
      el.style.backgroundColor = 'yellow';
    }
  });

new Vue({
    el: '#hoge',
});
</script>

learning_html.png

directiveメソッドの使い方は以下の通り

directive(name,def)

nameでディレクティブ名を、
defで、そのディレクティブが行う動作を定義する

ディレクティブのフック関数を定義する

「どのタイミングでディレクティブを実行するか」をフック関数が決めている。
例えば、先の例のinserted:もこれに該当する
他にも下記のようなフック関数が存在する。

  • bind:

    • ディレクティブが初めて対象の要素にひも付いた時に 1 度だけ呼ばれる。
  • inserted:

    • ひも付いている要素が親 Node に挿入された時。
  • update:

    • 要素を抱合している親コンポーネントが更新された時。
  • componentUpdated:

    • 抱合している小コンポーネントが更新された時。
  • unbind:

    • ディレクティブがひも付いている要素から取り除かれた時に 1 度だけ呼ばれる。

引数をみてみる

上記の例では、フック関数の引数にelしか取っていない。
実際には、他にも引数があるが、省略されている。
それぞれの引数を確認していこう

  • el:ディレクティブが適用された要素

  • binding:以下のプロパティを持っているバインド情報オブジェクト

    • name
      • ディレクティブの名前(highlight)
    • value
      • ディレクティブが受け取った値("Yellow")
    • expression
      • 文字列としてのバインド式("color")
    • ....etc

プラグインを使ってみる

プラグインを有効化する

プラグインはCDNとして呼び込むことが可能。今回はvee-validateを使用してみた。

<!-- HTML -->
<script src="https://cdn.jsdelivr.net/npm/vee-validate@latest/dist/vee-validate.js"></script>
<div id="app">
    <form>
        <label for="name">URL:</label>
        <input v-validate="'required|url'" data-vv-as="URL" id="url" name="url" />
    </form>
    <span v-if="errors.has('url')">{{ errors.first('url') }}</span>
</div>

<!-- Vue -->
<script>
Vue.use(VeeValidate, { locale: 'ja' });

new Vue({
    el: '#app'
});
</script>

下記のメソッドでプラグインを有効化する

Vue.use('有効化するプラグイン名', 'プラグインのオプション');

単一ファイルコンポーネントとは

単一ファイルコンポーネントとは、コンポーネントを構成するtemplate要素、script要素,style要素を一つにまとめたもの。
import時にはtemplateタグで囲まれた要素が渡される

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h2>Essential Links</h2>
    <ul>
      <li>
        <a
          href="https://vuejs.org"
          target="_blank"
        >
          Core Docs
        </a>
      </li>
      <li>
        <a
          href="https://forum.vuejs.org"
          target="_blank"
        >
          Forum
        </a>
      </li>
      <li>
        <a
          href="https://chat.vuejs.org"
          target="_blank"
        >
          Community Chat
        </a>
      </li>
      <li>
        <a
          href="https://twitter.com/vuejs"
          target="_blank"
        >
          Twitter
        </a>
      </li>
      <br>
      <li>
        <a
          href="http://vuejs-templates.github.io/webpack/"
          target="_blank"
        >
          Docs for This Template
        </a>
      </li>
    </ul>
    <h2>Ecosystem</h2>
    <ul>
      <li>
        <a
          href="http://router.vuejs.org/"
          target="_blank"
        >
          vue-router
        </a>
      </li>
      <li>
        <a
          href="http://vuex.vuejs.org/"
          target="_blank"
        >
          vuex
        </a>
      </li>
      <li>
        <a
          href="http://vue-loader.vuejs.org/"
          target="_blank"
        >
          vue-loader
        </a>
      </li>
      <li>
        <a
          href="https://github.com/vuejs/awesome-vue"
          target="_blank"
        >
          awesome-vue
        </a>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

ここで style-scopedに注目してほしい
style-scopedで定義されたデザインは配下のコンポーネントでのみ有効になる。
もしこれがstyleだけだと、全体にデザインが適用されてしまうので注意が必要

vue-cliを使ったroutesの設定

routesの設定はsrc/routes/index.jsに記述する

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },
    {
      path: '/top',
      redirect: '/'
    }
  ]
})

ここで作成されたroute設定は、src/main.jsでVueインスタンスと紐づけられる。

main.js
import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

routerrouter: routerの省略系。プロパティ名と変数名が同じ時は、このように省略することができる。

Vueのライフサイクルフック

Vueインスタンスは インスタンスの生成→要素へのマウント→データの変更に応じたビューの更新→破棄の一連の流れを辿る。
これをライフサイクルと呼び、この流れの中で都度呼ばれるメソッドをライフサイクルフックと呼ぶ。

  • beforeCreate...created
    • Vueインスタンスの生成まで
  • bwforeMount...mounted
    • インスタンスをページに紐づけるまで
  • beforeUpdate...updated
    • Viewの更新(再描画)まで(データに更新が会った時しか呼ばれない)
  • beforeDestroy...destroyed
    • インスタンスの破棄まで

image.png

Vueのリアクティブな挙動

dataについて

dataに格納されているプロパティはリアクティブデータと呼び、プロパティの値が替わるたびにViewの再描画が行われる。
timerを設定して、一定時間ごとにcurrentを更新した場合の動作を見てみよう

<!-- HTML -->
<div id="app">
  <p>現在時刻:{{ current.toLocaleString() }}</p>
</div>

<!-- Vue -->
<script>
  new Vue({
    el: '#app',
    data: {
      current: new Date()
    },
    created: function () {
      let that = this;
      this.timer = setInterval(function () {
        that.current = new Date();
      }, 1000);
    },
    beforeDestroy: function () {
      clearInterval(this.timer);
    }
  });
</script>

Image from Gyazo

一方でプロパティの追加・削除時にはこれらの変更が検知されることはなく、再描画が行われない。

<!-- HTML -->
<div id="app">
  <p>著者情報:{{ author.name }}({{ author.company }})</p>
</div>

<!-- Vue -->
<script>
  let app = new Vue({
    el: '#app',
    data: {
      author: {
        name: '山田'
      }
    },
    created: function () {
      let that = this;
      this.timer = setTimeout(function () {
        that.author.company = 'WINGSプロジェクト';
      }, 1000);
    },
    beforeDestroy: function () {
      clearInterval(this.timer);
    }
  });
</script>

今回はauthor.companyを追加したが、Viewの再描画は行われなかった。

Vue.setメソッドを使うことで、追加をViewへ伝播させることができる

<!-- HTML -->
<div id="app">
  <p>著者情報:{{ author.name }}({{ author.company }})</p>
</div>

<!-- Vue -->
<script>
  let app = new Vue({
    el: '#app',
    data: {
      author: {
        name: '山田',
        // company: ''
      }
    },
    created: function () {
      let that = this;
      this.timer = setTimeout(function () {
        Vue.set(that.author, 'company', 'WINGSプロジェクト');
      }, 3000);
    },
    beforeDestroy: function () {
      clearInterval(this.timer);
    }
  });
</script>

Image from Gyazo

watchについて

プロパティに変化があった場合、その変更を監視してViewに伝播させることを先述した。
watchオプションを使うことで、変更があった時の動作を細かく設定することができる

今回は入力後2秒後に文字列が大文字になるようにした

<!-- HTML -->
<div id="app">
  <label>名前:
    <input type="text" v-model="name" />
  </label>
  <p>入力された値:{{upperName}}</p>
</div>

<!-- Vue -->
<script>
  new Vue({
    el: '#app',
    data: {
      name: '',
      upperName: ''
    },
    created: function () {
      this.delayFunc = _.debounce(this.getUpper, 2000);
    },
    watch: {
      name: function (newValue, oldValue) {
        this.delayFunc();
      }
    },
    methods: {
      getUpper: function () {
        this.upperName = this.name.toUpperCase();
      }
    }
  });
</script>

Image from Gyazo

$watchメソッドを使ってこのように書き換えることもできる

!-- HTML -->
<div id="app">
  <label>名前:
    <input type="text" v-model="name" />
  </label>
  <p>入力された値:{{upperName}}</p>
</div>

<!-- Vue -->
<script>
  new Vue({
    el: '#app',
    data: {
      name: '',
      upperName: ''
    },
    created: function () {
      let that = this;
      this.delayFunc = _.debounce(this.getUpper, 2000);
      let watch = this.$watch('name',function(newVal,oldVal) {

      })
    },
    watch: {
      name: function (newValue, oldValue) {
        this.delayFunc();
      }
    },
    methods: {
      getUpper: function () {
        this.upperName = this.name.toUpperCase();
      }
    }
  });
</script>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.js コンポーネントについて初心者がまとめる

この記事について

公式や書籍で学んでまとめたことを記す記事です。
https://jp.vuejs.org/v2/guide/components.html
https://www.amazon.co.jp/dp/B07RN3YD79/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1

コンポーネントとは?

Webアプリを作成していく上で、headermain-bodyなどのUIを構成する部品がたくさんあって成り立っているが、大きな開発になるとメンテナンスがとても大変になっていく。
そこでVue.jsはそのUIの部品ごとにHTMLとはjsファイルを管理することで、他のUI部品とは切り離してメンテナンスをすることができる仕組みのことをコンポーネントと呼ぶ。
この仕組みによってメンテナンスをしたいコードを早く見つけることができるし、色んなファイルを行ったり来たりしなくてもいいようになる!

実際のコードを書いていく

main.html
<div id="app">
   <my-component></my-component>
</div>
main.js
Vue.component('my-component', {
    template: '<p>COMPONENT!!!!</p>'
})

new Vue({
    el: '#app'
})

ブラウザの表示
スクリーンショット 2020-09-16 9.47.53.png

コードの解説

Vue.component

Vue.componentmy-componentという新しいコンポーネントを定義。

templateオプション

描画させたいテンプレートを指定する。

HTML<my-component></my-component>

jsで定義したmy-componentと置き換わる場所。
今回であれば<p>COMPONENT!!!!</p>が置き換わっている。

注意すること

コンポーネントはnew Vue()より早くに定義をしないといけない。

dataは関数で定義する

new Vueと同じようにdataと同じようにdataオプションを定義することができるが、Vue.componentは関数で定義をする必要がある。

main.html
<div id="app">
   <my-component></my-component>
</div>
main.js
Vue.component('my-component', {
    template: '<p>{{ message }}</p>',
    data: function() {
       return {
           message: "阪神が巨人に全く勝てない"
       }
    }
})

new Vue({
    el: '#app'
})

ブラウザの表示
スクリーンショット 2020-09-16 10.03.16.png

templateオプションの注意点

templateオプションに指定するオプションは必ず全体を単一のタグで囲まないといけない!

main.html
<div id="app">
   <my-component></my-component>
</div>
main.js
Vue.component('my-component', {
    template: '<span>{{ team1 }}</span>:<span>{{ team2 }}</span>',
    data: function() {
       return {
           team1: "阪神",
           team2: "巨人"
       }
    }
})

new Vue({
    el: '#app'
})

ブラウザの表示
スクリーンショット 2020-09-16 10.08.03.png

templateで1つのタグで囲んでいないため、コンパイルでエラーが起きて期待通りに表示されない。
そこで<div></div>で1つに囲む

main.js
Vue.component('my-component', {
    //divタグで囲んでやる
    template: '<div><span>{{ team1 }}</span>:<span>{{ team2 }}</span></div>',
    data: function() {
       return {
           team1: "阪神",
           team2: "巨人"
       }
    }
})

new Vue({
    el: '#app'
})

ブラウザの表示
スクリーンショット 2020-09-16 10.12.09.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.js コンポーネントについて阪神タイガースを主張しながらまとめる

この記事について

公式や書籍で学んでまとめたことを記す記事です。
https://jp.vuejs.org/v2/guide/components.html
https://www.amazon.co.jp/dp/B07RN3YD79/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1

コンポーネントとは?

Webアプリはheadermain-bodyなどのUIを構成する部品がたくさんあって成り立っているが、大きな開発になるとメンテナンスがとても大変になっていく。
そこでVue.jsはそのUIの部品ごとにHTMLとjsファイルを管理することで、他のUI部品とは切り離してメンテナンスをすることができる仕組みのことをコンポーネントと呼ぶ。
この仕組みによってメンテナンスをしたいコードを早く見つけることができるし、色んなファイルを行ったり来たりしなくてもいいようになる!

実際のコードを書いていく

main.html
<div id="app">
   <my-component></my-component>
</div>
main.js
Vue.component('my-component', {
    template: '<p>COMPONENT!!!!</p>'
})

new Vue({
    el: '#app'
})

ブラウザの表示
スクリーンショット 2020-09-16 9.47.53.png

コードの解説

Vue.component

Vue.componentmy-componentという新しいコンポーネントを定義。

templateオプション

描画させたいテンプレートを指定する。
今回の場合だと、<p>COMPONENT!!!!</p>を描画させる

HTML<my-component></my-component>

jsで定義したmy-componentと置き換わる場所。
今回であれば<p>COMPONENT!!!!</p>が置き換わっている。

注意すること

コンポーネントはnew Vue()より早くに定義をしないといけない。

dataは関数で定義する

new Vueと同じようにdataと同じようにdataオプションを定義することができるが、Vue.componentは関数で定義をする必要がある。

main.html
<div id="app">
   <my-component></my-component>
</div>
main.js
Vue.component('my-component', {
    template: '<p>{{ message }}</p>',
    data: function() {
       return {
           message: "阪神が巨人に全く勝てない"
       }
    }
})

new Vue({
    el: '#app'
})

ブラウザの表示
スクリーンショット 2020-09-16 10.03.16.png

templateオプションの注意点

templateオプションに指定するオプションは必ず全体を単一のタグで囲まないといけない!

main.html
<div id="app">
   <my-component></my-component>
</div>
main.js
Vue.component('my-component', {
    template: '<span>{{ team1 }}</span>:<span>{{ team2 }}</span>',
    data: function() {
       return {
           team1: "阪神",
           team2: "巨人"
       }
    }
})

new Vue({
    el: '#app'
})

ブラウザの表示
スクリーンショット 2020-09-16 10.08.03.png

templateで1つのタグで囲んでいないため、コンパイルでエラーが起きて期待通りに表示されない。
そこで<div></div>で1つに囲む

main.js
Vue.component('my-component', {
    //divタグで囲んでやる
    template: '<div><span>{{ team1 }}</span>:<span>{{ team2 }}</span></div>',
    data: function() {
       return {
           team1: "阪神",
           team2: "巨人"
       }
    }
})

new Vue({
    el: '#app'
})

ブラウザの表示
スクリーンショット 2020-09-16 10.12.09.png

改行して見やすくしてみよう

'<div><span>{{ team1 }}</span>:<span>{{ team2 }}</span></div>'のままだと、見づらいので改行するようにする。
見やすく改行して記述するためにはバッククオテーションで囲む

main.js
template: `
           <div>
               <span>{{ team1 }}</span>:<span>{{ team2 }}</span>
           </div>`

ローカルスコープで登録

親コンポーネントのcomponentオプションに子コンポーネントを定義すると、その親コンポーネント以下が以下らは参照できないようになり、ローカルスコープとして制限することができる。

main.html
<div id="app">
   <my-component></my-component>
</div>
main.js
//親コンポーネント
new Vue({
    el: '#app',
    components: {
        "my-component" : myComponent
    }
})
my-component.js
//子コンポーネント
var myComponent = {
    template: '<p>{{message}}</p>',
    data: function() {
       return {
           message: "阪神頑張れ!!!!"
       }
    }
}

ブラウザの表示
スクリーンショット 2020-09-16 10.40.36.png

解説

my-component.jsではvar myComponent = {}の形をしている。つまり、ただ単にオブジェクトをmyComponentという変数に入れているだけ。

myComponentを宣言しているところはグローバルスコープだから親コンポーネント(main.js)から参照することができる。

③そこで、componentsオプションにmy-componentというプロパティを定義して、そのプロパティの値にmyComponentを関連づけさせる。

一応スコープについて確認しておく

  • ローカルスコープ
    関数の中で宣言した変数、 もしくは関数の仮引数でその関数の中でのみ参照できる

  • グローバルスコープ
    関数の外(トップレベル)で宣言した変数で、プログラム全体から参照できる

データの受け渡し(親から子へ)

同じ人間でも親から子へと言葉に表せないモノが受け継がれていく。
そんなレガシーを受け継いで行けるのは人間だけではなく、Vue.jsでもできちゃう。
親から子へとデータを渡すためには親と子それぞれで準備が必要!

①子が親からデータを受け取るプロパティ名を決めて、子コンポーネントのpropsオプションに定義するぞ〜。

propsに定義したプロパティは親からデータを受け取るための入れ物になる。
今回ではmessage1message2を受け取るようになっている。

my-component.js
var myComponent = {
    template: `
    <div>
        <span>{{ message1 }}</span><span>{{ message2 }}</span>
    </div>`,
    props: ["message1", "message2"]
}

②テンプレート側に子コンポーネントのpropsで定義したプロパティ名の属性を使って、渡したいデータをブチ込む。親から子へのデータを渡すときは属性を通じて渡されるんや。

main.html
<div id="app">
    <my-component message1="阪神は巨人に勝てないの?" message2="なぜ東京ドームで勝てないの?"></my-component>
    <my-component message1="サンズにまじ感謝!" message2="ボーアそろそろホームラン!"></my-component>
</div>

main.jsは変更なし

my-component.js
new Vue({
    el: '#app',
    components: {
        "my-component" : myComponent
    }
})

ブラウザの表示
スクリーンショット 2020-09-16 13.09.33.png

リアクティブなデータを受け取るためには?

①親にデータをいれる

main.js
new Vue({
    el: '#app',
    components: {
        "my-component" : myComponent
    },
    data: {
        message1: "能見さんが心配",
        message2: "ホンマに頑張って"
    }
})

②親のテンプレートに記述した子のカスタムタグにv-bindでバインドする

main.html
<div id="app">
    <my-component v-bind:message1="message1" v-bind:message2="message2"></my-component>
</div>

子コンポーネントに変更なし

これで親のデータが変われば描画されるデータにも反映される。

ブラウザの表示
スクリーンショット 2020-09-16 13.25.31.png

データの受け渡し(子から親へ)

時には子から親へ受け継ぐこともある。それをVue.jsでも実現してやる。
子からは親のテンプレートを見ることができないから、属性を介してデータを渡すことができない。
そこで、子は親にデータを渡したいタイミングでイベントハンドラを呼び出すようにさせる。
$emitを使って親から子へハンドラを介してデータを渡すぞ。

$emit("発生させたいイベント名", イベントハンドラに渡すデータ)

ここではボタンを押せば阪神がひたすらに対巨人に連勝することができる夢の機能を実現させる。

①子から親のイベントハンドラを呼び出す

子からボタンが押されると、v-onで指定したclickHandlerメソッドが呼び出される。
ここまでは親の登場なく、全て子で完結している。

my-component.js
var myComponent = {
    template: `
    <div>
        <button v-on:click="clickHandler">阪神に連勝させる</button>対巨人{{win}}連勝中
    </div>
    `,
    props: ["win"],
    methods: {
        clickHandler: function() {
            // 子コンポーネントにchild-clickを発生させる
            this.$emit("child-click")
        }
    }
}

②親のテンプレートで、child-clickが発生した時に親のイベントハンドラが呼び出されるようにする

ここで$emitメソッドを実行することで、子にchild-clickメソッドを実行させる。
これは開発者が勝手に名付けることができるカスタムメソッドで、親のテンプレートを通じて親のイベントハンドラを呼び出すために架け橋になってくれる役目がある。

main.html
<div id="app">
     <!-- 子のchild-clickが発生することでwiningメソッドを呼び出す -->
    <my-component v-on:child-click="winning" v-bind:win="win"></my-component>
</div>

③親のイベントハンドラを定義する

main.js
new Vue({
    el: '#app',
    components: {
        "my-component" : myComponent
    },
    data: {
        win: 1
    },
    methods: {
        // 子から呼び出されるメソッド
        winning: function() {
            this.win += 1;
        }
    }
})

ブラウザの表示
スクリーンショット 2020-09-17 13.38.08.png

まとめ

子から親へデータを渡すときは$emitを使う。
親から子へデータを渡すときはpropsを使う。

ポートフォリオを作成している時にでも、「この表示されてる該当のコードはどこや?」と、探すことは確かにあったな〜ってコンポーネントを学びながら思った。
Vue.jsを最初から導入しちゃえば、フロント管理の生産性が上がりそうやから早く別のポートフォリオ作りたい!!!!

ただ、Docker環境でrailsにVue.jsの導入になぜか苦戦中。。。。
独学でコケるときはとことんコケちゃう。

続きはまた別の記事で

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初心者がCodePenのサンプルを駆使したら、マジシャンの兄のプロフィールページを良い感じに作れた話。

私の兄はマジシャンです

いきなりですが、私の兄は「デビッドちんすこう」という名前で沖縄スタイルのマジシャンをしております。
沖縄出身ですが、現在は大阪を中心に活動中!
image.png

マジシャンのイメージからは程遠い風貌。
そして、マジシャンなのにオリジナルソングを5曲ほど作詞作曲。
(各配信サービスでリリースしてるので検索してみてね♪)

単独ライブでは、客席も一緒になってタオルをぶんぶん振り回す新スタイルのマジシャンです。

HP無い問題

そんな自慢の兄なんですが、いかんせん公式HPが無い。
(私が作れと言われてたけど、忘れてた。)

でも色んなメディアで発信しているので、情報が散漫としているのが課題でした。

こうした課題を解決できないかと思い、
これまで学んできた技術で兄のプロフィールページ的なものを作れないか挑戦してみました!

いざ作成開始!

CodePenでサンプル探し

意気揚々と作成開始したものの、UI作るの超苦手!きゃ~!
ここはネットに転がっているサンプルを駆使しよう!ということで、
CodePenで良い感じのサンプル探しから始めました。

CodePen は、ブラウザ上で HTML・CSS・JavaScript のコードを記述することができ、リアルタイムで表示を確認しながら開発ができるサービスです!

Image from Gyazo

このように色んなサンプルが公開されていて、初心者にはとても参考になります!

そして今回、私はこちらのサンプルを使うことにしました!
Image from Gyazo

このサンプルの写真や色を少し変更すると・・・
じゃじゃ~~ん!
Image from Gyazo
簡単に良い感じのページが出来上がりました!

SNSボタンもお兄ちゃん用にカスタマイズしました!
参考:初心者でも、これを読めばOK!簡単にSNSボタンを作れる方法!【Bootstrap/HTML/CSS】

YouTubeを埋め込む①~フレーム作成~

兄が最近力を入れているのは、そう!YouTube!!!

なので、どうしてもYouTubeの動画を埋め込みたい。
まずはhtmlにフレームを作成しました。

        <div style="text-align: center;">    
            <iframe 
             width="240" height="180" 
             src=""
             frameborder="0" allow="accelerometer; autoplay; 
             encrypted-media; gyroscope; picture-in-picture" 
             allowfullscreen></iframe>
        </div>

これでOKかな。どれどれ・・・
Image from Gyazo
あれ・・・???
スクロールできない・・・!?

フレームの上部だけが、虚しく「こんにちは」状態です。

調べてみたところ、原因はCSSにありました。

  overflow:hidden;

overflowがhiddenになっていると、ページの大きさを超えたところは非表示になるそうです。

  overflow:hidden;
  overflow-y:scroll;

それを、上記のように変更。
overflow-xは横軸、overflow-yは縦軸のスクロールを意味します。今回は縦軸のみでOK!
Image from Gyazo
無事にスクロールバーが表示されました♪

YouTubeを埋め込む②~チャンネルから動画データを取得~

せっかくなので、兄のYouTubeチャンネルから
最新の動画を引っ張ってきて表示されるようにしたいなと調べていたら
YouTube DATA APIでチャンネルごとや動画ごとにjsonデータを抽出できそうなのが判明!

最近習った、enebular(Node-RED)を使って、独自のWebAPIを作成しました!

▼作り方は以下記事にまとめてます。
YouTube DATA APIを使って、特定のチャンネルだけのjsonデータを取得する方法!!!

YouTubeを埋め込む③~フレームに動画データをはめこむ~

さぁ、あとは取得したデータをはめこむだけです!

簡単に行くかと思いきや、URLに変数データを代入するのに苦戦し、泣く泣く質問記事を投稿。
【質問記事】URLの中に変数を代入する方法を教えてください【Vue.js】

秒速で @kkent030315 さんから回答をいただき、あっという間に解決しました。
ありがとうございます><

        <div style="text-align: center;">    
            <iframe 
             width="240" height="180" 
             v-bind:src="video"
             frameborder="0" allow="accelerometer; autoplay; 
             encrypted-media; gyroscope; picture-in-picture" 
             allowfullscreen></iframe>
        </div>
      </div>
    </div>
    <script> 
        const app = new Vue({
          el: '#app',
          data: {
              video:''
          },
          mounted:function() {
            axios
            .get('WebAPIのURL')

            .then(response => {
              console.log(response.data)
              this.video="https://www.youtube.com/embed/"+response.data
            })
          }
        })
    </script>

これで、無事に動画を埋め込むことができました!!!

プレビュー

スマホで開かれることを想定しているので、Twitterにあげたスマホでのプレビュー動画をご覧ください!

良い感じ~~~~~~!

作った後に気づいたこと

WebAPIの制限

私がenebularで作ったWebAPI、時間制限あるんですね。笑
寝て起きたら、動画表示されなくなってました、、、
(スクールの先生が忠告してくれてた気はするのですが、その時よく理解していなかったすみません・・・)

(追記)同じスクールの同期も、同じ穴に落ちていたのがわかりました!笑
彼が解決策などもふまえてわかりやすく記事にしてくれているので、皆さんはこちらを参考にしていただければ…!
enebular上のNode-REDで作ったLINE BOTが1時間経ったら動かなくなる件の解決方法

まぁでも、新しい技術に触れられたからプラマイゼロということで!
兄のページは直しておきます…(笑)

サンプルを活用すれば、素敵なページを作れる!

改めて、この世には使えるものがたくさんあるなぁと実感しました。

ゼロから新しいものを作るのは素敵なことですが、かなり負荷がかかっちゃいます。
それがストレスになって一歩を踏み出せないぐらいなら、
楽しみながら作れる範囲で、使えるものを駆使して、作りたいものを程よいバランスで作っていく!

そういうアウトプットが大事だなぁと思いました。

最後に一言

デビッドちんすこうの応援よろしくお願いします!!!!!!!!!!

https://debichin.ml/

(*^^)v「よろしければLGTMもよろしくお願いします!」
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.js Slotの使い方

Vue.jsのスロットについて使い方が曖昧だったので、公式ドキュメントから自分なり咀嚼してまとめる。

slotとは

受け取った子コンポーネントに親コンポーネントから要素の受け渡しができる。

子コンポーネント<slot></slot>の部分に親コンポーネントで渡した要素が入る

navigationLink.vue
<template>
 <a href= "https://www.google.com/"
  class="nav-link">
  <slot></slot>
</a>
</template>

Parent.vue
<template>
  <div id="app">
    <navigationLink>
      Googleへのリンク
    </navigationLink>
  </div>
</template>

結果
Image from Gyazo
もしも <navigationLink> のテンプレートが 要素を含まない場合、開始タグと終了タグの間にある任意のコンテンツは破棄される。
この場合だと、Googleへのリンクは破棄され、何も描画されなくなる

・スロットには任意のタグや他のコンポーネントを埋め込むことが出来る

Parent.vue
<template>
 <!--ボタンタグを埋め込み-->
 <navigationLink>
  <button>Googleへのリンク</button>
 </navigationLink>

<!--コンポーネントの埋め込み-->
 <navigationLink>
  <List />
 </navigationLink>
</template>

フォールバックコンテンツ

フォールバックとは、通常使用する方式や系統が正常に機能しなくなったときに、機能や性能を制限したり別の方式や系統に切り替えるなどして、限定的ながら使用可能な状態を維持すること。 また、そのような切り替え手順・動作のこと
参考:IT用語辞典 e-Words

つまり、子コンポーネントのButtonタグの間に何も記述がなかった場合、切り替え手順として<slot>タグ間に設定してあるSubmitが描画される

Button.vue
<template>
<button type="submit">
  <slot>Submit</slot>
</button>
</template>
Parent.vue
<template>
  <div id="app">
 <!--Submitが表示される-->
  <Button></Button>
  <!--送信が表示される-->
  <Button>送信</Button>
  </div>
</template>

名前付きスロット

複数のスロットを使う際に、名前を付けて場合分けをする
名前付きスロットを使う場合は<template>タグで囲い、v-slotで名前をつける
今回は<template v-slot:header>とする
子コンポーネントでは<slot name="header">のように指定する
<template>タグで囲っていない要素は名前なしの<slot>に入る

Parent.vue
 <div id="app">
   <baseLayout>
    <!-- <slot name="header" />に入る -->
    <template v-slot:header>
     <h1>Here might be a page title</h1>
    </template>

   <!-- 名前なしslotに入る -->
     <p>A paragraph for the main content.</p>
     <p>And another one.</p>

   <!-- <slot name="footer" />に入る -->
    <template v-slot:footer>
     <p>Here's some contact info</p>
    </template>
   </baseLayout>
  </div>
baseLayout.vue
 <div class="container">
  <header>
  <!-- 親コンポーネントのv-slot:headerの要素を受け取る -->
    <slot name="header" />
  </header>
  <main>
    <!-- 名前を付けない場合はtemplete外の要素を受け取る -->
    <slot></slot>
  </main>
  <footer>
    <!-- 親コンポーネントのv-slot:footerの要素を受け取る -->
    <slot name="footer"></slot>
  </footer>
</div>

名前なしを明示的に指定したい場合は
<template v-slot:default>のようにdefaultをつける

コンパイルスコープ

このスロットはParent.vue内のdataにアクセス出来る。
navigationLink.vueのスコープにはアクセス出来ない。

Parent.vue
<template
 <navigationLink>
   {{user.lastName}}
 </navigationLink>

<!-- 省略 -->
<script>
data(){
    return{
      user:{lastName:"yamada",firstName:"taro"}
    }
  }
</script>

スコープ付きスロット

親コンポーネント側から子コンポーネントのデータにアクセスしたい場合<slot> 要素に属性を指定してバインドする

currentUser.vue
<template>
<span>
  <!-- dataのusreをバインドして親コンポーネントからアクセス -->
  <slot :user="user">
    {{ user.lastName }}
  </slot>
</span>
</template>
<script>
export default {
  data(){
    return {
      user:{lastName:"tanaka",firstName:"jiro"}
    }
  }
}
</script>
Parent.vue
 <currentUser>
    <!-- slotPropsは任意の値 -->
  <template v-slot:default="slotProps">
    <!-- 子コンポーネントのuserにアクセス -->
    {{ slotProps.user.firstName }}
  </template>
 </currentUser>
<!-- 省略記法 -->
<!-- 名前なしスロットのみの場合コンポーネントタグをスロットのテンプレートとして使うことができる -->
<!-- ただし、名前付きスロットと混在は不可。複数slotがある場合は<template>を使う -->
  <currentUser v-slot="slotProps">
    {{ slotProps.user.firstName }}
  </currentUser>

<!---分割代入を使った記法 -->
 <currentUser v-slot="{ user }">
    {{ user.firstName }}
 </currentUser>

<!---分割代入はプロパティをリネームする事もできる -->
<currentUser v-slot="{ user:person }">
   {{ person.firstName }} 
</currentUser>

動的なスロット名

スロット名は動的に定義が可能。
例えばdataからスロット名を定義できる

baseLayout.vue
<div>
  <slot name="slotName"></slot>
</div>
Parent.vue
<baseLayout> 
  <template v-slot:[dynamicSlotName]>
    ...
  </template>
</baseLayout>
<!-- 省略 -->
<script>
 data(){
    return{
      dynamicSlotName:"slotName"
    }
  }
</script>

名前付きスロットの省略記法

v-slotは省略があり#で置き換えられる。
例えばv-slot:header#headerに書き換えられる
名前なしスロットで省略記法を使いたい場合はdefaultでスロット名を指定する必要がある

Parent.vue
<current-user #default="{ user }">
  {{ user.firstName }}
</current-user>

参考: https://vuejs.org/v2/guide/components-slots.html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む