20200328のvue.jsに関する記事は11件です。

【Vue.js】XserverにVue CLIで作った超簡易ページをデプロイしてみた。

はじめに

Vue CLIを使ったポートフォリオの制作は初めてだったので、とりあえず制作に取り掛かる前にデプロイができるのかどうか試してみました。

(せっかく作ったのにデプロイできないなんてなったら悲しすぎるので。。。笑)

結論、割と簡単にできました◎

制作アプリに関して


猫本を参考に、Vue CLIでVue Routerを用いた簡易ページをとりあえず作りました(本当に簡易的です。)

ナビバーにHomeとお問い合わせボタンがあり、そこでビューを切り替えるだけです。(もはやjQueryでやれ。。。)

Vue CLIで制作したアプリのリリースには、npm run buildでまずビルドする必要があるみたいです。

distディレクトリが作成され、その中にビルドされたファイルがあります。

ところがアクセスしたところ表示されない。。。

どうやらconfig/index.jsを以下のように書き換える必要があるとのこと。


// assetsPublicPath: '/',
assetsPublicPath: '',


あとはdistフォルダをじぶんの好きな名前(URLに反映される)に変えてFTPでアップロード。

僕の場合はXserver(WordPressに利用しているドメイン)を使っているのでpublic_htmlにhomeというフォルダ名でアップロードしました。

(ドメイン名)/home(アップロードしたフォルダ名)でアクセス。

無事表示されました◎

参考サイト


vue-cliでwebアプリケーションを作って、GitHubPagesで無料で爆速でリリースした話
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.js私的備忘録まとめ

Vue.jsの私的なまとめです。

テンプレート

私的テンプレ

import XxxComponent from './components/XxxComponent'
import xxxMixins from './mixins/xxxMixins'

new Vue({
  el: '#app',
  components: {
    'xxx-component': XxxComponent
  },
  props: {
    item: {
      type: Object,
      required: true,
      default: () => {
        return {
          data: []
        }
      }
    }
  },
  data () {
    return {
      title: 'タイトル',
      item: []
    }
  },
  created () {
    //
  },
  mounted () {
    //
  },
  watch: {
    item (value, oldValue) {
      //
    },
    item: {
      handler (value, oldValue) {
        //
      },
      deep: true
    }
  },
  computed: {
    xxx (param) {
    }
  },
  methods: {
    /**
     * 説明
     * @param {string} param 内容
     * @return {string} return 内容
     */
    xxx (param) {
    }
  },
  mixins: [xxxMixins]
})

el

elはマウントする要素

el: '#app'

el: '#app'としたらHTMLのid="app"の中にVue.jsで使いたいHTMLを書く

<div id="app">
  // 中略
</div>

data

dataはvue.jsで使うデータを定義する

data () {
  return {
    title: 'タイトル',
    list: {
      data: []
    }
  }
}

マスタッシュ構文

  • HTMLの中に{{ }}でdataやcomputedを表示させる
  • $dataを付けるとdataやcomputedと区別が付きやすくなる
data () {
  return {
    text: 'タイトル'
  }
}
<h1>{{ $data.text }}</h1>

v-for

v-forで配列からHTMLにループ処理ができる

data() {
  return {
    list: [ 'りんご', 'ばなな', 'すいか' ]
  };
}
<ul>
  <li v-for="item in $data.list">{{ item }}</li>
</ul>

v-model

<input type="text" v-model="$data.text">

v-text

<p v-text="$data.text"></p>

v-if

  • v-if="!error"
  • v-if="text !== 'OK'"などの書き方もできる
<div v-if="error">
  <p>エラー</p>
</div>

v-show

<div v-show="error">
  <p>エラー</p>
</div>

v-ifとv-showの違い

  • v-showはCSSのdisplay要素が変わる
  • v-ifはHTML要素が変わる
  • 頻繁に変わる場合はv-showを使う

created

  • createdはelとDOM作成前
created () {
  // 処理
}

mounted

  • mountedはDOM作成後
mounted () {
  // 処理
}

createdとmountedの違い

watch

  • watchは変更があったら処理される
  • 第1引数が変更後の値

- 第2引数が変更前の値

watch: {
  item (value, oldValue) {
    // 処理
  }
}
  • 配列はhandlerを使う
  • deepネストされた値もみる
watch: {
  item: {
    handler (value, oldValue) {
      // 処理
    },
    deep: true
  }
}

computed

  • computedはキャッシュされる
computed: {
  xxx (param) {
    // 処理
  }
}

methods

  • methodsにはJSDocを入れる
methods: {
  /**
   * 説明
   * @param {string} param 内容
   * @return {string} return 内容
   */
  xxx (param) {
    // 処理
  }
}

mixins

  • 他のファイルからインポートできる
  • 共通部分などに使う
import xxxMixins from './mixins/xxxMixins'

new Vue({
  mixins: [xxxMixins]
})

components

<xxx-component>
import XxxComponent from './components/XxxComponent'

new Vue({
  components: {
    'xxx-component': XxxComponent
  },
})

props

  • componentsに受け渡す値を定義する
  • type:型
  • required:必須かどうか
  • default:初期値
props: {
  item: {
    type: Object,
    required: true,
    default: () => {
      return {
        data: []
      }
    }
  }
}

template

import template from './templates/XxxTemplate.html'

export default {
  template: `
    <div>
      <p>test</p>
    </div>
  `
}
  • templateは別ファイルにすることができる
  • HTMLを分けたほうがHTMLの可読性が良くなる
import template from './templates/XxxTemplate.html'

export default {
  template: template
}

$emit

  • 親コンポーネントにmethodsを動かす
action (param) {
  this.$emit('change-emit', param)
}
<xxx-component  
  @change-emit="action"
></xxx-component>

axios

  • Ajaxで使う
getData () {
  const action = '/api/'
  const params = {
    params: 'xxx'
  }
  axios.get(action, params)
    .then(response => {
      // 成功時
    }).catch(error => {
      console.error(error)
      // エラー時
    })
}

transition

  • transitionはアニメーションと使うことができる
<transition name="fade">
  <div v-show="error">
    <p>エラー</p>
  </div>
