20201014のvue.jsに関する記事は12件です。

【Firebase Authentication】Nuxt.jsで作成したアプリケーションにログイン機能をつける。

Nuxt.jsでのログイン実装

現在ユーザー機能が必要なアプリケーションを作成しているため,ログイン機能を実装する必要があります。
Firebase Authenticationの機能を使って登録したユーザーがログインできるかを確認します。

前提

・Firebaseが使える状態にある
・axiosがインストール済みである

ページ構成

よくあるヘッダーの右側にログイン、サインインがあるパターンを想定します。
こんな感じです。

まずはリンク先のページをpages配下に用意してあげましょう。

touch pages/login.vue

続いてヘッダーにリンクを用意してあげましょう。
Nuxtはルーティングが簡単にできるからとても便利ですね。

header.vue
<ul class="list-inline">
  <li class="list-inline-item"><n-link to="/login">Log in</n-link></li>
</ul>

loginフォームを用意する

シンプルなフォームがほしかったためこちらからお借りしました。

https://codepen.io/colorlib/pen/rxddKy

Firebase Authenticationでユーザーを用意

1.Authenticationをクリック
2.ユーザーを追加をクリック
3.メールアドレスとパスワードを入力(存在しないもので構いません)
4.ユーザーを追加をクリック

Sign-in methodの設定

1.Sign-in methodをクリック
2.メール/パスワードを有効化

plugins/firebase.jsを用意

firebaseの情報を設定します。
1.プロジェクトの概要 > 歯車をクリック > プロジェクトを設定をクリック
2.全般をスクロールする

こちらの画面をスクロールすると表示される情報ですね。

plugins/firebase.js
const config = {
  apiKey: "{{ APIKEY }}",
  authDomain: "{{ AUTHDOMAIN }}",
  databaseURL: "{{ DATABASEURL }}",
  projectId: "{{ PROJECTID }}",
  storageBucket: "{{ STORAGEBUCKET }}",
  messagingSenderId: "{{ MESSAGINGSENDERID }}",
  appId: "{{ APPID }}",
  measurementId: "{{ MESUREMENTID }}"
};

// Initialize Firebase
if (!firebase.apps.length) {
  firebase.initializeApp(config);
}

export default firebase;

storeを用意する

データを保存しておくという仕組みしか理解しておりませんので、提供いただいたコードをそのまま掲載します。

store/index.js
import firebase from '~/plugins/firebase'

// data保管庫
export const state = () => ({
  user: {
    uid: '',
    email: '',
    login: false,
  },
})

// stateの情報を取得
export const getters = {
  user: state => {
    return state.user;
  }
}

// storeの上書き以外の処理や非同期通信
export const actions = {
  login({ dispatch }, payload) {
    // メールとパスワードでログイン
    console.log('login action');
    firebase.auth().signInWithEmailAndPassword(payload.email, payload.password)
      .then(user => {
        console.log('ログイン成功!');
        this.$router.replace({ path: '/' });
        dispatch('checkLogin')
      })
      .catch((error) => {
        alert(error);
      })
  },
  loginGoogle({ dispatch }) {
    // Googleアカウントでログイン
    console.log('loginGoogle action');
    const provider = new firebase.auth.GoogleAuthProvider();
    firebase.auth().signInWithPopup(provider)
      .then(result => {
        const user = result.user;
        console.log('googleログイン成功!');

        dispatch('checkLogin');
      })
      .catch((error) => {
        alert(error);
      });
  },
  checkLogin({ commit }) {
    // ログインしているかどうかのチェックログインしていたらデータ追加
    firebase.auth().onAuthStateChanged((user) => {
      console.log(user);
      if (user) {
        console.log(user);
        commit('login', { uid: user.uid, email: user.email });
      }
    })
  },
  logout({ commit }) {
    // ログアウト
    firebase.auth().signOut()
      .then(() => {
        console.log("ログアウトしました");
        commit('logout');
      })
      .catch((error) => {
        console.log(`ログアウト時にエラーが発生しました (${error})`);
      });
  }
}

// stateの上書き(代入)
export const mutations = {
  login(state, payload) {
    state.user.uid = payload.uid;
    state.user.email = payload.email;
    state.user.login = true;
  },
  logout(state) {
    state.user.uid = '';
    state.user.email = '';
    state.user.login = false;
  }
}

ここまでで下準備が終わりました

login.vueから実処理を行うLoginMenuのコンポーネントを呼び出します

pages/login.vue
<template>
    <div>
      <h1>Log In</h1>
      <LoginMenu />
      <h3 v-if="user.login">
       ログインしました
      </h3>
      <h3 class="title" v-else>
       ログインしてください
      </h3>
    </div>
</template>

<script>
  import LoginMenu from "@/components/loginMenu.vue";
  export default {
    components: {
      LoginMenu: LoginMenu,
    },
    computed: {
        user() {
          return this.$store.getters["user"];
        },
    }
  };
</script>

components/loginMenu.vue
<template>
<div class="login-page">
  <div class="form">
    <div class="register-form" v-if="this.$route.path === '/signup'">
      <input type="text" placeholder="name"/>
      <input type="password" placeholder="password"/>
      <input type="text" placeholder="email address"/>
      <button>create</button>
      <p class="message">Already registered? <n-link to="/login">Sign In</n-link></p>
    </div>
    <div class="login-form" v-else>
      <input type="text" v-model="email" placeholder="username"/>
      <input type="password" v-model="password" placeholder="password"/>
      <button v-on:click="login">login</button>
      <p class="message">Not registered? <n-link to="/signup">Create an account</n-link></p>
    </div>
  </div>
