信頼はずっと、挑戦はもっと。

お問い合わせ
TEL:03-3496-3888

BLOG コアテックの社員ブログ (毎週月曜~金曜更新中)

2019

6

8月

NuxtJs

テクログ

皆さんこんにちは。

本日はNuxtjsというものを少し触ってみます


結構前ですが同じくブログでVueJsを紹介しました。↓

https://core-tech.jp/blog/article196/


NuxtJsはこれに対して機能を足してSSR(サーバサイドレンダリング)

を可能にしたフレームワークのようです。

これだけSPAサイトが流行っている中ですが、クローラにちゃんと

キーワードを読ませたいよってなったらこういったSSRができるフレームワーク

を使わないといけませんね。


では早速。

Nodejsがインストール済で、NPM5.2以降が入っている前提で話をします。


私はOSはMACOS(Mojave)です。


コンソールで以下を入力します。

npx create-nuxt-app sample


初期設定コンソールがでるので適当に好みにあったものを選択します。

で、おわるとこんな感じのがでます。


 To get started:

	cd sample
	npm run dev

 To build & start for production:

	cd sample
	npm run build
	npm run start


To get startedの手順をそのまま叩くと起動します。

	cd sample
	npm run dev


で、

http://localhost:3000

にアクセス。

はいできた。


ここで終わっても面白くはないので少しだけいじって体験してみます。

作成したプロジェクトにはすでにGitまで入っているので一応登録しておきます。

同じ場所で


git add .
git commit
:wq


デザインの部分に関しては、

今回はBootsnippさんにサンプルとしてある

https://bootsnipp.com/snippets/1ea0N


を使わせてもらいます。


いじるファイルは2ファイル


★変更点

sample/nuxt.config.js

headの部分をまるっとこの形にします。