</transition>
  • CSSが必要
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to {
  opacity: 0;
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.js私的まとめ

Vue.jsの私的なまとめです。

テンプレート

私的テンプレ

import XxxComponent from './components/XxxComponent'
import xxxMixins from './mixins/xxxMixins'

new Vue({
  el: '#app',
  components: {
    'xxx-component': XxxComponent
  },
  props: {
    item: {
      type: Object,
      required: true,
      default: () => {
        return {
          data: []
        }
      }
    }
  },
  data () {
    return {
      title: 'タイトル',
      item: []
    }
  },
  created () {
    //
  },
  mounted () {
    //
  },
  watch: {
    item (value, oldValue) {
      //
    },
    item: {
      handler (value, oldValue) {
        //
      },
      deep: true
    }
  },
  computed: {
    xxx (param) {
    }
  },
  methods: {
    /**
     * 説明
     * @param {string} param 内容
     * @return {string} return 内容
     */
    xxx (param) {
    }
  },
  mixins: [xxxMixins]
})

el

elはマウントする要素

el: '#app'

el: '#app'としたらHTMLのid="app"の中にVue.jsで使いたいHTMLを書く

<div id="app">
  // 中略
</div>

data

dataはvue.jsで使うデータを定義する

data () {
  return {
    title: 'タイトル',
    list: {
      data: []
    }
  }
}

マスタッシュ構文

  • HTMLの中に{{ }}でdataやcomputedを表示させる
  • $dataを付けるとdataやcomputedと区別が付きやすくなる
data () {
  return {
    text: 'タイトル'
  }
}
<h1>{{ $data.text }}</h1>

v-for

v-forで配列からHTMLにループ処理ができる

data() {
  return {
    list: [ 'りんご', 'ばなな', 'すいか' ]
  };
}
<ul>
  <li v-for="item in $data.list">{{ item }}</li>
</ul>

v-model

<input type="text" v-model="$data.text">

v-text

<p v-text="$data.text"></p>

v-if

  • v-if="!error"
  • v-if="text !== 'OK'"などの書き方もできる
<div v-if="error">
  <p>エラー</p>
</div>

v-show

<div v-show="error">
  <p>エラー</p>
</div>

v-ifとv-showの違い

  • v-showはCSSのdisplay要素が変わる
  • v-ifはHTML要素が変わる
  • 頻繁に変わる場合はv-showを使う

created

  • createdはelとDOM作成前
created () {
  // 処理
}

mounted

  • mountedはDOM作成後
mounted () {
  // 処理
}

createdとmountedの違い

watch

  • watchは変更があったら処理される
  • 第1引数が変更後の値

- 第2引数が変更前の値

watch: {
  item (value, oldValue) {
    // 処理
  }
}
  • 配列はhandlerを使う
  • deepネストされた値もみる
watch: {
  item: {
    handler (value, oldValue) {
      // 処理
    },
    deep: true
  }
}

computed

  • computedはキャッシュされる
computed: {
  xxx (param) {
    // 処理
  }
}

methods

  • methodsにはJSDocを入れる
methods: {
  /**
   * 説明
   * @param {string} param 内容
   * @return {string} return 内容
   */
  xxx (param) {
    // 処理
  }
}

mixins

  • 他のファイルからインポートできる
  • 共通部分などに使う
import xxxMixins from './mixins/xxxMixins'

new Vue({
  mixins: [xxxMixins]
})

components

<xxx-component>
import XxxComponent from './components/XxxComponent'

new Vue({
  components: {
    'xxx-component': XxxComponent
  },
})

props

  • componentsに受け渡す値を定義する
  • type:型
  • required:必須かどうか
  • default:初期値
props: {
  item: {
    type: Object,
    required: true,
    default: () => {
      return {
        data: []
      }
    }
  }
}

template

import template from './templates/XxxTemplate.html'

export default {
  template: `
    <div>
      <p>test</p>
    </div>
  `
}
  • templateは別ファイルにすることができる
  • HTMLを分けたほうがHTMLの可読性が良くなる
import template from './templates/XxxTemplate.html'

export default {
  template: template
}

$emit

  • 親コンポーネントにmethodsを動かす
action (param) {
  this.$emit('change-emit', param)
}
<xxx-component  
  @change-emit="action"
></xxx-component>

axios

  • Ajaxで使う
getData () {
  const action = '/api/'
  const params = {
    params: 'xxx'
  }
  axios.get(action, params)
    .then(response => {
      // 成功時
    }).catch(error => {
      console.error(error)
      // エラー時
    })
}

transition

  • transitionはアニメーションと使うことができる
<transition name="fade">
  <div v-show="error">
    <p>エラー</p>
  </div>
</transition>
  • CSSが必要
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to {
  opacity: 0;
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue.js】猫本を参考に基本的なところをまとめてみた。

はじめに

2か月程前、Vue.jsに関して以下の本を用いて学習を始めました。

https://www.amazon.co.jp/%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E5%AD%A6%E3%81%B6-Vue-js-mio/dp/4863542453/ref=asc_df_4863542453/?tag=jpgo-22&linkCode=df0&hvadid=295706574430&hvpos=&hvnetw=g&hvrand=10968923051787403043&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1028851&hvtargid=pla-524581061219&psc=1&th=1&psc=1

2週間ほど勉強して、少しだけアレンジして作成したToDoリストが以下になります。(Bootstrapでデザインして、状態ボタンを1つ追加しただけだけど)

https://chobimusic.com/vue_nekotodo_arrange/

その後、Laravelと組み合わせたポートフォリオ作成を目指して、Laravelの勉強に専念。

やっとこさ最近LaravelとVueの連携について理解できてきたので、とりあえずVue.jsで新しいポートフォリオのフロントサイドを作り始めようと思ったのですが。。。

手が一切動かない。全然覚えてない。悲しい。。。泣 

2週間程度勉強したのですが、1か月経ち、気づけば頭からすっぽり抜けてしまっていました。。。(記憶力なんてこんなもん)

ってことで改めて復習がてらVue.jsの基本を記事にまとめてみました。(今後の備忘録も兼ねて)

※WordPressで体裁を整えたものをコピペしたところ、テーブルの形が崩れてしまいました。。。もし当記事が気になりましたら、以下よりご覧いただけますと幸いです。。。

https://chobimusic.com/vuejs_nekobook_summary/

Vue.jsの表示

まずはVue.jsでHello worldしてみる。

index.html



<div id="app">
  <p>{{ message }}</p>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script src="main.js"></script>

appの内側にテンプレートを書き込んでいく。

インターネットに接続できる環境であれば、Vue.jsのインストールにCDNが利用可能。

マスタッシュ記法を用いて{{}}内にプロパティ名を記述するとその値が描画される。

main.js



var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello world'
  }
})


コンストラクタ(クラスのインスタンス生成時に実行されるメソッド)関数Vueを使ってルートとなるVueインスタンスを作成。