</div>
</template>

<script>
export default {
 computed: {
   // dataのように扱える
   // dataを作る前処理が必要な際に利用
   user () {
     return this.$store.getters['user'];
   },
 },
 data () {
   return {
     email: '',
     password: '',
   }
 },
 mounted() {
   // ログインしているかどうかのチェックログインしていたらデータ追加
   this.$store.dispatch('checkLogin');
 },
 methods : {
   async login () {
      // メールとパスワードでログイン
      console.log('login action', this.email, this.password);
      this.$store.dispatch('login', {email:this.email, password:this.password});
   },
   loginGoogle() {
      // Googleアカウントでログイン
      this.$store.dispatch('loginGoogle');
   },
   logout : function() {
      // ログアウト
      this.$store.dispatch('logout');
   }
 }
}
</script>

ログイン可能か確認する

ひとまずログインを行うと右のメニューがlogoutになるか確認します。

header.vue
<template>
    <nav class="navbar navbar-light bg-light">
        <h1><n-link to="/">title</n-link></h1>
        <ul class="list-inline" v-if="user.login">
            <li class="list-inline-item"><n-link to="/logout" >Log Out</n-link></li>
        </ul>
        <ul class="list-inline" v-else>
            <li class="list-inline-item"><n-link to="/login">Log in</n-link></li>
            <li class="list-inline-item"><n-link to="/signup">Sign up</n-link></li>
       </ul>
    </nav>
</template>

ひとまず作りながら覚えていく

Nuxt.jsは以前から何度か触れていましたが複数ページにまたがる物を作るのは今回が初めてだったため
作りながら覚えていくことになります。
ひとまずstoreやstateについて早急に学んでいく必要がありますね。

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

Vue-Laravel→Heroku 実践ミニマル必要情報

私のスタイル

初めまして。翁と申します。
ミニマルで強迫観念やストレスなく、かつ最大限を提供する
"Huge Minimalism"
を提唱し、スタイルとして活動させていただいてます。
お手柔らかによろしくお願いいたします。

あくまで"より高みへ。"を意識しており
一記事執筆5分以内と制限しております。
ご理解いただけたらと思います。

少しでも痒い所に手が届くような
貢献が出来たらと思います。
lo-ske.png

デプロイまで

1.ローカルコミット

git init
git add .
git commit -m "first commit"
//ここで行うことで自動でデプロイ先が設定されます。
heroku create 

2.デプロイ

//行く先確認
>git remote -v
heroku  https://git.heroku.com/~~.git (fetch)
heroku  https://git.heroku.com/~~.git (push)
//Herokuにデプロイ
git push heroku master
//App keyを設定する。
//これをする前はアクセスしても500エラーになるはず
>php artisan --no-ansi key:generate --show

>heroku config:set APP_KEY="一つ上の結果"
//Githubへと
//originを設定
>git remote add origin https://github.com/~~/~~.git

//行く先確認
>git remote -v
heroku  https://git.heroku.com/~~.git (fetch)
heroku  https://git.heroku.com/~~.git (push)
origin  https://github.com/~~/~~.git (fetch)
origin  https://github.com/~~/~~.git (push)

//デプロイ
>git push origin master
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue-Laravel→Heroku -デプロイまで-

私のスタイル

初めまして。翁と申します。
ミニマルで強迫観念やストレスなく、かつ最大限を提供する
"Huge Minimalism"
を提唱し、スタイルとして活動させていただいてます。
お手柔らかによろしくお願いいたします。

あくまで"より高みへ。"を意識しており
一記事執筆5分以内と制限しております。ご理解いただけたらと思います。

少しでも痒い所に手が届くような貢献が出来たらと思います。
lo-ske.png

デプロイまで

1.ローカルコミット

基本ルートディレクトリでコマンドを打っていきます。
```

git init
git add .
git commit -m "first commit"
```