head: {
  title: 'nuxt-example',
  meta: [
    { charset: 'utf-8' },
    { name: 'viewport', content: 'width=device-width, initial-scale=1' },
    { hid: 'description', name: 'description', content: 'Nuxt.js project' }
  ],
  script: [
    { src: 'https://maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js' },
    { src: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js' }
  ],
  link: [
    { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
    { rel: 'stylesheet', id: 'bootstrap-css', href: 'https://maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css' },
    { rel: 'stylesheet', type: 'text/css', href: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css' },
  ]
},



これは、ページのヘッダなどを設定する部分で

前回同様CDNでスタイルなど引けるようにしています。


Sample/pages/index.vue

まるっと下記を貼り付けます

<template>
  <div class="container">
    <div class="messaging">
      <div class="inbox_msg">
        <div class="inbox_people">
          <div class="headind_srch">
            <div class="recent_heading">
              <h4>Recent</h4>
            </div>
            <div class="srch_bar">
              <div class="stylish-input-group">
                <input type="text" class="search-bar"  placeholder="Search" >
                <span class="input-group-addon">
                <button type="button"> <i class="fa fa-search" aria-hidden="true"></i> </button>
                </span> </div>
            </div>
          </div>
          <div class="inbox_chat">
            <div class="chat_list active_chat">
              <div class="chat_people">
                <div class="chat_img"> <img src="https://ptetutorials.com/images/user-profile.png" alt="sunil"> </div>
                <div class="chat_ib">
                  <h5>Coretec-Nuxt-Sample<span class="chat_date">Aug 6</span></h5>
                  <p>テストのためのサンプルです</p>
                </div>
              </div>
            </div>
            <div class="chat_list">
              <div class="chat_people">
                <div class="chat_img"> <img src="https://ptetutorials.com/images/user-profile.png" alt="sunil"> </div>
                <div class="chat_ib">
                  <h5>テストです<span class="chat_date">Aug 7</span></h5>
                  <p>テスト部屋2番です</p>
                </div>
              </div>
            </div>
          </div>
        </div>
        <div class="mesgs">
          <div class="msg_history">
            <div class="outgoing_msg">
              <div class="sent_msg">
                <p>最初からいれてあるサンプルの部分です</p>
                <span class="time_date"> 11:01 AM    |    Today</span> </div>
            </div>
            <div class="incoming_msg">
              <div class="incoming_msg_img"> <img src="https://ptetutorials.com/images/user-profile.png" alt="sunil"> </div>
              <div class="received_msg">
                <div class="received_withd_msg">
                  <p>最初からいれてあるサンプルの部分です
                  </p>
                  <span class="time_date"> 11:01 AM    |    Today</span></div>
              </div>
            </div>
            <div v-for='(meg, index) in talks' :key='index' >
              <div class="incoming_msg" v-if=meg.flg>
                <div class="incoming_msg_img"> <img src="https://ptetutorials.com/images/user-profile.png" alt="sunil"> </div>
                <div class="received_msg">
                  <div class="received_withd_msg">
                    <p>{{ meg.item }}</p>
                    <span class="time_date">{{ meg.timestamp }}</span></div>
                </div>
              </div>
              <div class="outgoing_msg" v-else>
                <div class="sent_msg">
                  <p>{{ meg.item }}</p>
                  <span class="time_date">{{ meg.timestamp }}</span> </div>
              </div>
            </div>
          </div>
          <form v-on:submit.prevent>
            <div class="type_msg">
              <div class="input_msg_write">
                <input type="text" class="write_msg" placeholder="メッセージをいれてね" v-model="newItem" />
                <button class="msg_send_btn" type="button"><i class="fa fa-paper-plane-o" aria-hidden="true" v-on:click="addItem"></i></button>
              </div>
            </div>
          </form>
        </div>
      </div>

    </div></div>
</template>

<script>
    export default {
        data() {
            return {
                newItem: '',
                talks: [],
                flg: false
            }
        },
        methods: {
            addItem: function(event) {
              var val = this.flg
              var todo = {
                  item: this.newItem,
                  timestamp:new Date(),
                  flg:!val
              };
              this.flg = todo.flg
              this.talks.push(todo)
            }
        }
    }
</script>

<style>
  .container {
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
  }

  .title {
    font-family: "Quicksand", "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; /* 1 */
    display: block;
    font-weight: 300;
    font-size: 100px;
    color: #35495e;
    letter-spacing: 1px;
  }

  .subtitle {
    font-weight: 300;
    font-size: 42px;
    color: #526488;
    word-spacing: 5px;
    padding-bottom: 15px;
  }

  .links {
    padding-top: 15px;
  }
  .container{max-width:1170px; margin:auto;}
  img{ max-width:100%;}
  .inbox_people {
    background: #f8f8f8 none repeat scroll 0 0;
    float: left;
    overflow: hidden;
    width: 40%; border-right:1px solid #c4c4c4;
  }
  .inbox_msg {
    border: 1px solid #c4c4c4;
    clear: both;
    overflow: hidden;
  }
  .top_spac{ margin: 20px 0 0;}


  .recent_heading {float: left; width:40%;}
  .srch_bar {
    display: inline-block;
    text-align: right;
    width: 60%; padding:
  }
  .headind_srch{ padding:10px 29px 10px 20px; overflow:hidden; border-bottom:1px solid #c4c4c4;}

  .recent_heading h4 {
    color: #05728f;
    font-size: 21px;
    margin: auto;
  }
  .srch_bar input{ border:1px solid #cdcdcd; border-width:0 0 1px 0; width:80%; padding:2px 0 4px 6px; background:none;}
  .srch_bar .input-group-addon button {
    background: rgba(0, 0, 0, 0) none repeat scroll 0 0;
    border: medium none;
    padding: 0;
    color: #707070;
    font-size: 18px;
  }
  .srch_bar .input-group-addon { margin: 0 0 0 -27px;}

  .chat_ib h5{ font-size:15px; color:#464646; margin:0 0 8px 0;}
  .chat_ib h5 span{ font-size:13px; float:right;}
  .chat_ib p{ font-size:14px; color:#989898; margin:auto}
  .chat_img {
    float: left;
    width: 11%;
  }
  .chat_ib {
    float: left;
    padding: 0 0 0 15px;
    width: 88%;
  }

  .chat_people{ overflow:hidden; clear:both;}
  .chat_list {
    border-bottom: 1px solid #c4c4c4;
    margin: 0;
    padding: 18px 16px 10px;
  }
  .inbox_chat { height: 550px; overflow-y: scroll;}

  .active_chat{ background:#ebebeb;}

  .incoming_msg_img {
    display: inline-block;
    width: 6%;
  }
  .received_msg {
    display: inline-block;
    padding: 0 0 0 10px;
    vertical-align: top;
    width: 92%;
  }
  .received_withd_msg p {
    background: #ebebeb none repeat scroll 0 0;
    border-radius: 3px;
    color: #646464;
    font-size: 14px;
    margin: 0;
    padding: 5px 10px 5px 12px;
    width: 100%;
  }
  .time_date {
    color: #747474;
    display: block;
    font-size: 12px;
    margin: 8px 0 0;
  }
  .received_withd_msg { width: 57%;}
  .mesgs {
    float: left;
    padding: 30px 15px 0 25px;
    width: 60%;
  }

  .sent_msg p {
    background: #05728f none repeat scroll 0 0;
    border-radius: 3px;
    font-size: 14px;
    margin: 0; color:#fff;
    padding: 5px 10px 5px 12px;
    width:100%;
  }
  .outgoing_msg{ overflow:hidden; margin:26px 0 26px;}
  .sent_msg {
    float: right;
    width: 46%;
  }
  .input_msg_write input {
    background: rgba(0, 0, 0, 0) none repeat scroll 0 0;
    border: medium none;
    color: #4c4c4c;
    font-size: 15px;
    min-height: 48px;
    width: 100%;
  }

  .type_msg {border-top: 1px solid #c4c4c4;position: relative;}
  .msg_send_btn {
    background: #05728f none repeat scroll 0 0;
    border: medium none;
    border-radius: 50%;
    color: #fff;
    cursor: pointer;
    font-size: 17px;
    height: 33px;
    position: absolute;
    right: 0;
    top: 11px;
    width: 33px;
  }
  .messaging { padding: 0 0 50px 0;}
  .msg_history {
    height: 516px;
    overflow-y: auto;
  }

</style>



で、何ができたかというと。

一人でチャットできるWebアプリです(笑)

初期画面こんな感じ




『メッセージをいれてね』の部分に文字を入れて右の紙飛行機ボタンを押すと1人チャット完成です。



処理部分に関して抜粋して書きます。


Index.vueのHTML部分

 <div class="mesgs">
  <div class="msg_history">
   <div class="outgoing_msg">
    <div class="sent_msg">
     <p>最初からいれてあるサンプルの部分です</p>
     <span class="time_date"> 11:01 AM  |  Today</span> </div>
   </div>
   <div class="incoming_msg">
    <div class="incoming_msg_img"> <img src="https://ptetutorials.com/images/user-profile.png" alt="sunil"> </div>
    <div class="received_msg">
     <div class="received_withd_msg">
      <p>最初からいれてあるサンプルの部分です
      </p>
      <span class="time_date"> 11:01 AM  |  Today</span></div>
    </div>
   </div>
   <div v-for='(meg, index) in talks' :key='index' >
    <div class="incoming_msg" v-if=meg.flg>
     <div class="incoming_msg_img"> <img src="https://ptetutorials.com/images/user-profile.png" alt="sunil"> </div>
     <div class="received_msg">
      <div class="received_withd_msg">
       <p>{{ meg.item }}</p>
       <span class="time_date">{{ meg.timestamp }}</span></div>
     </div>
    </div>
    <div class="outgoing_msg" v-else>
     <div class="sent_msg">
      <p>{{ meg.item }}</p>
      <span class="time_date">{{ meg.timestamp }}</span> </div>
    </div>
   </div>
  </div>
  <form v-on:submit.prevent>
   <div class="type_msg">
    <div class="input_msg_write">
     <input type="text" class="write_msg" placeholder="メッセージをいれてね" v-model="newItem" />
     <button class="msg_send_btn" type="button"><i class="fa fa-paper-plane-o" aria-hidden="true" v-on:click="addItem"></i></button>
    </div>
   </div>
  </form>
 </div>
</div>



Index.vueの処理部分


<script>
  export default {
    data() {
      return {
        newItem: '',
        talks: [],
        flg: false
      }
    },
    methods: {
      addItem: function(event) {
       var val = this.flg
       var todo = {
         item: this.newItem,
         timestamp:new Date(),
         flg:!val
       };
       this.flg = todo.flg
       this.talks.push(todo)
      }
    }
  }
</script>


buttonを押下した時にscriptのv-on:click="addItem"が発火。

v-model="newItem”の値を入れてdataの変数を書き換え再描画しています。

1メッセージごとにflgの中身を交互に切り替え自分と相手側が会話しているように表現しています。

再描画部分は<div v-for='(meg, index) in talks' :key='index' >でループで出力し、

<div class="incoming_msg" v-if=meg.flg>でHTMLを相互に切り替えています。


わりと簡単な実装でチャットツールのような表現をすることができました。

しっかりと作り込んでいけばもっと沢山のことができるかもしれませんね。


本日はざっくり概要部分だけ触れました。

それでは。


この記事を書いた人

マスオさん

新納誠一

所 属:
役員
出身地:
新潟
仕事内容:
プログラミング