data内のデータをテンプレート側に送っている。変数化するとコンソールからもアクセスできるが必須ではない。

実際の描画


<p>hello</p>

基本機能(ディレクティブ/組み込みコンポーネント)


v-bind


クラス、スタイル、属性などタグ内のバインドに使用。※Mustache{{}}はテキストコンテンツ特有の記法のため、タグ内で使用することができない。
<input type="text" v-bind:value="message">

省略パターン
<input type="text" :value="message">

v-for


リストデータを用いて要素を繰り返し描画する際に、繰り返したいタグに対して使用。

v-on


「クリックしたとき」「要素が変わったとき」などDOMイベントのハンドリング(イベント)を受け取り、処理を行う際に使用。

※猫本では、イベントに紐づける処理の内容を「イベントハンドラ」、イベントハンドラをイベントと紐づけることを「ハンドル」と呼んでます。

<button v-on:click="handleClick">クリック</button> <!--handleClickはコンポーネントのmethodsオプションに定義-->

省略形「@」
<button @click="handleClick">クリック</button>

 

v-model


データとフォームの入力項目をバインド(同期)する際に使用(双方向データバインディング)。

下記でフォームの文字を編集すると、同期して画面のメッセージも更新される。


<div id="app">
  <input v-model="message">
  <p>{{ message }}</p>
</div>



var app = new Vue({
  el: '#app',
  data: {
    message: 'hello'
  }
})



v-if


プロパティがTrueの時だけ条件分岐でテンプレートを描画したい際に使用。条件を満たさなかった際はコメント化。似たディレクティブにv-showがあり、こちらはstyle="display: none;"のスタイルが付与されて描画。

<templete>タグを使うと複数の要素をグループ化できる。

<templete v-if="ok">
  <h1>タイトル</h1>
  <p>コンテンツ</p>
</templete>

また、v-else-if、v-elseを組み合わせることで複数の条件を指定できる。

<transition>タグ


組み込みコンポーネント。CSSトランジションやアニメーションを容易に適用できる。

基本的なオプションの構成


Vueクラスのインスタンスの生成テンプレート








//main.js

vue = Vue.new({
  el: '#app',
  data: {
    message: "Hello Vue.js"
  },
  computed: {
    computedMessage: function(){ 
      return this.message + "!"
    },
  },
  created: {
  // アクションフック
  },
  methods: {
    myMethod: function(){
    },
  },
})



el: mountする要素


アプリケーションを紐づけるセレクタ。

data:


アプリケーションで使用するデータの登録。

computed:


算出プロパティ。関数によって算出されたデータ。
メソッド内ではthis(Vueインスタンスを指す)を付ける。
テンプレートの可読性を保つためにここに記述。

created:


ライフサイクルハック。特定のタイミングで自動的に呼び出す。呼び出したいタイミングによってメソッドは変える。
処理を割り込ませる仕組みのことを「フック」と呼ぶ

methods:


アプリケーションで使用するメソッド。
コードを管理しやすくするために処理を分けたり、イベントハンドラなど細かな実装を担当する。

コンポーネント


機能をもつUI部品ごとにテンプレートとJavaScriptを1つのセットにして、ほかのUI部品とは切り離した開発、管理をできるようにする仕組み。設計図。再利用が容易になる。

※UI(User Interface)とは、ユーザーがPCとやり取りをする際の入力や表示方法などの仕組み。

index.html














<h1>Vue.js</h1>
<div id="app">
  <hello />
</div>
<script src="https://unpkg.com/vue"></script>
<script>
Vue.component('hello',
{
  template: '<p>Hello!</p>'
})
var app = new Vue({
  el: '#app',
});
</script>


コンポーネントの定義


Vue.component(名前,{設定情報});

コンポーネントの出力


<コンポーネント名 />

 



<h1>Vue.js</h1>
<div id="app">
  <mycomponent />
</div>
<script src="https://unpkg.com/vue"></script>
<script>
var component = {
  template:'<p>localcomponent</p>'
}
new Vue({
  el: '#app',
  components: {
    'mycomponent':component
  }
});
</script>


ローカルコンポーネントの登録


Vueオブジェクトの「components」プロパティに登録すると、そのコンポーネントのスコープ内だけで使用するように制限できる。

components:{'コンポーネントタグ':コンポーネント名}

※Vue.componentsはグローバルコンポーネント

親子間のコンポーネントデータフローは、「props(親から子)」と「カスタムイベント$emit(子から親)」を使用する。


 

拡張フレームワークには「Nuxt.js」や「VuePress」がある。

「Vuex」や「Vue Router」といった拡張ライブラリを導入することで効率よく目的に応じたスケールアップも可能。

また、UIコンポーネントサイトとしては「Element」や「Onsen UI」がある。

用語


ディレクティブ


テンプレートとロジックを関連付ける機能。テンプレート内で「v-if」など独自の属性で記述する。オプションで引数や修飾子を扱うことも可能。

マウント(mount)


配置する要素とアプリケーションを紐づけること。

データバインディング


データと描画を同期させる仕組みのこと(JavaScriptのデータとそれを使用する場所を紐づけ、データに変化があれば自動的にDOMを更新する)。リアクティブシステムによって実現している機能の1つ。

DOM(Document Object Model)


JavaScriptでhtmlの要素を操作するための仕組みのこと。(ファイルの特定の部分に目印を付けて「この部分」に「こういう事をしたい」という処理を可能にするための取り決め。)

オプション


Vueインスタンスの中で使用するデータやメソッドを定義する場所。

今回まとめで割愛したこと


テンプレート制御ディレクティブ(v-preやv-htmlなど)

各ディレクティブの修飾子

スクロールイベントの取得(スムーススクロール) P114

算出プロパティ詳細(ゲッターとセッター、キャッシュ機能、watchオプション)

コンポーネントの親子間のデータフロー P154

トランジション P194

Vue CLI P216

Vuex P252

Vue Router P282

予備知識


jQueryとの併用


Vue.jsを使用すると、jQuery(DOM操作系ライブラリ)を併用する機会は減る。マウントした要素内のDOMを直接操作しても仮想DOMは更新されず、データが変わらないため。

DOMを直接参照したい際は、$elや$refsなどカスタムディレクティブを使用する。

所感


復習してみて、今回割愛した各ディレクティブの修飾子がかなり重要な役割を果たす上に、数が多いので把握するのが大変だなと感じた。まずはポートフォリオにトランジションを用いたテキストアニメーションを実装しながら学んでいこうかな。