//ここで行うことで自動でデプロイ先が設定されます。
>heroku create 
.git/config
[remote "heroku"]
    url = https://git.heroku.com/okinaofficial.git
    fetch = +refs/heads/*:refs/remotes/heroku/*

2.デプロイ

//行く先確認
>git remote -v
heroku  https://git.heroku.com/~~.git (fetch)
heroku  https://git.heroku.com/~~.git (push)
//Herokuにデプロイ
>git push heroku master
//App keyを設定する。
//これをする前はアクセスしても500エラーになるはず
>php artisan --no-ansi key:generate --show

>heroku config:set APP_KEY="一つ上の結果"
//Githubへと
//originを設定
>git remote add origin https://github.com/~~/~~.git

//行く先確認
>git remote -v
heroku  https://git.heroku.com/~~.git (fetch)
heroku  https://git.heroku.com/~~.git (push)
origin  https://github.com/~~/~~.git (fetch)
origin  https://github.com/~~/~~.git (push)

//デプロイ
>git push origin master
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ヘッダー固定のリストコンポーネントの実装

始めに

以下のようなヘッダーを固定にした一覧を表示するコンポーネントを作った際に色々ハマったことがあるので備忘録として残したいと思います。

Oct-14-2020 17-15-46.gif

一番単純な実装

一番単純なのはheaderにposition: sticky;をつけることです。

stickyを使ったStickyListコンポーネント
<template lang="pug">
.sticky-list
  .sticky-list__header
    slot(name="header")
  .sticky-list__content
    slot(name="content")
</template>

<style lang="scss" scoped>
.sticky-list {
  position: relative;
  width: 100%;
  height: 100%;
  overflow-y: auto;

  &__header {
    position: sticky;
    top: 0;
    left: 0;
  }
}
</style>

呼び出しがわは以下のような感じでやると一番最初に表示したGIFアニメのようなものができます。

呼び出し側
<template lang="pug">
StickyList
  template(v-slot:header)
    .header
      .header__column.-item1 番号
      .header__column.-item2 項目2
      .header__column.-item3 項目3
  template(v-slot:content)
    .content
      template(v-for="index in 30")
        content__item
          .content__item__column.-item1 {{ index }}
          .content__item__column.-item2 内容2
          .content__item__column.-item3 内容3
</template>

<style lang="scss" scoped>
// 各カラム幅はmixinで設定しておく
@mixin list-width() {
  &.-item1 {
    flex: 0 0 50px;
  }

  &.-item2 {
    flex: 1 1 0;
  }

  &.-item3 {
    flex: 2 2 0;
  }
}

.header {
  display: flex;
  padding: 10px;
  background-color: #fff;
  border-bottom: solid 1px #ccc;

  &__column {
    @include list-width();
  }
}

.content {
  &__item {
    display: flex;
    padding: 10px;

    & + & {
      border-top: solid 1px #ccc;
    }

    &__column {
      @include list-width();
    }
  }
}
</style>

問題点

基本的にはこれで問題ないですが、親要素がflexを使っている場合、iOS Safariだと上手くいかない場合があるようです?

サンプルコード

サンプルコードは以下になります。CodePenではVueファイルは書けないので別な書き方になっていますが基本は同じです。

See the Pen StickyList(stickyで実装) by wintyo (@wintyo) on CodePen.

flexで書いたパターンも用意していますので、iPhoneがある方はこちらから動作を確認してみると上手く動いていないことが分かると思います。
https://codepen.io/wintyo/full/xxOwBbB

コンテンツ内だけスクロールさせる

前項のやり方では上手くいかない時があるので、愚直にコンテンツ内だけスクロールするようなコンポーネントにしてみます。
この際にコンテンツ側だけスクロールバーが出てしまうため、その幅分ヘッダーにpaddingを入れて幅を合わせます。

コンテンツ内だけスクロールさせる
<template lang="pug">
.sticky-list
  .sticky-list__header(
    :style="{ paddingRight: `${$data.scrollBarWidth}px` }"
  )
    slot(name="header")
  .sticky-list__content(
    ref="elContent"
  )
    slot(name="content")
</template>

<script>
export default Vue.extend({
  data() {
    return {
      scrollBarWidth: 0,
    };
  },
  mounted() {
    const { elContent } = this.$refs;
    // スクロールバーの幅を計算する
    this.$data.scrollBarWidth = elContent.offsetWidth - elContent.clientWidth;
  }
});
</script>

<style lang="scss" scoped>
.sticky-list {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;

  &__content {
    flex: 1 1 0;
    overflow-x: hidden;
    overflow-y: scroll;
  }
}
</style>

実行すると以下のようなGIFアニメになります。

Oct-14-2020 17-04-47.gif

サンプルコード

このやり方のサンプルコードは以下になります。

See the Pen Sticky List(paddingで実装) by wintyo (@wintyo) on CodePen.

終わりに

以上がヘッダー固定のリストコンポーネントの実装でした。基本的にはposition: stickyで済ませられるならそれにしたいですが、意外と罠がありましたので、確実にやる場合は2つ目のやり方を参考にするといいと思います。

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

vue ui (vue cli 3~) で作ったプロジェクトで eslint を無効化する

vue ui でのプロジェクト作成時に入れた eslint を無効化したくなったが、出来るようになるまで時間がかかったのでメモ。

環境
@vue/cli 4.5.7

プロジェクト内でwebpackの設定を記述している箇所が見当たらない

-> 初期状態では vue-cli の内部的な設定を利用している(?)ためファイルが存在しない
下は設定の中身を確認するコマンド

vue inspect
vue inspect > output.js  // ファイルに出力する

参考 https://cli.vuejs.org/guide/webpack.html#inspecting-the-project-s-webpack-config

eslint を無効化したい

-> vue.config.js に記載した内容がデフォルトのwebpack設定にマージされる
下の内容のファイルをプロジェクトルートに作成する

vue.config.js
module.exports = {
    chainWebpack: config => {
        config.module.rules.delete('eslint');
    }
}

参考 https://stackoverflow.com/questions/49121110/how-to-disable-eslint-on-vue-cli-3

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

(3)VueによるReactiveプログラミング その1

Vueを使って簡単なプログラムを作成して、特にリアクティブなUIの基本的な動作を確認してみたいと思います。

参考ドキュメント

リアクティブプログラミング

今までのリアクティブではないプログラミングでは、例えば、テキストの入力を受け付けて、その入力文字列を表示するには、何らかのイベント(ボタンの押下)をきっかけに、入力値の変数への格納と画面の表示を同時に変更する、というものでした。
これに対し、リアクティブなプログラミングでは、データとUIが密接に繋がっていて、プログラムの変数の値が変更されたら、画面にはその値が自動的にに表示される、というような動きをします。そのため、開発者は、プログラムで保持している値だけに注意してプログラミングすればよく、コードの量も少なくなることが期待できます。

Vue+Vuetifyのプロジェクトを作成

> vue create react01
> cd react01
> vue add vuetify

全て、Defaultを選択してプロジェクトを作成します。

src/components/HelloWorld.vue を使ってVueの動作を確認しようと思います。
最初に、HeeloWorld.vueの必要な物(<template> <v-container> <script>)だけを残して、あとは全部削除してしまいます。削除すると、下のようになります。

vscode_helloworld1.png

これで、Terminalから、

> npm run serve

でローカルのサーバを起動し、さらに、デバッガーからブラウザを起動すると、App.vueにある、上部のバー(<v-app-bar>)だけが残った状態になるはずです。

hello.png

ここで、HelloWorld.vueファイルの、<template>...</template>の部分は、主に画面のUIをHTMLベースで記述した部分になり、<script>...</script>は、処理をJavaScriptで記述する部分になっています。
全体の動きを少し説明すると、Vueのアプリケーションがブラウザに読み込まれると、まず、main.jsが動作し、その中でApp.vueが読み込まれ、次にApp.vueにある<template>中の、<HelloWorld/>で、HelloWorld.vueが呼び出される、というように動いています。

inputフィールドの作成

次は、Vuetifyにある、テキストフィールド<v-text-field>を使って、入力した内容が画面にリアルタイムに表示されるプログラムを上記の画面に追加しようと思います。

HelloWorld.vueを以下のように変更します。Visual Studio CodeのTerminalで実行しているローカルサーバはそのまま実行したままで構いません。

<template>
  <v-container>
      {{ message }}
    <v-text-field v-model="message" />
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: function () {
    return {
      message: ''
    }
  }
};
</script>

変更したファイルを保存すると、自動的に再コンパイルされ、ブラウザ情は、以下のような画面になります。

hello-react.png

ラインが表示されている入力のフィールドに文字を入力すると、それにしたがって、上部に同じ文字が表示されるのがわかると思います。

ここで、<v-text-field>のタグの中にある、v-modelとあるプロパティで指定されているのが、リアクティブに反応する変数です。この変数を、<script>dataの部分に記述することで、このmessageという変数が、Vueで管理されるようになります。
さらに、{{message}}<template><v-container>の中に記述すると、その変数の中身を表示することができるようになります。

テキストフィールドをかっこよくする

テキストフィールドは、様々なプロパティを設定することで、簡単にプロダクトレベルのUIに仕上げることができます。
<v-text-field>を以下のようにして確認します。

    <v-text-field 
      label="Input your message here."
      prepend-icon="mdi-message-text-outline"
      v-model="message" />

そうすると、テキストフィールドの前にアイコンが表示され、また、テキストフィールドにlabelに設定した文字が表示されます。入力を始めると小さなフォントでテキストフィールドの上部に表示されるのがわかるかと思います。

vuetify-input.png

アイコンは、マテリアルデザインのアイコンのリストから、検索して選ぶことができます。表示されるアイコンの名前の前に、mdi-をつけて、prepend-iconに設定するだけです。

おまけ1 nameは必要?

"HelloWorld.vue"の中で指定されているnameは、必ずしも必要ありません。nameは、Vueが必要なコンポーネントを探すときのキーになりますが、.vueファイルに記述されている場合は、自動的にファイル名がnameに設定されるためです。

おまけ2 リアクティブな動作はどうやって実装されているのか

変数に格納されているデータが変更されると、どのような仕組みを使って関連する変数が変更されたり、処理が動いたりできるのでしょうか。
それについては、Vueのガイドや、この記事が参考になると思います。

簡単に説明すると、ES5から追加された、Object.defineProperty を使って、変数の読み出しをフックして、変数の値が変更された時に実行すべき処理の依存関係を登録し、いざ変更されたときにそれらの処理を実行する、ということを行っています。

おまけ3 アロー関数

JavaScriptのfunctionの書き方は、ES6からアロー関数=>で記述することができるようになっています。単純に全体として短くなりますし、returnを省略できたり、条件によってかっこや波括弧を省略できたりするので、すっきり書くことができます。ただ、functionで宣言された関数と、アロー関数の中とでは、thisの参照の仕様が変わっているので注意が必要です。thisの参照については、こちらの記事こちらの記事が参考になると思います。

参考までに、functionキーワードを使って書くと

export default {
  name: "HelloWorld",
  data: function () {
    return {
      message: ''
    }
  }
};

ですが、アロー関数を使って以下のように書くこともできます。

export default {
  name: "HelloWorld",
  data: () => ({
    message: ''
  })
};
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

(2)Vue + Vuetify をVisual Studio Codeで実行・デバッグ

Vue, Vuetifyがインストールされていない場合は、前の記事(Vue + Vuetifyでローカル開発環境をセットアップ)を参照しながら、Node.js, Vue, Vue CLI, Vuetifyのインストールをしてください。
この記事中のスクリーンショットはMacOSのものですが、Visual Studio CodeのTerminalを使えば、操作はほぼ同じです。
以下に入る前に、Visual Studio Codeをダウンロードしインストールしておいてください。

Debug環境の設定

まず、Visual Studio Codeで、Vueのソースコードに対して、ブレークポイントを設定し、ステップ実行しながらデバッグができることを確認します。

  • Visual Studio Codeを起動し、Fileメニューから"New Window"を選択してWorkspaceを作る。
  • Welcomeと表示されたページの、左側にある、Startの"Open Folder..."を選択するか、Fileメニューから"Add folder to workspace..."を選択し、前の記事で作成した、"test002"のフォルダーをWorkspaceに追加する。

vscode_1.png

  • Debugの設定をするために、左側のデバッグボタンを押し、"create a launch.json file"を選択。Select Environment...で"Chrome"を選択。
  • ファイルの作成場所を、workspaceに作成するかlaunch.jsonファイルを別途作成するかを聞かれる場合もあります。どちらでも構いませんが、ここでは、launch.jsonファイルを作成しました。これによって、test002/.vscode/launch.jsonファイルが作成されます。

vscode_3.png

Terminalでローカルのサーバを起動し、Debug開始

  • Terminalメニューから"New Terminal..."を選択すると、下にshellあるいは、コマンドプロンプトが表示されます。作業ディレクトリは、test002になっているはずなので、ここで、

> npm run serve

と入力すると、開発用のローカルサーバが起動します。

vscode_9.png

  • ローカルサーバが起動したことを確認して、左上の三角のボタンを押して、デバッグの開始をします。

vscode_4.png

  • Chromeが起動して、自動的に localhost:8080に接続された状態になります。
  • 停止するには、表示されているフロートメニューの停止を押します。

ステップ実行

デバッグには、ソースコード上でブレークポイントを設定し、ステップ実行が有効ですが、この環境でできるか確認してみましょう。

  • main.jsファイルを選択して、ブレークポイントを設定します。ブレークポイントは、ソースコードの頭をクリックすると設定できます。ここでは、main.js内の、"Vue.config.productionTip = false"という行の頭をクリックします。赤い印がつけば、ブレークポイントが設定できています。

vscode_6.png

  • 再度、左側のデバッグボタンを押し、左上の三角のボタンから、デバッガを起動すると、以下のように、ブレークポイントで停止した状態になることが確認できます。
  • さっきのフローティングメニューから、ステップ実行、ステップイン、実行を続ける、などを選択してデバッグを行うことができます。

vscode_7.png

  • ローカルのサーバを停止するには、Visual Studio Codeを終了するか、Terminalで、Cntl+C を入力すれば、サーバは停止します。

workspaceの作成

  • 最後に、Visual Studio Codeのworkspaceを保存します。Fileメニューから、"Save Workspace As..."を選択します。
  • test002ディレクトリに、"test002.code-workspace"として、保存します。
  • WorkspaceファイルをGitの管理から除くために、".gitignore"ファイルを選択して、最後の行に、*.code-workspaceを追加しておきます。

まとめ

この記事では、Visual Studio Codeから、ローカルでサーバを起動し、Vueのアプリケーションの実行、ブレークポイントの設定ができることを確認しました。

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

【Vue.js】 axios / firebaseを利用して、データのやり取り

【ゴール】

axios / firebaseを利用して、データのやり取り

画面収録 2020-10-14 11.05.15.mov.gif

【環境】

mac catarina 10.156
Vue.js v2.6.12

【実装】

firebaseのセットアップ

下記URLにアクセス、googleアカウントの登録、作成
https://firebase.google.com/

1 プロジェクト作成

スクリーンショット 2020-10-14 11.09.51.png

2 アナリティクスはOFFで構いません。

スクリーンショット 2020-10-14 11.11.08.png

3 cloud firestroeにてdatabaseの作成

スクリーンショット 2020-10-14 11.12.46.png

4 テストモードで構いません

スクリーンショット 2020-10-14 11.13.27.png

5 ロケーションはデフォルトのままで構いません

スクリーンショット 2020-10-14 11.14.22.png

6 作成完了

スクリーンショット 2020-10-14 11.15.01.png

7 左のメニューバーの設定→プロジェクトの設定→プロジェクトIDを確認

スクリーンショット 2020-10-14 11.15.30.png

axiosのインストール

※ワークスペース作成は割愛

Mac.terminal
$ npm install axios

コード

<template>内
※「@click="textSend"」でaxiosが発火(下記に詳細ページ貼ってます)
※「v-for」で繰り返し処理で表示

App.vue
<template>
  <div>
    <h2>Post,new</h2>
    <div>
      <div class="form">
        <textarea name="text" cols="100" rows="10" v-model="text"></textarea
        ><br />
        <button @click="textSend">send</button>
      </div>
    </div>
    <div v-for="post in posts" :key="post.text">
      {{ post.fields.text.stringValue }}
    </div>
  </div>
</template>

<script>内
※「import axios from "axios";」でaxioをインポート
※「created」でページ読み込みじにデータベースから情報を取得
※「posts」に取得したデータを配列として渡す
※「stringValue」はデータ型、指定してあげる
※「this.text = '';」でtextarea内を空にする

app.js
import axios from "axios";

export default {
  data() {
    return {
      text: "",
      posts: [],
    };
  },
  created() {
    axios
      .get(
        "https://firestore.googleapis.com/v1/projects/texposts/databases/(default)/documents/text"
      )
      .then((res) => {
        this.posts = res.data.documents;
        console.log(res);
      });
  },
  methods: {
    textSend() {
      axios
        .post(
          "https://firestore.googleapis.com/v1/projects/7番のプロジェクトID/databases/(default)/documents/text",
          {
            fields: {
              text: {
                stringValue: this.text,
              },
            },
          }
        )
        .then((res) => {
          console.log(res);
        });
      this.text = "";
    },
  },
};
</script>

【まとめ】

■firebaseをセットアップ
■axiosをインストールしてhttp通信を可能に
■記述。URL等のタイポに気を付ける

【オススメ記事】

■ 【Vue.js】 IF文・For文 条件分岐、繰り返し処理
https://qiita.com/tanaka-yu3/items/0ccf9a11525331b764de

■【Vue.js】クリック処理 @click
https://qiita.com/tanaka-yu3/items/e578cadf35a7bc024770

■ 【Vue.js】Vue.jsでfontawsome(Free版)を使用する方法 
https://qiita.com/tanaka-yu3/items/86d05241f72674d186f6 

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

Vue.jsの概念

Vue.jsは、インタラクティブな(双方向性の)UIを構築するためのJavaScriptのフレームワーク。
MVVMモデルの設計思考(ソフトウェアアーキテクチャ)を採用している。
コンポーネント指向のUIを設計することができる。

MVVMモデルとは?

MVVMモデルとは、プログラムの処理を以下の3つの役割に分類して開発するモデル。

  • Model
  • View
  • ViewModel

それぞれの頭文字を取ってMVVMモデルと呼ばれる。
基礎的なアーキテクチャであるMVC、及びViewとModelについてはこちらを参照

ITエンジニアホワイトボード.jpg

ViewModel

ViewModelは、ModelとViewを紐付ける接着剤の役割。

  1. Viewからリクエストを受ける
  2. ViewModelにリクエストが反映される(ViewModelのデータが書き換えられる)
  3. Modelに処理を命令
  4. 書き換えられた値をViewに反映

という処理を行う。値の変更が即時的にViewに反映されるのが特徴である。脊髄反射的なイメージ。

データバインディング

MVVMモデルを支えるのが、データバインディングである。

データバインディングとはデータをバインド(結びつける)ことで、ViewとViewModelを結びつけることである。
データバインディングは、ViewとView Modelどちらかの値が変化するたびにViewとView Model、両方の値が変更される。

これが「データが双方向性を持って反映されるUI」を構築するVue.jsの最大の特徴である。

コンポーネント指向とは?

mokei_puramo_boy.png

コンポーネント(Component)とは、部品という意味である。

コンポーネント指向とは、様々な機能をそれぞれ1つのコンポーネントとして切り出し、複数のコンポーネントを組み合わせることで、1つのサービス、アプリケーション、WEBサイトなどを作り上げる考え方である。

サービスをガンプラとすれば、コンポーネントは1つ1つのパーツである。ガンプラを組み立てるようにサービスを作り上げるのがコンポーネント指向である。

メリット

  • 設計・開発・テストなどがコンポーネント単位でできる
  • パーツを共通化することで、複数ページに渡る同じような実装を1つのコンポーネントで対応することができる

デメリット

  • 表示されるページ数に対して必要なファイル数が多くなる
  • コンポーネントが共通化されている場合、1つのコンポーネントを変更すると別のページで不具合が発生する可能性がある

参考

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

[Vue.js]自前でv-forとv-ifを同時に利用しないスライダーを実装する

この記事で書くこと

ソースの公開。

この記事を書く理由

Nuxtでアプリケーションを作成している時に、「スライダーを実装したいけど、モジュールを入れるほどじゃない、、」と思った時、いくつか記事をみたのですが、以下のように実装されているものが多かったです。

<div>
  <transition :name="slider">
    <div :key="idx" v-for="(content, idx) in contents" v-if="content.id== idx"/>
       // 中身
    </div>
  </transition>
</div>

この実装は、うまく表示されますが、一つ問題があります。それは、v-ifとv-forを同時に使用していることです。
Vue.jsのドキュメントにあるように、これは非推奨となっています。:disappointed_relieved:Vue.jsドキュメント
なので、タイトル通り、v-forとv-ifを同時に利用しないスライダーを実装してみました。

ソース

See the Pen vue-slider by RyoTa (@RyoTa0222) on CodePen.

改良の余地等あるかもしれません。コメントいただければ幸いです!:pray:

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

vue.jsでvue-routerを使ってみる

初めて投稿をすることにしました、プログラミング歴7ヶ月目のKeitaです!
現在vue.jsを主に勉強しており、その中で特に便利だなと感じた機能を紹介していきたいと考えています。

vue-router

今回紹介したいパッケージはvue-routerについてです。
vue.jsでvue-routerを使うと、仮想DOMのお陰で高速な画面遷移を行うことが可能になります。
設定も簡単に出来ますので、是非取り入れましょう。

開発環境

  • vue 2.6.11
  • vueCli 4.5.6
  • Node.js 14.4.0
  • npm 6.14.5

です。

実際のフォルダ構造。

App.vue内にHeader.vueをimportし、常に固定されている状態を作ります。またHeader.vue componentの下で画面を切り替えていきたいと思います。

src
    ├── App.vue
    ├── component
    │   ├── Content.vue
    │   ├── ContentTwo.vue
    │   ├── ContentThree.vue
    │   └── Header.vue
    ├── main.js
    └── routes.js

インストール

では実際にインストールをしてみましょう!

1.
   <script src="/path/to/vue.js"></script> 
2.
   npm install vue-router

この2つの内どちらかで設定します。1の場合は、そのままHTML内に貼り付け、2の場合は各自のterminal内でダウンロードします。

実際にコードを書いてみる

実際にvue-routerのパッケージを使えるようにするためには、src内のroutes.jsのファイルを作りmain.js内でroutes.jsをimportしmountします。

routes.jsを書く

実際に表示させたいcomponentにpathとname付けを行います。
exportを行って宣言させる事でmain.jsからimportを可能にさせます。要は、他のファイル内でも自由に使えるようにしたよって事です。

routes.js
import Content from './component/Content.vue';
import ContentTwo from './component/ContentTwo.vue';
import ContentThree from './component/ContentThree.vue';

export const routes = [
    {path:'/',component:Content,name:'content'},
    {path:'/Two',component:ContentTwo,name:'contentTwo'},
    {path:'/Three',component:ContentThree,name:'contentThree'},
]

main.jsを書く

先程作成したroutes.jsとVueRouterをimportします。routes.jsに記述しただけでは何も行われません。
そこでVue.use()とnew Vue()内でダウンロードしたパッケージを使う宣言を行います。他のパッケージを使う際にも毎回書くので必ず忘れないように書きます。(私は何回も書くのを忘れてしまった事があります。汗)

modeはhistoryにします。hashに設定するとhistoryより実行速度が早いとされていますが、使った事がないのでここではhistoryにします。

main.js
import Vue from 'vue'
import App from './App.vue'
import {routes} from './routes'
import VueRouter from 'vue-router'

Vue.config.productionTip = false
Vue.use(VueRouter)
const router = new VueRouter({
  made:'history',
  routes
})

new Vue({
  el: '#app',
  router,
  render: h => h(App)
})

これで概ね準備は完了です!ただ、肝心な画面を実際に切り替えて表示させなくてはいけませんよね。次は、router-linkとrouter-viewを使います。

router-linkとrouter-view

先ずApp.vueに移動しHeader.vueをimportします。その下にrouter-viewで表示させたい場所決めをしましょう。今回は画面の真ん中に文字をそれぞれ表示させたいと思います。

App.vue
<template>
  <div class="container">
    <Header />
    <div class="view">
      <router-view  />
    </div>
  </div>
</template>
<script>
import Header from './component/Header.vue';
export default {
  components:{
    Header,
  }
}
</script>
<style>
*{
  margin: 0;
  padding: 0;
}
.view{
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  font-size: 30px;
}
</style>

HTMLで書く場合はaタグでリンク先に飛ぶ事が出来るようになりますが、vue-routerではrouter-linkタグを使います。名前の通り、リンク先に飛ぶ役割をしています。
そして、routes.jsで作ったpathをrouter-link内でto=""を用いてそれぞれのリンクに当てはめます。

Header.vue
<template>
  <div class="row">
    <ul>
      <li><router-link to="/" exact><a href="#">Content</a></router-link></li>
      <li><router-link to="/Two" exact><a href="#">ContentTwo</a></router-link></li>
      <li><router-link to="/Three" exact><a href="#">ContentThree</a></router-link></li>
    </ul>
  </div> 
</template>
<script>
export default {
}
</script>
<style scoped>
*{
    margin: 0;
    padding: 0;
}
.row{
    width: 100%;
    height: 10vh;
}
ul{
  width: 100%;
  list-style: none;
  display: flex;
  justify-content: start;
}
li{
  display: flex;
  padding: 40px;
}
a{
  text-align: center;
  font-size: 20px;
  color: rgb(7, 7, 7);
  width: 120px;
  height: 30px;
  text-decoration: none;
  cursor: pointer; 
  margin: 0px 10px;
}
a:hover{
  color: rgb(8, 126, 204);
}
.router-link-active{
  border-bottom:2px solid rgb(10, 10, 10);
  color: rgb(5, 13, 117);
  width: 100%;
}
</style>

nameを付けている場合は、toの前に:を付ける事で任意で値を受け渡す事が出来るようになります。propsと同じ用法ですね。

Header.vue
<template>
  <div class="row">
    <ul>
      <li><router-link :to="{name: 'content'}" exact><a href="#">Content</a></router-link></li>
      <li><router-link :to="{name: 'contentTwo'}" exact><a href="#">ContentTwo</a></router-link></li>
      <li><router-link :to="{name: 'contentThree'}" exact><a href="#">ContentThree</a></router-link></li>
    </ul>
  </div> 
</template>
<script>
export default {
}
</script>
<style scoped>
*{
    margin: 0;
    padding: 0;
}
.row{
    width: 100%;
    height: 10vh;
}
ul{
  width: 100%;
  list-style: none;
  display: flex;
  justify-content: start;
}
li{
  display: flex;
  padding: 40px;
}
a{
  text-align: center;
  font-size: 20px;
  color: rgb(7, 7, 7);
  width: 120px;
  height: 30px;
  text-decoration: none;
  cursor: pointer; 
  margin: 0px 10px;
}
a:hover{
  color: rgb(8, 126, 204);
}
.router-link-active{
  border-bottom:2px solid rgb(10, 10, 10);
  color: rgb(5, 13, 117);
  width: 100%;
}
</style>

上記のHeader.vue内に書かれている様に、router-linkタグ内にexactを用いcssで色を設定すると、アクティブなリンク(今いるリンク内)を表示する事も出来ます。

router-view内では、router-linkで指定したリンク先の内容が表示されます。 

Content.vue
<template>
  <div>
      <p>Hello!</p>
  </div>
</template>

<script>
export default {

}
</script>

<style scoped>

</style>
ContentTwo.vue
<template>
  <div>
      <p>Guten morgen!</p>
  </div>
</template>

<script>
export default {

}
</script>

<style scoped>

</style>
ContentThree.vue
<template>
  <div>
      <p>Ciao!</p>
  </div>
</template>

<script>
export default {

}
</script>

<style scoped>

</style>

実際の画面

image.gif

これで基本設定は終了です!次回はparamやpushを利用してvue-routerで出来る事を増やしていきたいと思います。

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

headers に独自のキーを追加してリクエストを送る

0. 環境

nginx:1.18.0
vue.js:2.6.12

1. 概要

ALB + ec2(nginx+gunicorn+flask) の構成でデプロイし、ALBにてリクエストヘッダーを確認し、アクセス制限をかけるのがゴールでした。UI側は cloudfront + s3 でデプロイ済みで、ここからサーバーにリクエストを送ります。
リクエストを送る際に cors のエラーが発生し、解決に時間がかかってしまったので、備忘録として書いておきます。

  • 発生したエラー
Access to XMLHttpRequest at 'http://xxx.xxx.elb.amazonaws.com/yyy' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

2. 結論

nginx の設定(confファイル)にPreflight Requestに対する設定を記述する。

location / {
      # preflightに対するレスポンス指定
      if ($request_method = 'OPTIONS') {
          add_header Access-Control-Allow-Origin '*'; # corsの許可
          add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE'; # メソッドの許可
          add_header Access-Control-Allow-Headers 'Origin, Authorization, Accept, Content-Type, key'; # ここにヘッダーに追加するキーを追加する!
          add_header Access-Control-Max-Age 3600;
      ...

3. 各種設定・コードの確認

3.1 ALBの設定

ALB ではヘッダーにkey=valueが含まれている場合は、ec2に転送する設定。
スクリーンショット 2020-10-13 22.54.28.png

3.2 UI(vue.js)側のリクエストコード

ヘッダーにkeyを追加し、axios で ALB に GETリクエストを送信。

vue.js
let config = {
  headers: {
    'key': 'value'
  },
};
this.axios
  .get('http://xxx.xxx.elb.amazonaws.com/hello', config)
  .then((response) => {
    console.log(response)
...

4. ハマった点・解決方法

① CORS のリクエストはSimple RequestPreflight Requestの2種類に分けられる。Preflight Requestの場合、サーバー側で許可する設定が必要
② リクエストヘッダーに独自のヘッダーを追加する場合(今回のケースだとkey)は、サーバー側でそれを許可する設定が必要

① の解決

これについてはこのサイトが大変参考になりました。
CORS(Cross-Origin Resource Sharing)について整理してみた

以下の条件の全てに該当する場合、ブラウザはpreflightリクエストを送る必要がないと判断し、シンプルなリクエストを送信します。それ以外の場合は、preflightリクエストを送信します。

・ HTTPメソッドがGET, POST, HEADのいずれか
・ HTTPヘッダにAccept, Accept-Language, Content-Language, Content-Type以外のフィールドが含まれない
・ Content-Typeの値はapplication/x-www-form-urlencoded, multipart/form-data, text/plainのいずれか

今回のケースだとリクエストヘッダーにkeyが入っているため Preflight Request とみなされます。なおPreflight Requestのレスポンスには、アクセス許可するメソッドをレスポンスヘッダに含める必要があるようです(結論のコードAccess-Control-Allow-Methodsの部分)。

② の解決

メソッドを許可したのと同様に、ヘッダーの許可も必要になります。
こちらのサイトには次のような記述があります。

CORS セーフリストリクエストヘッダー, Accept, Accept-Language, Content-Language, Content-Type は常に許可されており、このヘッダーで列挙する必要はありません。

上記のヘッダー以外はデフォルトでは許可されていないようです。今回のケースではkeyを許可したいので追加します(結論のコードAccess-Control-Allow-Headersの部分)。

5. 感想

CORSについてあまり理解していなかったので、解決にかなり時間を費やしてしまいました。
間違っている点、補足等あればコメントを頂きたいです!

参考

CORSまとめ
なんとなく CORS がわかる...はもう終わりにする。
CORS(Cross-Origin Resource Sharing)について整理してみた
MDN web docs
(ありがとうございました..)

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