Vue RouterでSPAも憧れるけどVue CLIの導入が必須っぽいので、まずはVue CLI導入せずにできるところからポートフォリオ制作に活かしつつ、勉強していこうと思います。

参考サイト


猫本公式サポートページ

猫本ソースコードgithub

JavaScript初心者でもすぐわかる!DOMとは何か?

Vue.js童貞がネコ本読んで得たもの①

今後活用したいチュートリアルなど


Vue.js/Vuexを使ってTrello風アプリを作成しよう!

Vue CLI活用

Vue.js & FirebaseでTwitterライクなSNSアプリを作ってみよう!

Vue CLI活用 (Vue Routerアリ、Vuexは使用しない)

Nuxt.js & Contentfulでハイスペックなポートフォリオサイトを超簡単に公開しよう!【JAMstack】

 

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

Vue.jsでTypeScriptを使う(with vue-property-decorator)

Vue.jsのscript内に型定義有りのコードを書きたい

通常のJSで書いていくのは辛いので、vue-property-decoratorを利用してTypeScriptで開発していきます。
対象のプロジェクトにはあらかじめTypeScriptがインストールされているものとします。1

インストール

$ npm install --save vue-property-decorator

基本

Component

<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'

@Component
export default class MyComponent extends Vue {
}
</script>

これはJavaScriptで以下のように書いたものと同じです。

<script>
export default {
  name: 'MyComponent'
}
</script>

Vue.jsとTypeScriptでコンポーネントのロジック部分を書いていく際はvue-property-decoratorというパッケージを利用します。
nameは明示的に宣言することもできますが、クラス名として宣言することで省略可能です。

Data

コンポーネント内のdataは、クラスのメンバ変数として宣言します。
比較のために、JavaScriptで書くケースも載せておきます。

// TypeScript
@Component
export default class MyComponent extends Vue {
  private msg = 'サンプルメッセージ'
  private users: Array<string> = [
    '山田',
    '田中'
  ]
}

// JavaScript
export default {
  data() {
    return {
      msg = 'サンプルメッセージ',
      users: [
        '山田',
        '田中'
      ]
    }
  }
}

Computed

TypeScriptではcomputedはプレフィックスgetをつけて記述します。
戻り値として指定した型とreturnで返す値の型は一致させる必要があります。

// TypeScript
export default class MyComponent extends Vue {
  get profile(): string {
    return `Hi, My name is ${this.name} and I am ${this.age} years old!`
  }
}

// JavaScript
export default {
  computed: {
    profile() {
      return `Hi, My name is ${this.name} and I am ${this.age} years old!`
    }
  }
}

Props

vue-property-decoratorから{ Prop }をインポートし、コンポーネント内に記述します。
JavaScriptのPropsの受け渡しと同様に、TypeやRequired等の属性を指定できます。

// TypeScript
import { Component, Vue, Prop } from 'vue-property-decorator'
@Component
export default class MyComponent extends Vue {
  @Prop() message: string
  @Prop({ default: '山田' }) name: string
  @Prop({ required: true }) age: number
  @Prop({ type: String, required: false, default: 'Nagoya' }) address: string 
}

// JavaScript
export default {
  props: {
    message,
    name: {
      default: '山田'
    },
    age: {
      required: true
    },
    address: {
      type: String,
      required: false,
      default: 'Nagoya'
    }
  }
}

Methods

// TypeScript
import { Component, Vue } from 'vue-property-decorator'
@Component
@Component
export default class MyComponent extends Vue {
  public incrementAge(): void {
    this.age++
  }
  public sum(num1: number, num2: number): number {
    return num1 + num2
  }
}

// JavaScript
export default {
  methods: {
    incrementAge() {
      this.age++
    },
    sum(num1, num2) {
      return num1 + num2
    }
  }
}

Watch

@Watchを宣言して以下のように書きます。

// TypeScript
import { Vue, Component, Watch } from 'vue-property-decorator'
@Component
export default class MyComponent extends Vue {
  private message: string
  private age: number

  @Watch('message')
  changedMessage() {
    this.message = 'The message has been changed.'
  }
  @Watch('age')
  changedAge(newVal: number, oldVal: number) {
    console.log(`new: ${newVal}, old: ${oldVal}`)
  }
}

// JavaScript
watch: {
  message() {
    this.message = 'The message has been changed.'
  },
  age(newVal, oldVal) {
    console.log(`new: ${newVal}, old: ${oldVal}`)
  }
}

おわりに

今回はVue.jsとTypeScriptでdecoratorを使用したComponent, Data, Props, Methods, Watchの書き方を説明しました。
他にも方法があるようなので、また勉強して記事を書こうと思います。
最後まで読んでいただき、ありがとうございました!

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

Vue.jsでDRF製APIにデータを送信する

以下の記事で作成したAPIに対して、今度はPOSTでデータを送信、データベースに登録したい。
JsfiddleのVue.jsからDRFで作成したapiにアクセスしたい

環境

book/models.py
from django.db import models
import uuid
from django.utils import timezone

# Create your models here.
class Book(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    title = models.CharField(verbose_name='タイトル', max_length=50)
    price = models.IntegerField(verbose_name='価格')
    created_at = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return self.title

また、Vue.jsはjsfiddle上に記載しています。

登録したいデータ

Bookテーブルに新規のデータとして、titleフィールドとpriceフィールドを登録したいです。
idとcreated_atは自動で追加されるのでスルーでOK。

Vue.jsを書いていく

html
<div id="app">
  <div>
    <h1>GET</h1>
    <p>タイトル : {{ results[1].title }}</p><hr>
  </div>

  <div>
    <h1>POST</h1>
    <h2>タイトル : {{ title }}</h2>
    <h2>¥{{ price }}</h2>
    <input v-model='title'>
    <input v-model='price'>
    <button v-on:click='postBook'>送信</button>
  </div>
</div>

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
javascript
new Vue({
  el: '#app',
  data: {
    results: [],
    title: '',
    price: '',
  },
  methods:{
    postBook: function(){
        console.log('Hello')
      axios.post('http://127.0.0.1:8000/apiv1/book/', 
      { title : this.title , price : this.price })
    }
  },
  mounted() {
    axios.get('http://127.0.0.1:8000/apiv1/book/')
    .then(response => {this.results = response.data})
 },
})

inputタグでv-modelディレクティブを使い、titleprice設定。
Vueインスタンスに同じ名前のdataオブジェクトを定義し、中身は空にしておきます。

methodsにpostBookを登録。buttonタグにv-onディレクティブを使い、登録します。

postBookメソッドでは、axios.post('一覧画面のエンドポイント', { フィールド名:データ, フィールド名:データ})とし、フィールドとそれに対するデータをPOSTしている。

ここまでで以下とおり。
スクリーンショット 2020-03-28 15.26.17.png

送信する

スクリーンショット 2020-03-28 15.46.41.png

送信を押すと...

スクリーンショット 2020-03-28 15.48.11.png

追加されてます。

数字にカンマをつける

値段を表示する際にカンマをつけたい場合は、Vueインスタンス内にfilter作り、適用させたいテンプレートのマスタッシュにパイプ=|でfilterを適用させます。

vueインスタンス
  filters: {
    comma(value) {
      if (!value) return ''
      value = value.toString()
      return value.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,')
 }
 }
html
<h2>¥{{ price | comma }}</h2>

スクリーンショット 2020-03-28 16.00.46.png

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

Vue routerについて調べたこと

vue routerについて

  • ルーター対応アプリで、ユーザーナビゲーションを有効にするためのコンポーネント
  • ターゲットの場所は、toプロップで指定する
<router-link to="/foo">Go to Foo</router-link>

使用するコンポーネント

Vue Routerでは、二つのコンポーネントを使う
1. router-link・・・リンクを作成するためのもの
2. router-view・・・それぞれのリンク先に基づいた内容を表示するためのもの
3. router-viewが、/だったら、routervieの中身がHome.vueになり、/Usersであれば、Users.vueになる
4. URLの内容によって、router-viewの中身が変わる、動的コンポーネントのようなもの a

使用するに当たって設定すべき事項

  • Vue.use()とすることでプラグイン(router)を使用できるようにする (Vue.jsが公式で提供してるプラグインを使うためのもの)
router.js
 import Router from "vue-router";
Vue.use(Router)
  • 表示させたいページを作る(HomeとUsersの2ページ作ってみます)
Home.vue
<template>
 <div>
   <h3>Home</h3>
 </div>
</template>
Users.vue
<template>
 <div>
   <h3>Users</h3>
 </div>
</template>
  • 表示させたいページへのルートをかく
    • このURLの場合は、このコンポーネントを表示する、というもの
    • URLとコンポーネントをマッピングする作業
    • routesは配列になっててその中はオブジェクトでかける
router.js
 new Router({
    routes:[{path: '/', component: 'Home'}, {path: '/users.vue', component: 'Users'}]
  })
  • 最初のページをHomeにするが、作成したHome.vueをインポートさせる必要がある
router.js
import Home from './Home.vue';
  • new Routerをexport させる
router.js
export default new Router({
    routes:[{path: '/', component: 'Home'}, {path: '/users.vue', component: 'Users'}]
  })

  • routerの中身をvue.jsに適用させる
  • main.jsの中で、ルーターの中身をVue.jsに適用させる
    • routerの中身は、router.jsの中で、export defaultしてる部分
  • new Vue のなかでrouterを登録する
    • (router.jsで書いた)Vue.useとかくことで、使用できるようになる
main.js
//⬇︎ここ
import router from './router.js';

new Vue ({
//⬇︎ここ
 router: router,
 render:h =>(App)
}).$mount('#app');

ここまで書いても、そのままURLにHomeやUsersと書いても、App.vueが表示されてしまう
ので、どうするかというと、、

App.vue
<template>
 <div>
<!-- 動的コンポーネント的な動きをする -->
  <router-view></router-view>
 </div>
</template>

その上で、urlにUsersなどと入力すると、Usersページを表示することができる
つまり、URLの内容によって、<router-view>の表示するものが変わってくる!ということです

ちなみに。。 

  • そのままでは、URLに#がついて、それ以降にUserと入力すると、 の部分にUsersのコンポーネントが表示されるが、この#を表示したくない場合は、 router.jsの部分に、mode:'history'と書くことで、#が消えた状態でURLを表示することができる
  • しかし、毎回index.htmlを返す、という処理を書いておかないとerrorがでる
router.js
Vue.use(Router);
export default new Router({
//⬇︎こんな感じ
 mode:'history',
 routes:[{path: '/', component: 'Home'}, {path: '/users.vue', component: 'Users'}]
  })
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JsfiddleのVue.jsからDRFで作成したapiにアクセスしたい

経緯

Vue.jsのプロジェクトをWeb上で手軽に作ることができるjsfiddleで、Django Rest Framework(以下DRF)で作成したapiにアクセスしたいと思い、試しました。

本記事に書くこと

  1. DRFにおけるシンプルなAPIの作成と、シンプルなVue.jsプロジェクトの作成。
  2. Vue.jsからDRFのapiにアクセスする方法と、その際の留意点。

手順

  1. DRFでapiを作成する
  2. Vue.jsからDRFで作成したapiにアクセスする

1. DRFでapiを作成する

環境を作る
mkfir simple_drf
cd simple_drf
python3 -m vena venv
source venv/bin/activate

pip install django
pip install djangorestframework

django-admin startproject config.

-- モデル用のbook API作成用のapiv1 --
python manage.py startapp book
python manage.py startapp apiv1
book/models.py
from django.db import models
import uuid
from django.utils import timezone

# Create your models here.
class Book(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    title = models.CharField(verbose_name='タイトル', max_length=50)
    price = models.IntegerField(verbose_name='価格')
    created_at = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return self.title
book/admin,py
from django.contrib import admin

# Register your models here.
from .models import Book


class BookModelAdmin(admin.ModelAdmin):  
    list_display = ('title', 'price', 'id', 'created_at')  
    ordering = ('-created_at',)  
    readonly_fields = ('id', 'created_at')  

admin.site.register(Book, BookModelAdmin) 
apiv1/serializers.py
from rest_framework import serializers  
from book.models import Book  

class BookSerializer(serializers.ModelSerializer):  
    class Meta:  
        model = Book  
        fields = ['id', 'title', 'price'] 
apiv1/views.py
from rest_framework import viewsets  
from rest_framework.permissions import IsAuthenticatedOrReadOnly  
from book.models import Book  
from .serializers import BookSerializer  

class BookViewSet(viewsets.ModelViewSet):  
    queryset = Book.objects.all()  
    serializer_class = BookSerializer 
apiv1/urls.py
from django.urls import path, include
from rest_framework import routers
from apiv1 import views

router = routers.DefaultRouter()
router.register('book', views.BookViewSet)

app_name = 'apiv1'
urlpatterns = [
    path('', include(router.urls))
]
config/urls,py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('apiv1/', include('apiv1.urls')),
]

管理画面で適当に本を追加しました
スクリーンショット 2020-03-28 14.24.55.png

2. Vue.jsからDRFで作成したapiにアクセスする

jsfiddleにアクセスし、各フィールド(html, css, javascript)に以下の通り記載。

HTML
<div id="app">
  {{ results }} 
  <hr>
  {{ results.id }} 
  <hr>
  {{ results.title }} 
  <hr>
  {{ results.price }} 
  <hr>
</div>

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

axiosをcdnで使えるようにしておく

CSSは適当に
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}
Vue
new Vue({
  el: '#app',
  data: {
    results: []
  },
  mounted() {
    axios.get('http://127.0.0.1:8000/apiv1/book/d5da82ff-8f63-4718-9ddb-e989832170d1/')
    .then(response => {this.results = response.data})
 }
 },
)

ライフサイクルフックのmountedでapiを使います。
axiosのgetメソッドに、DRFで作った記事のエンドポイントを指定。レスポンスのデータをresultsリストに格納します。
HTMLのMustache構文で{{ results }}などとしているため、getしてきた結果が表示されるはずですが...

スクリーンショット 2020-03-28 14.07.25.png

表示されへん

エラー

コンソール
fiddle.jshell.net/takuto/4vjsdpag/64/show/:1 Access to XMLHttpRequest at
'http://127.0.0.1:8000/apiv1/book/d5da82ff-8f63-4718-9ddb-e989832170d1/'
from origin 'https://fiddle.jshell.net' has been blocked by CORS policy: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.

Failed to load resource: net::ERR_FAILED

表示されません。コンソールを見ると上記の通りエラーが。
origin 'https://fiddle.jshell.net' has been blocked by CORS policy
https://fiddle.jshell.netがCORSポリシーによってブロックされたと言ってます。

原因は?

同一オリジンポリシーです。
詳しく:https://developer.mozilla.org/ja/docs/Web/Security/Same-origin_policy

セキュリティの観点から、異なるオリジン同士でリソースをやり取りすることを防ぐものです。
オリジンは、スキーム、ポート、ホストの3つの組み合わせのこと。
これらが一致していない場合は、同一オリジンとは言えません。

オリジンとは:https://www.atmarkit.co.jp/ait/articles/1311/26/news007.html

異なりオリジンへのアクセスを許可するためには、CORSという機能を使います。HTTPヘッダに設定を加える必要があります。

今回エラーが起きているのは、DRFで作成したAPIのオリジンと、Jsfiddleのオリジンが異なるためです。

解決するために...

DRFでdjango-cors-headersを使えば、CORSを設定することができます。

DRFにdjango-cors-headersを入れる

https://github.com/adamchainz/django-cors-headers

インストール
$ pip install django-cors-headers
DRFのsettings.pyに追記
settings.py
INSTALLED_APPS = [
    ...
    'corsheaders',
    ...

MIDDLEWARE = [
    ...
    'corsheaders.middleware.CorsMiddleware',
    ...
]
CORS_ORIGIN_ALLOW_ALL か CORS_ORIGIN_WHITELISTを設定する
settings.py
CORS_ORIGIN_ALLOW_ALL = True

CORS_ORIGIN_WHITELIST = [
    "https://fiddle.jshell.net", 
]

CORS_ORIGIN_ALLOW_ALLは、他のオリジンをすべて許可する。
CORS_ORIGIN_WHITELISTは、許可するオリジン指定する。

これでもう一度試してみる

スクリーンショット 2020-03-28 14.08.57.png

やったー。睡眠が大事という本の情報を取得できました。

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

Vue.jsでTO DOアプリを作る

はじめに

Vue.jsの基本的な使い方まとめの続きです。

チュートリアルの鉄板であるTO DOアプリを作成していきます。

テンプレートを用意する

雛形となるHTMLとJSを作成します。

todoディレクトリを作成して、その中にindex.htmlindex.jsを作成します。

todo/index.html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>TO DOアプリ</title>
    </head>
    <body>
        <div id="app">
          <!-- ここにVueインスタンスを展開する -->
        </div>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.js"></script>
        <script src="./index.js"></script>
    </body>
</html>

続いてVueインスタンスを作成する。

todo/index.js
var app = new Vue({
  el: '#app'
})

入力フォームとメソッドの追加

form要素の中に入力フォームとボタンを追加する。

<div id="app">
    <h2>TODO List</h2>
    <form>
        <input type="text">
        <button>
          追加
        </button>
    </form>
</div>

続いてbutton要素にv-on:clickを設定する。

buttonがクリックされたらaddItemメソッドを呼び出す。

<button v-on:click="addItem">

VueインスタンスにaddItemメソッドを記述する。

一旦、正常に動いているか確認するため、アラートを表示させてみる。

var app = new Vue({
  el: '#app',
  // メソッド定義
  methods: {
    addItem: function(event) {
      alert()
    }
  }
})

次にbuttonをクリックした時にsubmitイベントが発動して、ページがリロードされるのを防ぐ処理をformに記述する。

preventはデフォルトの動作を停止させる。

<form v-on:submit.prevent>

TO DOリストにタスクを登録

input要素にv-modelを記述して双方向データバインディング出来るようにする。

これで、inputに入力した値がdataオプションで定義するプロパティと同期する。

<!-- v-modelを定義 -->
<input type="text" v-model="newItem">

dataオプションにnewItemと、入力した値(todoのタスク)を保存する配列todoを定義する。

var app = new Vue({
  el: '#app',
  data: {
    newItem: '', // 入力フォームと双方向データバインディング
    todos: [] // 入力したtodoを保存する配列
  },
  methods: {
    addItem: function(event) {
      alert()
    }
  }
})

さらに、入力フォームで入力した値を配列に保存できるようにaddItemメソッドを書き換える。

プロパティにはthis.プロパティ名でアクセスできる。

このthisはVueインスタンスを指す。

var app = new Vue({
  el: '#app',
  data: {
    newItem: '',
    todos: []
  },
  methods: {
    addItem: function(event) {
      var todo = {
        item: this.newItem // todoオブジェクトに入力した値を保存
      }
      this.todos.push(todo) // todoを配列に追加
    }
  }
})

TO DOリストの改善

buttonをクリックしてタスクを追加した後に、inputに文字列が残ってしまうため、文字列をクリアにする記述をする。

さらに、空の文字列を保存するのを防ぐための処理を記述する。

methods: {
    addItem: function(event) {
      // 追加
      if (this.newItem === '') return // 空の文字列の場合はここで処理を終える
      var todo = {
        item: this.newItem
      }
      this.todos.push(todo)
      // 追加
      this.newItem = '' // 入力フォームの文字列をクリア
    }

TO DOリストの表示

HTML側でリスト表示させる記述をする。

v-forディレクィブを使って繰り返し処理をする。

<div id="app">
    <h2>TODO List</h2>
    <form v-on:submit.prevent>
        <input type="text" v-model="newItem">
        <button v-on:click="addItem">
          追加
        </button>
    </form>
    <!-- 追記 -->
    <ul>
        <li v-for="todo in todos">
            {{ todo.item }}
        </li>
    </ul>
    <!-- 追記 -->
</div>

タスクの完了と未完了の実装

タスクの完了と未完了を管理するチェックボックスを設定する。

addItmeメソッドの変数todoを編集する。

チェック済みかどうか判定するisDoneを追加し、初期値をfalseに設定する。

var todo = {
  item: this.newItem,
  isDone: false // 追加
  }

次に、HTMlにチェックボックスを追加し、v-modelディレクティブにtodo.isDoneを双方向データバインディングさせる。

これで、チェックされるとisDonetrueになる。

<ul>
    <li v-for="todo in todos">
        <input type="checkbox" v-model="todo.isDone">
        <span>{{ todo.item }}</span>
    </li>
</ul>

タスクの削除を実装

登録したタスクを個別に削除するため、配列のindexを取得する。

v-for="(値, index) in 配列"で配列のindexが取れる。

続いて削除ボタンを追加し、タスクを削除するメソッドdeleteItemを定義する。

deleteItemメソッドの引数には配列のindexを持たせる。

<ul>
    <li v-for="(todo, index) in todos"> <!-- indexの取得 -->
        <input type="checkbox" v-model="todo.isDone">
        <span>{{ todo.item }}</span>
        <!-- 追加 -->
        <button v-on:click="deleteItem(index)">Delete</button> 
    </li>
</ul>

続いてdeleteItemメソッドを定義する。

配列から要素を削除するJavaScriptのspliceメソッドを使用して、登録されたタスクを削除する。

methods: {
    addItem: function(event) {
    // 〜省略〜
    },
    //追加
    deleteItem(index) {
      this.todos.splice(index, 1) // sprice(削除を始めるindex, 削除する長さ)
    }
  }

まとめ

DOMの取得やデータの更新を意識することなく書けるので、コードの見通しがスッキリする。

そして、データバインディング楽しい:v:

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

スプレットシートのデータをVue.js(SPA)で表示する方法【vue-tables-2とaxiosを利用】

スプレットシートのデータをVue.js(vue-table-2)でいい感じに表示するまでの流れの解説です。
Screen-Shot-2019-12-09-at-1.09.31-1.png

GoogleスプレッドシートをAPIサーバー化

本記事の作成にあたって参考にしたサイトのご紹介です。

(参考1)
Qiita[@ksyunnnn] | Googleスプレッドシートのデータを表示させてリッチな静的サイトを作る
スプレットシートのAPIサーバ化/Vue.jsで取得データの描画について参照(特にHTML/JS/CSSはベースにさせて頂きました。)

(参考2)
Vue.js公式ページ | axios を利用した API の使用
axiosを用いたAPIからのデータ受け取りについて参照

(参考3)
SIerだけど技術やりたいブログ | Vuejs vue-tables-2 でテーブル表示
vue-table-2のお作法について参照

【今回活用するデータ】
過去の記事でも取り扱っている会議の参加者リストを例として活用します。

スプレットシートは公開しているので、必要に応じてコピペしてご活用ください。今回扱うデータセットはこちらです。
Screen-Shot-2019-12-09-at-1.09.31-1.png

GoogleスプレッドシートをAPIサーバー化

まずはスプレットシートを用意していただいて、参考記事(Googleスプレッドシートのデータを表示させてリッチな静的サイトを作る)にならってAPIサーバー化を行ってください。

念のための補足ですが、スプレッドシートのIDは、黄色下線部の部分に該当するのでお手元のスプレットシートをご確認ください。
Screen Shot 2020-03-28 at 9.17.08.png

Vue.js(SPA)でデータを描画(HTML/JS/CSS)

Vue.jsでの表示にあってのコードは以下の通りとなります。

index.html
<meta http-equiv="content-type" charset="utf-8">

<link rel="stylesheet" href="main.css">
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

<div id="app">
  <h3 class="vue-title">厳かな会合参加者リスト</h3>
  <v-client-table :columns="columns" :data="data" :options="options">

    <a slot="画像" slot-scope="props" :href="props.row.画像" target="'_blank'">
        <img :src="props.row.画像" width="40" height="40" />
      </a>

  </v-client-table>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.8/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.js"></script>
<script src="https://rawgit.com/matfish2/vue-tables-2/master/dist/vue-tables-2.min.js"></script>
<script src="main.js"></script>
main.js
Vue.use(VueTables.ClientTable);

new Vue({
  el: '#app',
  data() {
    return {
      loading: true,
      errored: false,
      columns: [
        '画像',
        '名前',
        '出身地',
        '主な実績'
      ],
      data: [],
      options: {
        sortable: [
          'name'
        ],
        texts: {
          filterPlaceholder: 'search'
        },
        columnsDropdown: true,
        perPage: 25
      }
    }
  },
  filters: {
    currencydecimal(value) {
      return value.toFixed(2)
    }
  },
  mounted() {
    // axiousを用いてスプレットシート(APIサーバ化)から値を取得
    axios
      .get('https://script.google.com/macros/s/AKfycbz792Y12WYDaiW2U5CiUdgCj8Uu9xWIDfq6cYfyXqq5m3MFRxU/exec')
      .then(response => {
        this.data = response.data
      })
      .catch(error => {
        console.log(error)
        this.errored = true
      })
      .finally(() => this.loading = false)
  }
})
main.css
* {
  box-sizing: border-box;
  font-size: 15px;
}

#app {
  max-width: auto;
  margin: 0 auto;
  padding: 10px;
}

td {
  white-space: nowrap;
}

table {
  width: 100%;
  border-collapse: collapse;
}

thead th {
  border-bottom: 2px solid #0099e4;
  /*#d31c4a */
  color: #0099e4;
}

th,
th {
  padding: 0 8px;
  line-height: 40px;
}

thead th.id {
  width: 50px;
}

thead th.state {
  width: 100px;
}

thead th.button {
  width: 60px;
}

tbody td.button,
tbody td.state {
  text-align: center;
}

tbody tr td,
tbody tr th {
  border-bottom: 1px solid #ccc;
  transition: all 0.4s;
}

tbody tr.done td,
tbody tr.done th {
  background: #f8f8f8;
  color: #bbb;
}

tbody tr:hover td,
tbody tr:hover th {
  background: #f4fbff;
}

button {
  border: none;
  border-radius: 20px;
  line-height: 24px;
  padding: 0 8px;
  background: #0099e4;
  color: #fff;
  cursor: pointer;
}

/* columns choice button */
button.btn.btn-secondary.dropdown-toggle {
  margin-right: 10px;
}

アプリイメージ(実行結果)

最終的に、このようなアプリとして動作します。

spreadsheet_vue_spa_01.jpg

vue-tables-2のオプションを変更すれば、フィルタなどのオプションを簡単に付与することができます。冒頭にご紹介した記事(SIerだけど技術やりたいブログ | Vuejs vue-tables-2 でテーブル表示)で、大変分かりやすくデモをまとめてくださっているのでぜひ気になる方はぜひ確認してみてください。


スプレットシートのデータをVue.js(SPA)で表示する方法についてでした。この組み合わせで且つ、axiousvue-tables-2を併用している参考サイトがなかったので、冒頭ご紹介したブログを参考にさせて頂きながら組み合わせでアプリを組んでいます。

簡単にWebアプリケーションが作れるのは大変魅力的です。ちなみに社内利用に閉じた利用ですが同じ構成で作ったデータビューワアプリをFirebaseでデプロイしています。認証機能もさくっと作れるので大変ありがたいです(何より無料枠でまかなえるありがたさ)。

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

新型コロナウイルス対策サイト(石川県版)を開発した学生の話

自己紹介

こんにちは、東洋大学 情報連携学部 新4年になるものです。
iniad.jpeg

まだまだひよっこ中のひよっこなので暖かい目で見ていただけると幸いです。(どMなので厳しいのでもOK!)
最近は、何かと大変ですね。僕も春休みに入りインターンも一時休業となりました。
給料がなくて悲しいのです、、、
もし、お仕事あれば連絡ください!!

開発の経緯

避難も兼ねて地元に石川県に帰ったわけですが、あらびっくりやることがございません。
なのでずっとゴロゴロ。。。
そんな日々を2週間続けてたある日、なにやら面白い活動が、、、

東京都 新型コロナウイルス対策サイトの話ですねー。

スクリーンショット 2020-03-28 4.44.15.png

俺も作りたい!!
そう思いまして、作ることになりました。
クソな経緯でごめんなさい

まずなにから?

どうやって作ろうか、、、考えました。
ソースコードを持って来れば行けそうですね!!

https://github.com/tokyo-metropolitan-gov/covid19

実は、貢献する方法も乗せて来れているんですねー。

https://qiita.com/FPC_COMMUNITY/items/b9cc072813dc2231b2b2

じゃあ簡単じゃん!!!

実は、vueとかnuxtとかさっぱりなんですねー。
でも、とりあえず東京都の部分を全部石川県に置き換えますねー。
ogp?favicon?も初めて知ったのですが、adobeを使ってうまく石川県ようにしますねー。

割と簡単に置き換えられた

スクリーンショット 2020-03-28 4.44.23.png

なんだ!簡単じゃーん!!余裕余裕。。。。
肝心のデータがないじゃん!!
これほど準備も計画もなにも立てていないことを悔やんだことはありません。
どれどれ、石川県のコロナウイルスのデータはどこかな〜??
ちゃんとあるじゃーん!!
ポチッと、、
スクリーンショット 2020-03-28 4.44.31.png

https://www.pref.ishikawa.lg.jp/kansen/coronakennai.html

はーい!おっけー。なんらかのcsvとかexcelデータはないんだ。(悲)
それでも一応オープンデータ?!
大学で学んだことを生かして、、、

しっかりスクレイピング

割とpythonならできると思っていたので、bs4とpandasでデータを整形しますねー。
まあこんな感じで書けましたわい。(冗長なコードがあったら教えて欲しいと甘えたい)

https://github.com/Retsuki/covid19-ishikawa/blob/development/tool/scraping.py

いよいよデプロイ?

さてとどうすればあげられるのか??
私はherokuしか使ったことのないものだったので、、、
んー、悩みました。

そして見つけた一筋の光 〜netlifyとの出会い〜

netlify.png

https://tech.moyashidaisuke.com/entry/covid19-netlify
こんな簡単にできるの?!
すげー時代だなと感心しました。

よっしゃー!公開できたぜ!

スクリーンショット 2020-03-28 4.44.23.png

https://ishikawa-covid19.netlify.com/
まあまあええやん!
しかし!!!ここでもう一つの問題が、、、
これってデータの更新は手動??

いや、ちょっと待てちょっと待てお兄さん。。。
実は、インターン先でcronを使った経験があったので
すぐに察しましたよ!

さくらさんにサーバーを借りて、、、

sakuracloud.png

一瞬でしたね。
さくらさんにメールをしたら迅速に対応してくださり
多分、サーバーの費用はかからないはず!
クラウドサーバーに仕掛けます。
シェルに実行コマンドを書いて

https://github.com/Retsuki/covid19-ishikawa/blob/development/run-regularly.sh

cronで定期実行

完成しましたね!!

かかった日数

4日?
1日目:サイトを石川版に改良
2日目:データをスクレイピング
3日目:悲しいことがあって、、休んだ。
4日目:データ自動更新
5日目:石川県のコロナウイルスサイトの情報開示が変わったため、再度スクレイピングコードを修正

取り組んでみて

非常に楽しかったよ!!
ほぼほぼパクリだけど、東京都を作った人たちは本当に偉大ですよ。
全部その人たちのおかげでできましたから。
今年は「達成」が目標の僕だったので
実は、大変嬉しい日々でした。

完成物

https://ishikawa-covid19.netlify.com/

日本へ

頑張ろうとは言いません。
困っている人がいたら助ける。それで少しは平和になるんじゃないかな。
世界に平和を祈って、、、
we can do it!!!

お世話になったサイトたち

[東京都新型コロナウイルス対策サイト]
https://stopcovid19.metro.tokyo.lg.jp/
[東京都新型コロナウイルス感染症対策サイトをforkしてnetlifyでdev環境を立ち上げる手順]
https://tech.moyashidaisuke.com/entry/covid19-netlify
[新型コロナウイルス感染症の県内の患者発生状況]
https://www.pref.ishikawa.lg.jp/kansen/coronakennai.html
[さくらクラウド]
https://cloud.sakura.ad.jp/
[我が学部]
https://www.iniad.org/

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