20200707のvue.jsに関する記事は25件です。

【個人開発】爆速でWebサービスを開発した感想と裏側でやったこと

はじめに

ついにNPBが開幕しましたね!1

野球が開幕する喜びのため、Vue.js + FirebaseでWebサービスを開発しました。

ぼく将オーダー

どういうモチベーションで作ったとかっていう話はnoteで書きました2ので、この記事ではどうやってVue.js+FirebaseでWebサービスを公開にこぎ着けたかの泥臭いお話をしようと思います。

ちなみに「爆速」は釣りタイトルです。言ってみたかっただけなんやすまんな。3

お前誰よ4

  • 大学(情報系学科)→メー子(コード書かない方)→空白の期間→iOSアプリ開発→非エンジニア兼業主夫三十路おじさん
  • サーバとかフロントエンドとかは2000年初期くらいの知識
  • 直近だとPython/Djangoでアプリを作った

「このDjangoアプリ、せっかくデータ貯めてるんだからデータ切り替えたりチャート表示したりしたいな・・・」
「せや!Vue使ったろ!」
「でもよく考えたら最近のHTML/CSS/JavaScriptってよく分からんな・・・」
「地道にキャッチアップするかぁ」
ということで、だいぶ長い道のりを歩むことになったのであった。

リリースにいたる道のり

MDNのチュートリアルをやる

MDNチュートリアル

まずはここで現代のHTML/CSS/JavaScriptについてキャッチアップ(実質学びなおし)をしました。
ちなみにMDNとは、

MDN Web Docsは、ウェブ標準及びMozillaプロジェクトの開発文書のためのMozillaの公式ウェブサイトである。

です(Wikipediaより)

ただ読むだけだと眠くなるし頭に入らないので、実際にコードを写経したりちょっと変えてみたりして動作を確認していました。章末の課題もちゃんとやったり。

無料だけど網羅的に学べるのでお勧めです。はぇーCSSだけでこんなにできるんか・・・ってなりました。
並行してDjangoアプリをやってたのもあるのですが、完走まで約3か月かかっていました。みっちりこれだけやるならもっと早く終われると思います。

Vue.jsのチュートリアルをやる

Vue.jsチュートリアル

HTML/CSS/JavaScriptのキャッチアップができたので、Vue.jsの公式サイトを写経していました。
実は当初、いきなりVue.jsから入ったのですがよくわからず撤退しました。基礎大事。
こちらは1週間くらいで完走しました。

フロントエンドに疎いおじさんなので、入力したら即反応してくれるのが楽しかった(小並感)

入門書をやる

以下の2冊を読みました。

この本でもう一度お勉強しました。だいたい4日くらい。
あとは辞書的にたびたび読み返しています。

この本でVueで作ったものをFirebaseへデプロイする一連の流れを学べました。ちょいちょいFirebaseの仕様が変わっててそのままでは動かないところがありましたが、落ち着いて調べれば大丈夫です。

N予備校のプログラミング入門 Webアプリコースをやる(番外編)

ちょうど時期的にN予備校が無料開放されていたので、「プログラミング入門 Webアプリコース」を完走しました。
入門だと思ってちょっと侮っていましたが、MDNでやったことの復習以外にも仮想環境構築、Slack Bot作成、Node.jsでアプリ作成など、学びが多かったです。

想定180時間と書かれていていつ終わるか心配でしたが、知ってるところはサクサク飛ばしたりしてなんとか3週間くらいで完走できました。

ようやく開発に着手

ここまでの学習は今回リリースしたサービス用のためにやった訳ではなく、どちらかというと副産物ですね。卒業課題的な何か。
習熟のために何か自分で考えたモノを作ろうと思い、生まれました。

なにこれ?

ぼく将オーダー

野球ファンなら1年で334回5は考えるであろう「ワイならこうやって打線組むわ!」をオーダー表のような画像にするサービスです。
選手名は入力しなくてもプルダウンから選択することができます。

使った技術

  • Vue.js(Vue CLI)
  • Firebase
  • Bootstrap4

割り切った点

  • バックエンドを用意せずデータはJSONを読み込むようにした

FirebaseのRealtime Databaseがよく分からなかったので、どうせ読み込みだけだからいっか!
ということでJSONでデータを用意して読み込むようにしました。
今後困りそうな気がするので、移行に取り組みたいと思います。

  • App.vueに処理は全部書いた

規模が小さいのでひとまず全部App.vueに書きました。
こちらは現在進行形でコンポーネント化するなどリファクタリングを進めています。

  • 最低限見やすければいいやの精神

あまり見た目にはこだわらず、シンプルに並べました。
ただシンプル過ぎるので、見やすさを維持しつつ

案外難航した点

  • ファビコン作成
  • サイト自体のOGP画像作成

最後の最後まで残しました。というか2日くらいリリースが伸びた理由がこれです。デザインセンスの欠片もないので難航しましたが、やっぱ無いよりはそれっぽさが格段にあがりますね。

  • 利用規約とか説明文とか

これも最後の方まで残しておいてどこまでちゃんと書くべきかわからず結局お茶を濁した結果に。これからもサービスを世に出すなら避けては通れないと思うので熟成させていきたいです。

  • 使ってくれそうな層にリーチできていない(重要)

さらっとTwitterに流したりnote書いたりしたくらいでは全然使われません。多少閲覧してくれたっぽいですが、画像をツイートまでは導けていませんでした。

完走した感想ですが6

個人開発は十種競技みたいだな、なんて感じました。7

こんだけ小さいプロダクトでも途中で心折れそうになりましたが、私の場合ではありますがその原因の多くは実装部分ではなく、デザインとか、画像作成とか、説明文書いたりとか、宣伝の部分でした。や、実装できなくて機能削ったりもしたけどもさ。8

まぁでも全部自分でやらなきゃいけないという環境で拙いながらも全部やったので、いい経験でした。
自分はここ強い/弱いんだな、とかあーこういうのあるんだ興味出たなーとかわかるので、次学びたい事とか具体的になりますね。

また、この経験をもとに色々作っていくということを続けていきたいとおもいます。

さいごに

個人開発はいいぞ!

GitHub
note

参考

「中年の危機」ど真ん中のオッサンがWEBサービス作ってみた。
「ツイッターでつぶやけるボタン」を簡単に作成できるサービスをリリースしました【個人開発】
ぼくのかんがえたさいきょうの配色Webサービスを公開した話
Nuxt.js使って個人開発やってみた 〜時間割を円グラフで表示するサービスをリリースした話〜
Vue.jsとFirebaseでOGP画像生成系のサービスを爆速で作ろう


  1. 時候の挨拶 

  2. NPB開幕が決まったのでWebサービスを作った話  

  3. この規模で11日(40~50Hくらい?)かかってるのを爆速とはいいづらい 

  4. 青い球団に怒られそう 

  5. な阪関無 

  6. RTA界隈でよくみる激うまギャグ 

  7. 元陸上部員(跳躍系)としてはあいつらマジでおかしなことやっとる 

  8. 人によってはそもそもそんな時間取れない、とかもあるでしょう 

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

Gridsomeでブログを作成する - Building a Blog with Vue and Markdown Using Gridsome

VueとGridsomeを用いたJAMstaticなブログを作成します。以下の記事を簡単に意訳していますが、ほとんどGoogle先生頼りです:sweat_smile:
※コードは一部変更しています。

参考サイト

Building a Blog with Vue and Markdown Using Gridsome

Introducing Gridsome

GridsomeはVue.jsを利用した静的サイトジェネレーターです。開発者は高速で安全な最新のJAMstack Webサイトを簡単に構築してデプロイできます。

Gridsomeには魅力的な機能が用意されているので、最も人気のある静的サイトジェネレーターの1つとなっています。機能の一部は次のとおりです。

  • ホットリロードによるローカル開発-開発中にリアルタイムで変更を確認できます
  • Vue.jsコードの記述-軽量で親しみやすいフロントエンドフレームワーク
  • GraphQLデータレイヤー-すべてのデータの一元管理
  • 自動ページルーティング-ファイルを含むページをすばやく作成して管理します
  • プログレッシブ画像のサポート-画像の自動サイズ変更、最適化、遅延読み込み
  • 自動ページプリフェッチ-高速ブラウジングのために、ページがバックグラウンドでロードされます
  • 自動最適化コード-すぐに使用できるコード分割とアセット最適化を取得します
  • 高速静的ページ生成-静的Webホストに安全かつ高速にデプロイします
  • データソースプラグイン-一般的なヘッドレスCMS、API、Markdownファイルからデータを追加します

Prerequisites

このチュートリアルを完了するには、次の基本的な知識が必要です。

  • HTMLとCSS
  • Vue.jsとターミナルの使用方法
  • GraphQLの仕組みに関する知識があれば尚可ですが、必須ではありません。
  • Node.js(v8.3以降)とYarn

Setting Up a Gridsome Project

次のコマンドを実行して、新しいGridsomeプロジェクトを作成します。
最初にnpmまたはyarnを使用してGridsome CLIをインストールします。

$ npm install --global @gridsome/cli or
$ yarn global add @gridsome/cli

次にgridsome-blogという新しいプロジェクトを作成して実行します。

// create a new gridsome project
$ gridsome create gridsome-blog
$ cd gridsome-blog
$ gridsome develop

これらのコマンドを実行すると、ローカル開発サーバーがhttp://localhost:8080 で実行され、以下のようなサンプルページが表示されます。
202007060945.png
Gridsomeのホットリロード機能があるので、ソースファイルを変更すると、画面上にあるものが自動的に変更されるようになっています。

Building Out a Blog with Gridsome

ブログの構成要素を説明します。投稿のリストを含む単一のページがあり、各投稿にMarkdownのコンテンツがあります。これを実現するには、gridsome / source-filesystemと呼ばれるGridsomeプラグインを次のコマンドを使用してインストールします。

yarn add @gridsome/source-filesystem or 
npm install @gridsome/source-filesystem

gridsome.config.jsに構成を追記します。

gridsome.config.js
module.exports = {
  siteName: 'Gridsome Blog',
  siteDescription: 'A simple blog designed with Gridsome',
  plugins: [
    {
      use: '@gridsome/source-filesystem',
      options: {
        path: 'content/posts/**/*.md',
        typeName: 'Post',
      }
    }
  ]
}

上記の設定は、source-filesystemプラグインを設定するために必要なものです。設定するオプションは以下のとおりです。

  • Path:投稿で使用するマークダウンコンテンツの場所。
  • typeName:GraphQLタイプとテンプレート名。 src / templates内の.vueファイルは、テンプレートを持つためにtypeNameと一致する必要があります。
  • route:localhost:8080/blog/new-post のような投稿のルートです。

公式ドキュメントに記載がないので、routeのオプションは廃止になったようです。

Gridsomeは、LayoutsをページとテンプレートのWrapperとして使用します。レイアウトには、ヘッダー、フッター、サイドバーなどのコンポーネントと、ページやテンプレートからのコンテンツが挿入されるスロットコンポーネントが含まれます。

src/layouts/Default.vue
<template>
  <main class="layout" role="main">
    <slot/>
    <div class="footer">
      <p>
        Built with
        <a class="link" href="//gridsome.org">Gridsome</a>
        & Made with ❤️ by
        <a class="link" href="//twitter.com/lauragift_">Gift Egwuenu</a>
      </p>
    </div>
  </main>
</template>

<style>
body {
  font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  margin: 0;
  padding: 0;
  line-height: 1.5;
  border: 15px solid #fecd43;
  min-height: 100vh;
}
.layout {
  max-width: 760px;
  margin: 0 auto;
  padding-left: 20px;
  padding-right: 20px;
}
.footer {
  padding-top: calc(30em / 4);
  text-align: center;
  font-size: 1em;
}
.link {
  border: 2px dashed #fecd43;
  padding: 7px;
  color: #333;
  text-decoration: none;
}
</style>

上記のコードブロックは、Default.vueコンポーネントです。GitHubリポジトリで使用されているスタイルを確認してみましょう。

Creating the Page Layout

ページレイアウトは、ブログ投稿リストの表示とホームページとしても機能します。 GridsomeではPagesは通常のページと、GraphQLコレクションのリストおよびページ付けに使用されます。ブログ投稿はコレクションです。
ページのURLは、ファイルの場所と名前に基づいて生成されます。例えば、pagesフォルダ内にIndex.vueファイルを作成すると、index.htmlとなります。About.vue作成した場合も同様にabout.htmlとなり、/aboutとしてリンクが作成されます。これがPagesでのルーティングの仕組みです。
今回はすべての投稿を単一のページに表示したいだけなので、ない場合はIndex.vueファイルを作成します。

Index.vueを下記のように変更します。

src/pages/Index.vue
<template>
  <Layout>
    <header class="header">
      <h1>Gridsome Blog</h1>
      <p>A simple blog designed with Gridsome</p>
    </header>
  </Layout>
</template>


<script>
export default {
  metaInfo: {
    title: 'Hello, world!'
  }
}
</script>

<style>
.header {
  font-family: "Stylish";
  font-size: 35px;
  text-align: center;
  line-height: 20px;
  padding: 0.7em;
}
.header h2 {
  font-weight: 200;
  font-size: 35px;
}
</style>

ホームページは以下のように表示されます。
202007061025.png

これでホームページができたので、ブログ投稿のリストを作成してページに表示します。componentsフォルダ内にPostList.vueファイルを作成し、ブログの投稿のリストを表示するためのレイアウトを記述します。

components/PostList.vue
<template>
  <div class="post-list">
    <hr class="line">
    <p class="date" v-html="post.date"/>
    <h3 class="title" v-html="post.title"/>
    <p class="description" v-html="post.description"/>
    <b>{{post.timeToRead}} min read</b> &nbsp;
    <g-link :to="post.path" class="read">Read More <span class="visuallyhidden">about {{post.title}}</span></g-link>
  </div>
</template>

<script>
export default {
  props: ["post"]
};
</script>

<style>
.line {
  border: 0.5px solid #cdc8c5;
  margin: 30px 0;
}
.date {
  font-weight: 300;
}
.read {
  padding: 7px;
  color: #333;
  text-decoration: none;
  border: 2px dashed #fecd43;
}
.visuallyhidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  clip-path: inset(50%);
  border: 0;
}
.visuallyhidden:focus {
  display: inline-block;
  padding: 15px 23px 14px;
  width: auto;
  height: auto;
  clip: auto;
  color: #000000;
  background-color: #ffffff;
  clip-path: unset;
}
</style>

このファイル内に、投稿のリストを表示するためのコンテンツがあり、親コンポーネントから子コンポーネントのPostListにデータを渡すことを可能にするprops: ["post"]も追加しています。

Pagesフォルダ内のIndex.vueに戻ります。Gridsomeはすべてのデータ(この場合はGraphQL)のデータを集中管理しているので、とを使用して、ページ、テンプレート、コンポーネントにデータをフェッチします。
ここでは、Markdownで作成されたコンテンツディレクトリにあるすべての投稿をプルし、Vueコンポーネント内に表示できるように以下のような変更を加えます。

pages/Index.vue
<template>
  <Layout>
    <header class="header">
      <h1 v-html="$page.metadata.siteName" />
      <h2 v-html="$page.metadata.siteDescription" />
    </header>
    <section class="posts">
      <PostList v-for="edge in $page.allPost.edges" :key="edge.node.id" :post="edge.node" />
    </section>
  </Layout>
</template>

<script>
import PostList from "@/components/PostList";
export default {
  components: {
    PostList
  },
  metaInfo: {
    title: "A simple blog"
  }
};
</script>

<page-query>
query {
  metadata {
    siteName
    siteDescription
  }
  allPost {
    totalCount
    edges {
      node {
        id
        title
        timeToRead
        description
        date (format: "D MMMM YYYY")
        path
      }
    }
  }
}
</page-query>
・・・

Displaying the Post Layout

ここまででコンテンツフォルダからブログ投稿のリストが一覧表示することができました。
次はこれらの投稿の1つがクリックされたときに、投稿を詳細ページを表示するためのにテンプレートを作成します。
Gridsomeでは、テンプレートはGraphQLコレクションへの単一の投稿ビューを表示するために使用されます。次の内容のPost.vueファイルをtemplatesフォルダ内に追加します。

src/templates/Post.vue
<template>
  <Layout>
    <br>
    <g-link to="/" class="link">  &larr; Go Back</g-link>
    <div class="post-title">
      <h1>{{$page.post.title}}</h1>
      <p class="post-date"> {{ $page.post.date}} | {{$page.post.timeToRead}} min read</p>
    </div>
    <div class="post-content">
      <p v-html="$page.post.content" />
    </div>
  </Layout>
</template>

<page-query>
query Post ($path: String!) {
  post: post (path: $path) {
    id
    title
    content
    date (format: "D MMMM YYYY")
    timeToRead
  }
}
</page-query>

<style>
.post-title {
  text-align: center;
  font-size: 30px;
  line-height: 10px;
  padding: 2em 0;
  font-family: 'Stylish';
}
.post-date {
  font-size: 16px;
  font-weight: 400;
}
.post-content {
  font-size: 20px;
}
</style>

これで、ホームページの[read more]をクリックすると、gridsome.config.jsで構成したように、投稿のタイトルを使用してスラッグで表示された単一の投稿のコンテンツが表示されます。

サンプル記事を投稿する

ここまでは参考サイト通りに実行しましたが、サンプル記事の投稿方法が書かれていなかったので補足します。

プラグインのインストールと設定

GitHubのソースコードgridsome.config.jsは下記の通りになっています。

gridsome.config.js
module.exports = {
  siteName: 'Gridsome Blog',
  siteDescription: 'A simple blog designed with Gridsome',
  templates: {
    Post: '/blog/:title',
  },
  plugins: [
    {
      use: '@gridsome/source-filesystem',
      options: {
        path: 'content/posts/**/*.md',
        typeName: 'Post',
      }
    }
  ],
  transformers: {
    //Add markdown support to all file-system sources
    remark: {
      externalLinksTarget: '_blank',
      externalLinksRel: ['nofollow', 'noopener', 'noreferrer'],
      plugins: [
        '@gridsome/remark-prismjs'
      ]
    }
  },
}

公式ドキュメントのtransformer-remarkremark-prismjsを確認し、下記のコマンドでプラグインを追加し、上記のようにgridsome.config.jsを変更します。

$ npm install @gridsome/transformer-remark
$ npm install @gridsome/remark-prismjs

次にmain.jsに下記のようにを変更します。

src/main.js
import DefaultLayout from '~/layouts/Default.vue'
import 'prismjs/themes/prism.css'


export default function (Vue, { router, head, isClient }) {
  head.link.push({
    rel: 'stylesheet',
    href: 'https://fonts.googleapis.com/css?family=Stylish&display=swap'
  }),
  // Set default layout as a global component
  Vue.component('Layout', DefaultLayout)
}

サンプル記事を用意

content/postsフォルダを作成し、以下のようにファイルを作成します。

src/content/posts/posts.md
---
title: "Writing In Markdown"
description: "Markdown post content stress test. See how your post content is being styled with Tailwind CSS."
date: 2019-05-23
---

Today, A lot of developers are conversant with the `alt` attribute on images. I can say most of us know that it is one way of making webpages accessible but do we really understand the scope of the alternative text, when to make use of it, how to use it. I agree it is one step to being an accessibility advocate so that is why in this article, I'll be explaining in detail the alt attribute and how practicing it can improve web accessibility in a long run.

src/content/posts/vue.md
---
title: "Markdown styling"
description: "Markdown post content stress test. See how your post content is being styled with Tailwind CSS."
date: 2019-05-21
---

Today, A lot of developers are conversant with the `alt` attribute on images. I can say most of us know that it is one way of making webpages accessible but do we really understand the scope of the alternative text, when to make use of it, how to use it. I agree it is one step to being an accessibility advocate so that is why in this article, I'll be explaining in detail the alt attribute and how practicing it can improve web accessibility in a long run.

※サンプルの一部のみを抜粋しています。全文はGitHubにて確認してください。

ここまでできると、以下のように投稿の一覧ページと投稿の詳細ページが表示されます。

  • 投稿の一覧ページ
    202007072240.png

  • 投稿の詳細ページ
    202007072239.png

おまけ

クエリを確認する変更する

http://localhost:8080/___explore を開くとクエリを試せるので、Gridosomeの公式ドキュメントGraphQLの公式ドキュメントを参照して試してみてください。
202007072238.png

VScodeの設定

設定は個人の自由ですが、下記の記事を参考にVScodeにプラグインを入れると、作業しやくすくなると思います。
https://qiita.com/kyohei_ai/items/aeddc6a179ea3a464ed5

今回のファイルはGitHubに公開していますので、参考にしてみてください。
https://github.com/neneta0921/gridsome-blog

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

転職4日目

本日は、参加するプロジェクトで利用する予定のVue.jsについて勉強をしました。
プログラミングスクールでは、主にRubyを学びましたが、Vue.jsについての理解は低く、JavaScriptが使いやすいくらいなのかなとの認識でした。

Vue.jsとは

  • UI(ユーザーインターフェース)を構築するためのJavaScriptフレームワーク
  • MVVMモデル型である
  • SPA開発ができる
  • 記述を少なく済ませることができる

こんな感じです。

Vue.jsのメリット

  • 他のプログラミング言語と比べて学習コストが低い
  • MMVVMモデル型のため、レスポンスが早い
  • DOMを操作するコード量を減らすことができるため、開発スピードが早くなる

まだガイドを読み終えていないので、他にもたくさんあると思いますが、今日1日コードを打ったりガイドを読んでみた感じはこの辺りかなと思います。

実際にガイドで勉強しながら書いてみたコードが以下です。
HTMLファイルに作成するだけで動作します。

veu.html
  <!DOCTYPE html>
  <html lang ="ja">
    <head>
      <meta charset="UTF-8">
      <title>Vue test</title>
    </head>
    <body>
      <script src="https://cdn.jsdelivr.net/npm/vue@2.5.13"></script>
      <div id= "watch-example">
        <p>
          yes/no で回答するので、質問をどうぞ!
          <input v-model="question">
        </p>
        <p>{{ answer }}</p>
      </div>
      <script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
      <script>
        var watchExampleVM = new Vue({
          el: '#watch-example',
          data: {
            question: '', // デフォルトの質問は空白
            answer: '質問受付中です^^' // 回答待ち中の質問
          },
          watch: {
            // この関数は 質問が変わる毎に実行される。
            question: function (newQuestion, oldQuestion) {
              this.answer = 'あなたが入力しています。'
              this.debouncedGetAnswer()
            }
          },
          created: function (){
            this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
            // _.debounce はコストの高い処理の実行を制御するためのlodash の関数
            // この場合、yesno.wtf/apiへのアクセスすべきか制限するために、
            // ユーザー入力が終わるのを待ち ajax リクエストを実行している。
          },
          methods: {
            getAnswer: function () {
              // もし質問の最後に?が入っていない場合の処理
              if (this.question.indexOf('') === -1) {
                this.answer = '質問は最後に?を入れてください。'
                return
              }
              // 最後に?が入っていた場合、処理に移行する
              this.answer = '考え中です、お待ちください...'
              var vm = this
              axios.get('https://yesno.wtf/api')
              .then(function (response) {
                vm.answer = _.capitalize(response.data.answer)
              })
              .catch(function (error) {
                vm.answer = 'APIにアクセスできませんでした' + error
              })
            }
          }
        })
      </script>
    </body>
  </html>

質問を入れたら[Yes/No]で回答をしてくれる単純な作りですが、HTMLファイルのこの記述量で動作するのはすごいと思いました。

勉強してみた所感

Vue.jsのガイドを勉強してるだけでも、感覚的に操作ができるようになってきたので、楽しいと感じられるようになりました。

非同期コンポーネントの理解を深めていけば、実際の業務でも役に立ちそうな気がしてきたので、引き続き理解を深めていこうと思います。

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

Vuetifyのv-selectにてtextの値をカスタマイズする方法

はじめに

Vuetifyのv-selectでは、デフォルトのitemsの仕様は以下となっています

{
  text: string | number | object
  value: string | number | object
}

textの値をバインディングしたオブジェクトから値を取り出した後、加工して設定します

対処法

itemsとして、以下のオブジェクトを使用する場合のコード例です

{
  [
    { id: 1, lastName: "test", firstName: "taro" },
    { id: 2, lastName: "test", firstName: "jiro" },
    { id: 3, lastName: "test", firstName: "saburo" },
    { id: 4, lastName: "test", firstName: "shiro" },
  ]
}

textにfirstName + lastName、valueにidを使用する場合、v-selectのitem-valueとitems-textにitemsの対応するキーを指定します。ここでは以下のようにします

  • value : id
  • text : firstName + lastName
<v-select
  v-model="id"
  label="*氏名"
  :items="items"
  item-value="id"
  :item-text="item => item.lastName + ' ' + item.firstName"
  required>
</v-select>

参考

Customizing item-text in v-select

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

vue-cliインストール時のエラー(EEXIST: file already exists, symlink ~)

エラー発生状況

nodeバージョン:v12.16.3
npmバージョン:6.14.4

Vue CLIをインストールするため

npm install -g @vue/cli

を実行したところ、

npm ERR! code EACCES
npm ERR! syscall access
npm ERR! path /usr/local/lib/node_modules
npm ERR! errno -13
npm ERR! Error: EACCES: permission denied, access '/usr/local/lib/node_modules'
npm ERR!  [Error: EACCES: permission denied, access '/usr/local/lib/node_modules'] {
npm ERR!   errno: -13,
npm ERR!   code: 'EACCES',
npm ERR!   syscall: 'access',
npm ERR!   path: '/usr/local/lib/node_modules'
npm ERR! }
npm ERR! 
npm ERR! The operation was rejected by your operating system.
npm ERR! It is likely you do not have the permissions to access this file as the current user
npm ERR! 
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator.

npm ERR! A complete log of this run can be found in:

と怒られた。

どうやらアクセス権限を拒否されたみたいなので、
コマンドの先頭にsudoをつけて

sudo npm install -g @vue/cli

を実行したところ、

npm ERR! code EEXIST
npm ERR! syscall symlink
npm ERR! path ../lib/node_modules/@vue/cli/bin/vue.js
npm ERR! dest /usr/local/bin/vue
npm ERR! errno -17
npm ERR! EEXIST: file already exists, symlink '../lib/node_modules/@vue/cli/bin/vue.js' -> '/usr/local/bin/vue'
npm ERR! File exists: /usr/local/bin/vue
npm ERR! Remove the existing file and try again, or run npm
npm ERR! with --force to overwrite files recklessly.

npm ERR! A complete log of this run can be found in:

と、さっきとは違うエラーが出た。

解決策

symlinkがどうちゃらこうちゃらなってるみたいなので色々ググって解決策を試してみたのですが一向に直らず。
でもnpmがおかしいんだろうなとは思っていたのでとりあえず

npm install -g npm

でnpmをアップデートし、
再度sudo無しで

npm install -g @vue/cli

を実行したところ、
なんとインストールできました。

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

Vue CLIインストール時のエラー(EEXIST: file already exists, symlink ~)

エラー発生状況

nodeバージョン:v12.16.3
npmバージョン:6.14.4

Vue CLIをインストールするため

npm install -g @vue/cli

を実行したところ、

npm ERR! code EACCES
npm ERR! syscall access
npm ERR! path /usr/local/lib/node_modules
npm ERR! errno -13
npm ERR! Error: EACCES: permission denied, access '/usr/local/lib/node_modules'
npm ERR!  [Error: EACCES: permission denied, access '/usr/local/lib/node_modules'] {
npm ERR!   errno: -13,
npm ERR!   code: 'EACCES',
npm ERR!   syscall: 'access',
npm ERR!   path: '/usr/local/lib/node_modules'
npm ERR! }
npm ERR! 
npm ERR! The operation was rejected by your operating system.
npm ERR! It is likely you do not have the permissions to access this file as the current user
npm ERR! 
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator.

npm ERR! A complete log of this run can be found in:

と怒られた。

どうやらアクセス権限を拒否されたみたいなので、
コマンドの先頭にsudoをつけて

sudo npm install -g @vue/cli

を実行したところ、

npm ERR! code EEXIST
npm ERR! syscall symlink
npm ERR! path ../lib/node_modules/@vue/cli/bin/vue.js
npm ERR! dest /usr/local/bin/vue
npm ERR! errno -17
npm ERR! EEXIST: file already exists, symlink '../lib/node_modules/@vue/cli/bin/vue.js' -> '/usr/local/bin/vue'
npm ERR! File exists: /usr/local/bin/vue
npm ERR! Remove the existing file and try again, or run npm
npm ERR! with --force to overwrite files recklessly.

npm ERR! A complete log of this run can be found in:

と、さっきとは違うエラーが出た。

解決策

symlinkがどうちゃらこうちゃらなってるみたいなので色々ググって解決策を試してみたのですが一向に直らず。
でもnpmがおかしいんだろうなとは思っていたのでとりあえず

npm install -g npm

でnpmをアップデートし、
再度sudo無しで

npm install -g @vue/cli

を実行したところ、
なんとインストールできました。

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

Vue.js ✕ CSS Modules のコンポーネントのつくり方

さいきん流行りのコンポーネント化をすすめるにあたり、
弊社(ビザスク)では Vue.js ✕ CSS Modules を採用しています。

これをマークアップするのがちょっと難しかったので、
初心者向けに マークアップのコツコンポーネントの使い方 をまとめてみました。

※ 担当外なので、script内のことや、vue.js自体の話はしません
※ なぜCSS Modulesを使っているかは以下を参照。
https://qiita.com/mascii/items/3202b9e18fd4a7366ac1

基本説明

以下がコンポーネントファイルの基本の構成です。

ComponentName.vue
<template>
  <div>
    <!-- ここにコンポーネントの中身のHTMLを書く -->
  </div>
</template>

<script lang="ts">
import Vue from 'vue';

export default Vue.extend({
  name: 'ComponentName', // ここにコンポーネントの名前を記載
});
</script>

<style lang="scss" module>
/* ここにscssを書く */
/* "lang=scss"を取り除くとcssで書ける */
</style>

上段の <template> で囲まれた部分にHTMLを書き、
中段の <script> で囲まれた部分にTypeScriptを書き、
下段の <style> で囲まれた部分にscssを書くことで、
コンポーネントが作ることができます。

<template> の書き方

<template>の直下は ひとかたまりにする必要があります

こういうのはできない
<template>
  <h1>タイトル</h1>
  <p>テキスト</p>
</template>
こうする
<template>
  <div>
    <h1>タイトル</h1>
    <p>テキスト</p>
  </div>
</template>

CSS Modulesのクラスの指定方法

HTMLでの通常の書き方とは異なります。
複数のクラスを使いたい時などが特にややこしいので注意が必要です。

1.基本の書き方
<!-- :class と $style がミソ -->
<div :class="$style.class_name"></div>
2.複数のクラスを付けたい時
<!-- Arrayに入れる -->
<div :class="[$style.class1, $style.class2]"></div>
3.条件によってクラスをつけたりつけなかったりしたい時
<!-- Objectにする / 左側は [$style.class_name] のように [] で包む -->
<div :class="{[$style.class_name]: isHoge === true}"></div>
4.?2と3を組み合わせたいとき
<!-- Arrayの中にObjectを入れる -->
<div :class="[{[$style.hoge1]: isFuga}, $style.hoge2]"></div>
コンポーネントにも付けられる
<ComponentName :class="$style.class_name"></ComponentName>

:class ではなく class を使うと通常のglobalなcssも使えます。
当然ながらglobalなcssを書き換えられた際に影響を受けます。
コンポーネント化している意味が薄れるので、よっぽどのことがなければ使わない方がいいと思います。

ちなみに <template><slot /> (後述)には クラスが付けられません
<div> で囲ったり直下に <div> を置いたりして回避してください。

CSS Modules のscssの書き方

<style lang="scss" module>
.container {
  background: #fff;
  font-size: 16px;
}
</style>

先程クラスを :class="$style.class_name" と指定しましたが、
その内の .class_name をクラス名とし、
<style> 内で普通のscss(css)を書くとstyleが反映されます。

CSS Modulesには「外部の影響を受けない」「外部に影響しない」という特徴があるため、
同コンポーネント内で名前が被らない限りは 汎用的なクラス名を使うことができます

例: .container .heading .form .text など

他のコンポーネントの使い方

<script lang="ts">
import Vue from 'vue';
import ComponentName from '@/components/path/ComponentFileName.vue';

export default Vue.extend({
  name: 'Name',
  components: {
    ComponentName,
  }
});
</script>

<script> 内で
使いたいコンポーネントを import して(2行目)
その名前をcomponents として指定する(7行目)と使えるようになります。

コンポーネントは <template> 内のお好みの箇所で、以下のように使用します。

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

コンポーネントの中身を可変にする その1

同じコンポーネントでも中の文字は変えたい、
外側は同じstyleだけど中身は変えたい、といったときに使います。

コンポーネント側
<template>
  <div :class="$style.container">
    <slot />
  </div>
</template>
コンポーネントを使う側
<div>
  <ComponentName>
    <!-- ここに書いたものが <slot /> のところに入る -->
  </ComponentName>
</div>

このように書くと <slot /> 部分が可変になり、
コンポーネントの要素で囲った部分が <slot />に代入されます。

コンポーネントの中身を可変にする その2

slotに名前をつけることで、複数の箇所を可変にできます。
コンポーネントを使うときは <template #name> でどのslotに代入するか指定します。

なお、用意したslotは使わなくても大丈夫です。
その場合 <slot /> 部分に何も代入されなくなります。

コンポーネント側
<template>
  <div :class="$style.container">
    <h1 :class="$style.title">
      <slot name="title" />
    </h1>
    <div :class="$style.contents">
      <slot name="contents" />
    </div>
  </div>
</template>
コンポーネントを使う側
<div>
  <ComponentName>
    <template #title>タイトル</template>
    <template #contents>中身</template>
  </ComponentName>
</div>

コンポーネントの中身を可変にする その3

用意したslotを使わなかった場合、styleだけ当たった空の要素が発生することがあります。
そういうときは「slotがあるときだけこの要素を表示」みたいなロジックを添えるとよいです。

<template>
  <div :class="$style.container">
    <h1 :class="$style.title" v-if="$slots.title">
      <slot name="title" />
    </h1>
  </div>
</template>

上記の例では v-if="$slots.title" を付け足しているので、
<template #title>がないときは <h1> 自体が表示されなくなります。

コンポーネントの中身を可変にする その4

propsを使う方法もあります。
その場合は <script>内に追加の記述が必要です。

コンポーネント側
<template>
  <div :class="$style.container">
    {{ label }} <!-- ここが可変 -->
  </div>
</template>

<script lang="ts">
import Vue from 'vue';

export default Vue.extend({
  name: 'ComponentName',
  props: { // これを追記
    label: {
      type: String,
      required: true,
    },
  },
});
</script>
コンポーネントを使う側
<div>
  <ComponentName label="ここに書いたものが代入される" />
</div>

上記の例では文字列を代入させています。
コンポーネント側の記述量が増えますが、使用する側の記述量は減っています。
短い文字列だけを渡したい時などはこの方法が便利です。

コンポーネントの中身を可変にする その5

その4に記載した propsboolean などを渡すと、
コンポーネント内の表示を切り替えたりすることもできます。

以下の例では「ラベル付きのフォーム」をコンポーネント化しています。
コンポーネント側で作成した required 属性を利用することで、任意項目と必須項目の表示が切り換わるようになっています。

コンポーネント側
<template>
  <div> 
    <label>{{ label }}</label>

    <!-- 以下が切り替わる -->
    <span v-if="required" >(必須)</span>
    <span v-else>(任意)</span>

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

<script lang="ts">
import Vue from 'vue';

export default Vue.extend({
  name: 'FormComponent',
  props: {
    label: { 
      type: String,
      required: true,
    },
    required: { // これを追記
      type: Boolean,
      required: true,
    },
  },
});
</script>
コンポーネントを使う側
<div>
  <FormComponent label="パスワード" :required="true">
    <input type="password" />
  </FormComponent>
</div>

※ 文字列以外を渡す際は 属性に : を付ける必要がある ことに注意してください。

おわりに

コンポーネント化が進むと同じコードを何度も記述しなくて済むようになりますが、
コンポーネント化すること自体の難易度が高く「コピペしたほうが楽だから…」と後回しにしがちです。

このぐらいまで覚えると簡単なコンポーネントであれば一人で作れるようになります。
弊社の様にマークアップをデザイナーが担当している会社もあるかと思いますが、
コンポーネントを作成・編集する際、エンジニアに依頼しなくてもデザイナー自身が行えると開発効率が上がると思います。

マークアップを担当するデザイナーやVue.js ✕ CSS Modulesの環境で開発したいエンジニアさんなど、お役に立てれば幸いです!

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

【Nuxt.js】Nuxt文法編:$emit

? この記事はWP専用です
https://wp.me/pc9NHC-od

$emitとは

通常は子→親には何もできません。
$emitを使えば子自身のイベントや
値を親に渡せます?
値に関してはvuexで管理しても⭕️
ただシンプルな物なら
わざわざvuex使う必要もないし…
って時とかに便利です✨

ちなにみ親→子ならpropsが⭕️

書き方

@clickとセットで使用します?
書き方は2種類

メソッド記法
@click="methods名"
this.$emit('イベント名', 第二引数)

インライン記法
@click="$emit('イベント名', 第二引数)"

? 続きはWPでご覧ください?
https://wp.me/pc9NHC-od

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

【Vueエンジニアおすすめ】絶対に失敗しない画像エフェクト"総まとめ23選"(コピペOK)

スクリーンショット 2020-07-07 18.05.39.png

こちらの記事に記載のデザイン・コードは全て自由に使っていただいて大丈夫です(筆者が作成したため)
プロジェクトに取り込んでより充実したデザインにしてもらえれば○
*動きだけ確認したい初学者の方はJSFiddle使ってみるといいですよ


clip path polygonで2枚の画像を半々(三角形)で表示するCSSアニメーション3選

動きは下の画像のような感じになります

1. 【ぼやけるアニメーション】clip path : polygon+filter : blur

clip-path-image-animation1.png

2. 【美しいアニメーション】clip path : polygon+filter : grayscale contrast saturate

clip-path-image-animation2.png

3. 【オーロラアニメーション】clip path : polygon+filter : grayscale saturate hue-rotate

clip-path-image-animation3.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.37.32.png


【解説付き】マテリアルデザインをコピペで実装!CSSスライダーアニメーション6選(filter編)

動きは下の画像のような感じになります

1. hoverで画像が半透明に?超便利なスライダーアニメーション

click-animation-sliders-filter-opacity.png

2. hoverで画像の色が暴れ出すスライダーアニメーション

click-animation-sliders-filter-hue-rotate.png

3. hoverでモノクロ画像が200倍色鮮やかになるスライダーアニメーション

click-animation-sliders-filter-grayscale.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.42.27.png


絶対失敗しないナビゲーションメニューサンプル3選

動きは下の画像のような感じになります

1. シンプルだけど洗練されたスライダーアニメーション

click-animation-sliders.png

2. blurでぼやけながらスライドするスライダーアニメーション

click-animation-sliders2.png

3. blurとmargin-leftでぼやけながら右へスライドするスライダーアニメーション

click-animation-sliders3.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.43.47.png


hoverで画像の色が暴れ出す!filter: hue-rotateとtransitionでCSSエフェクト3選

動きは下の画像のような感じになります

1. 画像がイルミネーションみたいに光りながら回転するhoverエフェクト

css-effects-hover-filter-hue-rotate-spin.png

2. 臨場感あふれる花火画像が立体的に回転するhoverエフェクト

css-effects-hover-filter-hue-rotate-spin2.png

3. 色相回転しながらぼかしアニメーションを効かせて消えていくhoverエフェクト

css-effects-hover-filter-hue-rotate-blur.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.48.16.png

CSSだけ!hoverとtransitionで作る動的画像エフェクト4選(コピペOK)

動きは下の画像のような感じになります

1. 階段のように背景が現れるhoverエフェクト

animation-image-1.png

2. 上からブロックが落ちてくるように背景が現れるhoverエフェクト

animation-image2.png

3. 斜め上からスクリーンのように背景が現れるhoverエフェクト

animation-image3.png

4. 手裏剣のように回転(rotate)しながら背景が現れるhoverエフェクト

animation-image4.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.53.25.png

hoverとtransitionでオシャレなCSS画像エフェクト4選!(背景がスっと表示される)

動きは下の画像のような感じになります

1. フワッと背景が現れるhoverアニメーション

hover-animation-image-fadein.png

2. 背景が徐々に画像全体へ広がるhoverアニメーション

hover-animation-image-box.png

3. 扉が閉まるように背景が現れるhoverアニメーション

hover-animation-image-door.png

4. 丸い背景が徐々に画像全体に広がるhoverアニメーション

hover-animation-image-squere.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.56.56.png

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

【現役Vueフロントエンジニアおすすめ】絶対に失敗しない画像エフェクト"総まとめ23選"(コピペOK)

スクリーンショット 2020-07-07 18.05.39.png

こちらの記事に記載のデザイン・コードは全て自由に使っていただいて大丈夫です(筆者が作成したため)
プロジェクトに取り込んでより充実したデザインにしてもらえれば○
*動きだけ確認したい初学者の方はJSFiddle使ってみるといいですよ


clip path polygonで2枚の画像を半々(三角形)で表示するCSSアニメーション3選

動きは下の画像のような感じになります

1. 【ぼやけるアニメーション】clip path : polygon+filter : blur

clip-path-image-animation1.png

2. 【美しいアニメーション】clip path : polygon+filter : grayscale contrast saturate

clip-path-image-animation2.png

3. 【オーロラアニメーション】clip path : polygon+filter : grayscale saturate hue-rotate

clip-path-image-animation3.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.37.32.png


【解説付き】マテリアルデザインをコピペで実装!CSSスライダーアニメーション6選(filter編)

動きは下の画像のような感じになります

1. hoverで画像が半透明に?超便利なスライダーアニメーション

click-animation-sliders-filter-opacity.png

2. hoverで画像の色が暴れ出すスライダーアニメーション

click-animation-sliders-filter-hue-rotate.png

3. hoverでモノクロ画像が200倍色鮮やかになるスライダーアニメーション

click-animation-sliders-filter-grayscale.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.42.27.png


絶対失敗しないナビゲーションメニューサンプル3選

動きは下の画像のような感じになります

1. シンプルだけど洗練されたスライダーアニメーション

click-animation-sliders.png

2. blurでぼやけながらスライドするスライダーアニメーション

click-animation-sliders2.png

3. blurとmargin-leftでぼやけながら右へスライドするスライダーアニメーション

click-animation-sliders3.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.43.47.png


hoverで画像の色が暴れ出す!filter: hue-rotateとtransitionでCSSエフェクト3選

動きは下の画像のような感じになります

1. 画像がイルミネーションみたいに光りながら回転するhoverエフェクト

css-effects-hover-filter-hue-rotate-spin.png

2. 臨場感あふれる花火画像が立体的に回転するhoverエフェクト

css-effects-hover-filter-hue-rotate-spin2.png

3. 色相回転しながらぼかしアニメーションを効かせて消えていくhoverエフェクト

css-effects-hover-filter-hue-rotate-blur.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.48.16.png

CSSだけ!hoverとtransitionで作る動的画像エフェクト4選(コピペOK)

動きは下の画像のような感じになります

1. 階段のように背景が現れるhoverエフェクト

animation-image-1.png

2. 上からブロックが落ちてくるように背景が現れるhoverエフェクト

animation-image2.png

3. 斜め上からスクリーンのように背景が現れるhoverエフェクト

animation-image3.png

4. 手裏剣のように回転(rotate)しながら背景が現れるhoverエフェクト

animation-image4.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.53.25.png

hoverとtransitionでオシャレなCSS画像エフェクト4選!(背景がスっと表示される)

動きは下の画像のような感じになります

1. フワッと背景が現れるhoverアニメーション

hover-animation-image-fadein.png

2. 背景が徐々に画像全体へ広がるhoverアニメーション

hover-animation-image-box.png

3. 扉が閉まるように背景が現れるhoverアニメーション

hover-animation-image-door.png

4. 丸い背景が徐々に画像全体に広がるhoverアニメーション

hover-animation-image-squere.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.56.56.png

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

【現役Vueエンジニア厳選】完全オリジナルの画像エフェクト"総まとめ23選"(コピペOK)

スクリーンショット 2020-07-07 18.05.39.png

こちらの記事に記載のデザイン・コードは全て自由に使っていただいて大丈夫です(筆者が作成したため)
プロジェクトに取り込んでより充実したデザインにしてもらえれば○
*動きだけ確認したい初学者の方はJSFiddle使ってみるといいですよ


clip path polygonで2枚の画像を半々(三角形)で表示するCSSアニメーション3選

動きは下の画像のような感じになります

1. 【ぼやけるアニメーション】clip path : polygon+filter : blur

clip-path-image-animation1.png

2. 【美しいアニメーション】clip path : polygon+filter : grayscale contrast saturate

clip-path-image-animation2.png

3. 【オーロラアニメーション】clip path : polygon+filter : grayscale saturate hue-rotate

clip-path-image-animation3.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.37.32.png


【解説付き】マテリアルデザインをコピペで実装!CSSスライダーアニメーション6選(filter編)

動きは下の画像のような感じになります

1. hoverで画像が半透明に?超便利なスライダーアニメーション

click-animation-sliders-filter-opacity.png

2. hoverで画像の色が暴れ出すスライダーアニメーション

click-animation-sliders-filter-hue-rotate.png

3. hoverでモノクロ画像が200倍色鮮やかになるスライダーアニメーション

click-animation-sliders-filter-grayscale.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.42.27.png


絶対失敗しないナビゲーションメニューサンプル3選

動きは下の画像のような感じになります

1. シンプルだけど洗練されたスライダーアニメーション

click-animation-sliders.png

2. blurでぼやけながらスライドするスライダーアニメーション

click-animation-sliders2.png

3. blurとmargin-leftでぼやけながら右へスライドするスライダーアニメーション

click-animation-sliders3.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.43.47.png


hoverで画像の色が暴れ出す!filter: hue-rotateとtransitionでCSSエフェクト3選

動きは下の画像のような感じになります

1. 画像がイルミネーションみたいに光りながら回転するhoverエフェクト

css-effects-hover-filter-hue-rotate-spin.png

2. 臨場感あふれる花火画像が立体的に回転するhoverエフェクト

css-effects-hover-filter-hue-rotate-spin2.png

3. 色相回転しながらぼかしアニメーションを効かせて消えていくhoverエフェクト

css-effects-hover-filter-hue-rotate-blur.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.48.16.png

CSSだけ!hoverとtransitionで作る動的画像エフェクト4選(コピペOK)

動きは下の画像のような感じになります

1. 階段のように背景が現れるhoverエフェクト

animation-image-1.png

2. 上からブロックが落ちてくるように背景が現れるhoverエフェクト

animation-image2.png

3. 斜め上からスクリーンのように背景が現れるhoverエフェクト

animation-image3.png

4. 手裏剣のように回転(rotate)しながら背景が現れるhoverエフェクト

animation-image4.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.53.25.png

hoverとtransitionでオシャレなCSS画像エフェクト4選!(背景がスっと表示される)

動きは下の画像のような感じになります

1. フワッと背景が現れるhoverアニメーション

hover-animation-image-fadein.png

2. 背景が徐々に画像全体へ広がるhoverアニメーション

hover-animation-image-box.png

3. 扉が閉まるように背景が現れるhoverアニメーション

hover-animation-image-door.png

4. 丸い背景が徐々に画像全体に広がるhoverアニメーション

hover-animation-image-squere.png

:point_down:コードを確認する

スクリーンショット 2020-07-07 17.56.56.png

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

【非公式】NotionをCMSにして記事一覧を取得してみた【だけど便利】

みなさんこんにちは。itohです。最近は業務委託でデザイン会社で学びつつ日銭を稼ぐ生活をしています。まだまだ社会情勢など不安定な中皆さんはどうお過ごしでしょうか。
今回は、あのEvernoteの上位互換、タスク管理もメモもブックマーク管理も兼ね備えたすごいツール。NotionをNuxtをつかってCMSみたいにしてみたので、こうして手記をのこしてみたいと思います。

https://www.notion.so/

やりかた

今回はNuxtで作っていきますので、手始めに create-nuxt-app でNuxtのプロジェクトを作成します。

$ npx create-nuxt-app notion-api-test

またこのあとaxiosを入れるかどうか聞かれると思うので忘れずに入れましょう。
入れ忘れた場合はnpmかyarnでaxiosをインストールします。

$ npm i axios

nuxtのプロジェクトができたところでpageディレクトリーにページを追加します。今回私はindex.vueというページを作成しました。

Notionに専用のページをつくる。

さてここまでできたところで、Notionに自分がCMSを設定したいページを作成していきます。ここがデーターベースのような形になるのでただのページではなくFull page listFull page tableで作っていきます。
今回はテスト用にNotionが用意してくれているTemplateで作っていきます。

スクリーンショット 2020-07-07 15.38.09.png

またNotionをブラウザなどで開き、ついでにPAGE_IDTOKENも取得しておきましょう。

PAGE_IDはブラウザで開いたときのURLの黒塗りされた部分、ワークスペース名のスラッシュと?で括られた部分になります。
スクリーンショット 2020-07-07 15.45.41.png

TOKENはこのページで開発者ツール > Application にある token_v2 という項目になります。
スクリーンショット 2020-07-07 15.48.53.png

これで下準備は整いました。それでは実際にコードを書いていきます。

コード

目指すコードはこのような形になります。

<script>
import axios from 'axios'

export default {
  async asyncData() {

    const id = 'PAGE_ID'
    const token = 'TOKEN'
    const { data } = await axios.get(
      'https://notion-api.splitbee.io/v1/table/' + id,
      {
        headers: { Authorization: `Bearer ${token}` }
      }

    )
    console.log(data);
    return {
      ITEM: data
    }
  }
}
</script>

やっていることはヘッドレスCMSを使ったことがある人ならわかると思いますが、import文でaxiosをインポートします。
API情報取得はasync awaitで非同期処理をする必要があります。中にaxiosを使った書き方でgetする対象はhttps://notion-api.splitbee.io/v1/table/のエンドポイントと先ほどのPAGE_IDをつなげた形になります。
今回のこちらのエンドポイント、有志の方々が開発したNotionの記事取得のエンドポイントになります。
資格認証のために、headersにはAuthorizationをキーに設定し、Bearerという文字列の後にTOKENをつなげて渡します。
たったこれだけの行でNotionから情報を取得することができます。

あとはHTMLかPugでコードを書いてスタイルを整理するだけです。

<template lang="pug">
.container
  h2.container__title Meeting
  .container__box
    .item(v-for="item in ITEM")
      p {{item.Name}}
</template>

<script>
import axios from 'axios'

export default {
  async asyncData() {

    const id = 'PAGE_ID'
    const token = 'TOKEN'
    const { data } = await axios.get(
      'https://notion-api.splitbee.io/v1/table/' + id,
      {
        headers: { Authorization: `Bearer ${token}` }
      }

    )
    console.log(data);
    return {
      ITEM: data
    }
  }
}
</script>

<style lang="sass">
.container
  padding: 80px
  width: 100vw
  &__title
    font-size: 40px
    margin-bottom: 60px
  &__box
    display: grid
    display: grid
    grid-template-columns: repeat(3, 1fr)
    grid-template-rows: 1fr
    gap: 20px 20px

.item
  padding: 20px
  border: 1px solid #525252

</style>

localhost_3000_(Desktop).png

最後に

こちらのAPI、Twitterのほうで「What do you guys want to do when the Notion API comes out? I want to use it as a CMS.」と呟いていたところ作者直々に教えていただきました。

しかも1日に使えるリクエストは10,000件と太っ腹です。今回は一覧だけを取得しましたが、中の記事を取得する方法が記載されたドキュメントがあるので、興味がある方は是非ご覧ください。
私も使い始めてわからないことだらけですが、どんどん勉強していきたいと思います。

https://github.com/splitbee/notion-api-worker

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

Vue.js で プルダウンメニューの作り方 (基礎編)

プルダウンとは?

検索バーとしてよく使用されるプルダウンメニューバー。
Webサイトなどにおけるメニューの表示方法の一種で、クリックなどの操作によって複数のメニュー項目を表示させるタイプの表示方法のことである。

完成コード

HTML

<select v-model="selectedFruits">
  <option disabled value="">果物一覧</option>
  <option v-for="fruit in optionFruits" 
    v-bind:value="fruit.name" 
    v-bind:key="fruit.id">
  {{ Fruit.name }}
  </option>
</select>

Vue.js

export default {
  data() {
    return {
      selectedFruits: '', 
      optionFruits: [ 
          { id: 1, name: 'りんご' }, 
          { id: 2, name: 'みかん' }, 
          { id: 3, name: 'ぶどう' } 
      ], 
    }
  }
}

手順① dataを関数に

export default {
  data() {
    return {
  }
}

コンポーネントのdataオプションは関数でなければいけないため、return 以下に初期設定したいdataプロパティの内容を記述します。

手順② dataの値を設定

selectedFruits: '', 
optionFruits: [ 
  { id: 1, name: 'りんご' }, 
  { id: 2, name: 'みかん' }, 
  { id: 3, name: 'ぶどう' } 
], 

selectedFruitsプロパティにはからの文字列("")で指定します。
そしてプルダウン指定値を配列 [] で用意し、その中に複数の{}オブジェクトを用意します。

手順③ HTMLで表示する

<select v-model="selectedFruits">
  <option disabled value="">担当</option>
  <option v-for="fruit in optionFruits" 
    v-bind:value="fruit.name" 
    v-bind:key="fruit.id">
  {{ Fruit.name }}
  </option>
</select>

selectタグにデータバインディングを作成するためのv-modelを指定します。
そしてその値の中に先ほど用意した、selectedFruitsプロパティにはからの文字列("")をあてます。

<select v-model="selectedFruits"></select>

次にoptionタグはfor文で値を回し、それを一つ一つ選択できるように設定します。
その際、先ほど配列 []で用意したoptionFruitsをあてます。

  <option v-for="fruit in optionFruits" 
    v-bind:value="fruit.name" 
    v-bind:key="fruit.id">
  {{ Fruit.name }}
  </option>

key, valueは実際にフォームとして送信したいケースに合わせて値を変更してください。

実際使用するケースとしては、
バックエンド側と連携するプルダウンを作成するために、axiosを使用し、
apiを叩いてselectする値まで取得するケースが多いです。
そちらの記事はまた後ほど追加で書きます。

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

Vueでジェネリックと継承を使って処理の共通化をした話

Vueでジェネリックと継承を使って処理の共通化をした話

前提

背景

  • いくつかのマスタの管理画面をVueで作ることになった。
  • マスタの(View)ModelはTypeScriptの型が作ってある状態。
  • マスタの数が多いぶん、管理画面もたくさん作らなきゃいけない。何とか処理の共通化ができないものか・・・。
  • そこで、 各画面で共通の処理を親クラスに全部書いて、テンプレート(HTML)と各マスタ個別処理は各ページに書く ことにしてみた。

イメージ

  • models/
    • A.ts: モデルAのインターフェース
    • B.ts: モデルBのインターフェース
    • C.ts: モデルCのインターフェース
    • ModelUtil.ts: モデルを操作する関数群の共通インターフェース
    • AModelUtil.ts: モデルAを操作する関数群
    • BModelUtil.ts: モデルBを操作する関数群
    • CModelUtil.ts: モデルCを操作する関数群
  • pages/
    • MasterPageBase.ts: 今回の主役。3つのページの親クラス
    • AMasterPage.vue: Aを操作するためのページ
    • BMasterPage.vue: Bを操作するためのページ
    • CMasterPage.vue: Cを操作するためのページ

やったこと

ページの共通親クラス

MasterPageBase.ts: ページの親クラス。各ページの処理の共通部分を担う。

中身はだいぶ省略。雰囲気だけお伝えします。

@Component
export default class MasterPageBase<T extends IMasterModel> extends Vue {
  // サブクラスで上書く
  protected masterUtil!: ModelUtil<T>;
  protected masterApi!: string;
  protected masterName!: string;

  // ページで現在表示しているマスタの一覧
  protected masters: T[] = [];
  protected page: number = 1;

  protected async save(): Promise<string> {
    // 略
  }
  protected async load(): Promise<T[]> {
    // 略
  }

}

個別ページ

AMatserPage.vue

<template></template>
<script lang="ts">
import { Component } from 'vue-property-decorator';
import MasterPageBase from './MasterPageBase';
import { A } from '@/models/A';
import { AModelUtil } from '@/models/AModelUtil';
import { ModelUtil } from '@/models/ModelUtil';

@Component()
export default class AMasterPage extends MasterPageBase<A> {
  // サブクラスで上書きするべきところ
  protected masterUtil: ModelUtil<A> = AModelUtil;
  protected masterApi: string = '/api/v1/a';
  protected masterName: string = 'A';
}
</script>

中身だいぶ省略。でも実際ほぼこのくらいしか中身ないです。上書きすべきところに値を突っ込む。

ModelUtil

ジェネリックをうまく生かすねらいで、各モデル(ビューモデル?ドメインモデル?)への処理を抽象化した。

こちらも雰囲気で理解してください。clone()を呼ぶとクローンされそうな雰囲気。

ModelUtil.ts

export interface ModelUtil<T> {
  clone(target: T): T;
  empty(): T;
  getId(target: T): T;
  fromServer(obj: object): T;
  toServer(target: T): object;
}
  • MasterPageBaseでは、扱うモデルの種類がわからないまま中身を書くことになる。モデルに対する処理を抽象化するためのインターフェースがこれ。「Tの正体はわからんけどコピーならできる」「Tの正体はわからんけどIDの取得ができる」状態にしておきたかったので。

AModelUtil BModelUtil CModelUtil

ModelUtilを継承してクラスを作っても良かったのだけど、staticとの相性が何か微妙だったので、次の2つのどちらかにしようとした。

  • シングルトンにする
  • 定数にする

シングルトンは大げさだということで定数にした。

export const AModelUtil: ModelUtil<A> {
  clone(target: A): A {
    // 略
  },
  empty(): A {
    // 略
  },
  getId(target: A): A {
    // 略
  },
  fromServer(obj: object): A {
    // 略
  },
  toServer(target: A): object {
    // 略
  },
}

わかったこと・ベストプラクティス的な

? 行数は大きく減った!

個別のページで、<script>部分がほぼ皆無なページがいっぱいできた。大成功!

? プログラムの見通しも良くなった

特別な処理をする必要があったページでも、その特別な処理だけを書けばいいので、プログラムの見通しがぐっと良くなった。

? 実装手順を手順化して、慣れてない人にも作業してもらえた

新しく.vueファイルを作って、
/// サブクラスで上書くの部分を上書いて、
設計書にある通りにコンポーネント置いて、

のように、派遣の方に出す指示がかなり明確になって、慣れていない人にも作業してもらいやすくなった。

? 「この処理ってどこにあるんですか?」と聞かれやすくなった

継承は、見かけ上そのクラスになんにも書いていないのに動くように見えますので、慣れていない人には「なんで動くの!?」と思われがちだった。
フロントエンド界隈はまだまだJavaScriptが強く、静的型付けに慣れていない人は結構いる。ジェネリックや継承などは、C#やJavaなどを触っていると当たり前だけど、そういう開発者ばかりではないので。。。

? 特別な処理をする際の工夫が必要になった

いくら共通化するといっても、特別な処理が必要な場合はどうしてもあって、その際どうしたか

  • 引数でフラグを渡す: あんまりやらなかった
  • 「サブクラスで上書きしてね」: 事前にわかっている、サブクラスで上書きする前提のフィールドやメソッドもいくつか作った。
  • TypeScript(とJavaScript)は関数をオブジェクトとして使える言語なので、コールバック引数を受け取るのはよくやる方法。でも今回はあんまりやらなかった
  • フックを作っておく: 「保存前に呼ばれる処理」のように、ほとんどの場合何もしないけど、あるページでは特別な処理が必要な場合が(途中で)判明して、どうしても共通親クラス側に何かひと手間加えなきゃいけない場合はこれをやった。共通側にはフックだけ作っておいて、特別な処理をしたい場合にはフック関数を上書いてもらう。

以上。似たようなことをしようとしている方の参考になりますように?

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

Nuxt.jsフレームワークを使いこなす

この記事では、Nuxtフレームワークを取り上げ、Alibaba Cloud ECSサーバ上に設定する方法を説明します。

本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。

序章

Nuxt.jsはVue.jsアプリケーションを作成するためのユニバーサルフレームワークです。ユニバーサルなフレームワークを持つ目的は、サーバーサイドでレンダリングされたアプリとしても、静的に生成されたサイトとしても、単一ページのアプリケーションとしても使用できるように柔軟性を持たせることにあります。

Nuxt.jsの主な焦点は、クライアント/サーバーの配信を抽象化しながら、開発のUIレンダリングの側面にあります。この記事では、Nuxt フレームワークを見て、どのように設定するか、また、Vue を搭載したアプリケーションを構築する際にどのように構造化されているかを見ていきます。

なぜNuxtを使うのか?

Nuxt.js には見逃せない機能がバンドルされており、これらの機能はすべて箱から出してすぐに利用できるので、ウェブアプリケーションを構築する際に活用することができます。これらの機能には以下のようなものがあります。

  • 自動コード分割
  • Vueパワード
  • 静的ファイルのレンダリング
  • ホットモジュールの交換
  • プリプロセッサ:Sass、Stylus、Less
  • サーバーサイドレンダリング
  • HTTP/2 サポート

Nuxt アプリを足場にする

Nuxt.jsは本当に簡単に始められます。Nuxtチームは、creat-nuxt-appと呼ばれるNuxtアプリを数秒で作成できるようにするための足場ツールを作成しました。npxyarnを使って以下のコマンドでNuxtプロジェクトを作成することができます。

npx create-nuxt-app <project-name> or 
yarn create nuxt-app <project-name>

image.png

create-nuxt-appコマンドを使用するときに利用できるオプションは多様で、統合されたサーバーサイドフレームワーク、UIフレームワーク、テストフレームワーク、PWAやlintingのような他の必要なツールを持つかどうかを選択することができ、それはあなたのために自動的に生成され、設定されます。しかし、このチュートリアルでは最低限のことしかしないので、いくつかの機能を選択しました。

プロジェクトを実行する

依存関係がインストールされたら、プロジェクトを実行できるコマンドは以下のコマンドです。

yarn run dev

他にも、アプリをビルドしたり、プロジェクト全体をリントしたり、generateスクリプトを使って静的サイトを生成したりするコマンドがあります。

image.png

アプリを起動するコマンドを実行した後、[http://localhost:3000](http://localhost:3000/)に移動すると、以下のような画面でアプリが起動しているのが確認できるはずです。

image.png

フォルダ構造

nuxt アプリのフォルダ構造は、以下のファイルとフォルダディレクトリで構成されています。

image.png

Assets:このフォルダに含まれるファイルは、Nuxtアプリで使用されるイメージ、フォント、スタイルシートなどのアセットで構成されています。

Components: このフォルダに含まれるファイルは、Nuxt アプリで使用されるイメージ、フォント、スタイルシートなどのアセットです。コンポーネントディレクトリは、アプリケーションを構築する際に使用される再利用可能なVue.jsコンポーネントで構成されています。

layouts: layoutsディレクトリには、アプリケーションのlayoutsが含まれています。layoutsは、ページの外観を変更するために使用されます(例えば、ホームページを含めるなど)。layoutsディレクトリには、アプリケーションが使用できる様々なレイアウトが定義されています。ここは、ヘッダーやフッターなど、アプリ全体で使用される共通のグローバル コンポーネントを追加するのに最適な場所です。このファイルには、新しいページごとに何度も何度も再定義したくないコンポーネントを含める必要があります。

middlewaremiddleware ディレクトリには、アプリケーションのmiddlewareが含まれます。middlewareを使用すると、ページまたはページのグループをレンダリングする前に実行できるカスタム関数を定義できます。

pages: pagesディレクトリには、アプリケーションのビューとpagesグループが含まれます。pages ディレクトリには、アプリケーションのビューとルートが含まれます。フレームワークは、このディレクトリ内のすべての.vue ファイルを読み込み、アプリケーション ルーターを作成します。例えば、index.vue が / ルートになり、about.vue/aboutルートになります。

plugins:plugins ディレクトリには、ルート Vue.js アプリケーションをインスタンス化する前に実行したい Javascript pluginsが含まれています。コンポーネントをグローバルに登録したり、関数や定数を注入したりする場所です。

static:static ディレクトリは assets と似ていますが、サーバー ルートに直接マッピングされており (/static/robots.txt は http://localhost:3000/robots.txt 以下からアクセスできます)、変更されない可能性の高いファイル (ファビコンなど) が含まれています。

store:storeディレクトリには、Vuex Storeのファイルが格納されています。Vuex StoreにはNuxt.jsが付属していますが、デフォルトでは無効になっています。このディレクトリにindex.jsファイルを作成すると、storeが有効になります。

nuxt.config.js: このファイルには、Nuxt.jsのカスタム設定が含まれています。余分な設定がないとファイル名を変更できないので注意してください。

package.json:このファイルには、すべての依存関係とスクリプトが格納されており、ファイル名を変更することはできません。

ルーティング

Nuxt.jsでルーティングが動作する方法は、pageディレクトリ内の.vueファイルのファイルツリーに基づいて、自動的にvue-router設定を生成することです。その構造を見て、その構造に基づいてルート設定を自動的に生成します。Nuxt と vue-router は、その下ですべての作業を行います。

そのような構造の例は以下の通りで、ファイルツリーは以下の構造と全く同じようになります。

pages/
--|index.vue
--|product.vue
 --|index.vue
 --|one.vue 

のようなルートを生成します。

router: {
  routes: [
    {
      name: 'index',
      path: '/',
      component: 'pages/index.vue'
    },
    {
      name: 'product',
      path: '/product',
      component: 'pages/product/index.vue'
    },
    {
      name: 'product-one',
      path: '/product/one',
      component: 'pages/product/one.vue'
    }
  ]
}

ダイナミックルート

ダイナミックルートを扱う場合、どのように動作するのか気になるかもしれません。パラメータでダイナミックルートを定義するには、.vue ファイルを定義するか、アンダースコアで始まるディレクトリを定義する必要があります。

pages/
--| _slug/
-----| comments.vue
-----| index.vue
--| users/
-----| _id.vue
--| index.vue

と入力すると、以下のようなルートが生成されます。

router: {
  routes: [
    {
      name: 'index',
      path: '/',
      component: 'pages/index.vue'
    },
    {
      name: 'users-id',
      path: '/users/:id?',
      component: 'pages/users/_id.vue'
    },
    {
      name: 'slug',
      path: '/:slug',
      component: 'pages/_slug/index.vue'
    },
    {
      name: 'slug-comments',
      path: '/:slug/comments',
      component: 'pages/_slug/comments.vue'
    }
  ]
}

ネストされたルート

Nuxt.js を使用すると、vue-router の子ルートを使用してネストされたルートを作成することができます。

ネストされたルートの親コンポーネントを定義するには、子ビューを含むディレクトリと同じ名前の Vue ファイルを作成する必要があります。

pages/
--| products/
-----| _id.vue
-----| index.vue
--| products.vue

このようになります。

router: {
  routes: [
    {
      path: '/products',
      component: 'pages/products.vue',
      children: [
        {
          path: '',
          component: 'pages/products/index.vue',
          name: 'products'
        },
        {
          path: ':id',
          component: 'pages/products/_id.vue',
          name: 'products-id'
        }
      ]
    }
  ]
}

ページ間を移動する際には、vue-router が使用する router-link ではなく、nuxt-link コンポーネントを使用することをお勧めします。

Nuxt.js アプリのデプロイ

Nuxt.jsには、開発用と本番用の両方の便利なコマンドが付属しています。

ここでは、Nuxt アプリの実行に使用されるすべてのスクリプトを見て、Nuxt アプリをデプロイするためのスクリプトを掘り下げていきます。

コマンド 説明
dev localhost:3000で開発サーバーをホットリロードして起動します。
build webpackでアプリケーションを構築し、JSとCSSをミニマイズします(本番用)。
start 本番モードでサーバを起動します(nuxt buildを実行した後)。
generate アプリケーションをビルドし、すべてのルートをHTMLファイルとして生成します(静的ホスティングに使用されます)。

上記のコマンドは、ターミナル上で yarn または npm を使って実行できるスクリプトです。本番環境では、アプリケーションをデプロイする必要があります。Nuxt.jsでは、アプリケーションのデプロイ方法を3つのモードから選ぶことができます。サーバーサイドレンダリング、静的生成、シングルページアプリケーションです。

デプロイ方法の選択に応じて、次のような方法で本番環境向けの Nuxt アプリケーションを構築することができます。

サーバーレンダリング

アプリケーションを実行するには、以下のコマンドを実行する必要があります。

$ yarn build or npm run build

静的に生成された
アプリケーションを静的ファイルに生成するには、以下のコマンドを実行する必要があります。

$ yarn generate or npm run generate

シングルページアプリケーション

Nuxt の SPA は、2 つのモードを使って生成することができます。
- mode: 'spa'nuxt.config.js ファイルに追加する

export default { 
  mode: 'spa'
}
  • すべてのスクリプトコマンドに -spa フラグを追加
"scripts": {
    "dev": "nuxt --spa",
    "build": "nuxt build --spa",
    "start": "nuxt start --spa",
    "generate": "nuxt generate --spa",
  },

上記で説明した以下の手順で、Nuxtアプリを3つの異なるモードでデプロイすることができます。

Nuxtアプリをアリババクラウドにデプロイする

今回は、世界中のどこにでも大量のデータを保存できるクラウドストレージサービスであるAlibaba Object Storage Serviceを使用して、nuxtアプリケーションをデプロイします。

開始するには、すでにアリババクラウドのアカウントを持っている必要がありますが、作成していない場合は、こちらに行って作成してください。

Alibaba Cloud OSSで静的ウェブサイトをホストするためには、まず以下の手順を完了する必要があります。

  • ファイル、画像、スクリプトなどのウェブサイトのファイルを保存するバケットを作成します。
  • 次に、ファイルをバケットにアップロードします。
  • バケットを静的ウェブサイトホスティングモードに設定します。

これらの手順を行った後、サイトをAlibaba Cloudにデプロイし、同様のリンク http://nuxt-app.oss-ap-southeast-1.aliyuncs.com/ を使用してアクセスすることができます。

Alibaba OSSでバケットを作成する

バケットを作成するには、画像に表示されている「バケット作成」ボタンをクリックしてください。モーダルが表示されるので、バケット名リージョンを入力してください。ストレージクラスアクセス制御リスト(ACL)を下の画像のデフォルトに設定してください。

image.png

image.png

バケットにファイルをアップロードする

次のステップは、先ほど作成したバケットにファイルをアップロードすることです。静的サイトとしてデプロイしているので、アップロードできる静的ファイルを作成するために、nuxt generate コマンドを実行する必要があります。コマンドを実行すると、プロジェクトディレクトリにdistフォルダが作成されます。そして、ファイルをアップロードするためにAlibabaに向かい、ファイルをクリックすると、アップロードをクリックできるようになります。先に進み、modalをアップロードするためにdistフォルダ全体をドラッグすると、数秒でファイルがアップロードされます。

image.png

バケットを静的サイトモードに設定する

そして最後のステップとして、バケットを静的なウェブサイトのホスティングモードに設定する必要があります。ダッシュボードで、基本設定をクリックして静的ページに移動し、index.htmlをデフォルトのホームページとして追加します。

image.png

次のステップを経て、我々はAlibaba OSSによって生成されたカスタムドメイン上でサイトを実行していることになります http://nuxt-app.oss-ap-southeast-1.aliyuncs.com/

image.png

結論

アプリケーションとしてのNuxt.jsは、静的サイトの生成、サーバーレンダリング、Vue.jsを使用したシングルページアプリケーションの生成のいずれかに使用することができ、それが普遍的なものであることを示しています。この記事では、プロジェクトの設定からNuxt.jsの機能の理解、ディレクトリ構造と異なるバージョンのNuxtアプリをデプロイする方法まで、Nuxt.jsを使い始める方法を見てきました。これで、Nuxt.jsを使ってWebアプリケーションを構築することができるようになりました。

関連コンテンツ
Vue.JSフレームワークの紹介に関する別のAlibaba Clouderの記事をチェックしてみましょう。

アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ

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

vue.js コマンドメモ

vue init webpack my-project
npm install -g @vue/cli-init
vue init webpack my-project
npm ls | grep ele
npm i element-ui -S 
npm install @nuxtjs/axios
npm install @nuxtjs/dotenv
npm run dev

npm install --save-dev eslint eslint-plugin-vue
npm install stylus-loader stylus --save-dev
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

REST APIベースwebアプリ開発時のHTTPキャッシュについて【GCP使用】

概要

自分はサーバサイドをCloud runにてPython(Flask)、クライアントサイドはFirebaseにてJavascript(Vue.js)で開発しています。pythonではFirestoreのデータの読み書きを主に行っています。このとき、以下の二つの課題に当たってしまいました。

  1. GETリクエストしているのに、OPTIONSリクエストしている(ブラウザにて確認)
  2. GETリクエストがCloud runに届いていないが、レスポンスが返ってくる。このとき、PUTなどでFirestoreの内容を変更していても、GETリクエストのレスポンスが以前のFirestoreの内容になっている。

本記事は、これらの原因と対策について示します。

「1.」について

1については、OPTIONSリクエストはプレフライトリクエストと言い、単純リクエストではない場合、CORS プロトコルが理解されているかどうかを確認する CORS リクエストであるらしいです。これはクライアント側のリクエスト設定を見直すと飛ばなくすることが出来ます(REST APIの時、Authrizationヘッダがある場合があるため、飛んでしまうことが多いかもしれない)。プレフライトリクエストについては、以下のサイトを参考にしてください。結局これは特に問題ではなかったので、ここまで。

「2.」について

こちらは、HTTPキャッシュが原因となっています。サーバサイドでレスポンス生成した際、自分はHTTPキャッシュに係る「Cache-controlヘッダ」を設定していなかったことが原因でした。これにより、本来Cloud run側にリクエストがいかず、FirebaseにあるHTTPキャッシュがクライアントサイドにレスポンスされていました。deploy後の1回目のGET通信は問題ないですが、その後はFirestoreの内容を変更しても、2回以降のGET通信は1回目の内容と同じものとなってしまいます。

おわりに

もしかしたらweb屋さんの常識過ぎるためか、あまりそれっぽい記事はありませんでしたので、備忘録として記述しました。

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

Nuxt.jsで動的に画像のパスを指定する??

Nuxt.jsで画像のパスを指定したかった

requireを使って解決しました
(パスというより名前の指定な気もする…)

失敗:よっしゃこれで…

 <img src="@/static/images/{{ $store.state.img }}" /> 

ダメだった????????????

成功:じゃあこれで…

<img :src="require(`@/static/images/${$store.state.img}`)" />

ヤッターうまく表示できた?????????

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

Vue.jsでHello World!を表示させる。

まずはhead部分

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

続いてbody

<body>
    <div id="app">
        {{ message }}
    </div>
    <script>
        new Vue ({
            el: "#app",
            data: {
                message: "Hello World!"
            }
        });
    </script>
</body>
</html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.jsとjQueryを混在させる

HTML側

CDNでvue.jsとjqueryを読み込みます

<div id="app">
  <button id="okBtn">ok</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
<script src="https://player.vimeo.com/api/player.js"></script>

javascript側

mountedにjqueryで処理する内容を書きます。

const vueApp = new Vue({
  el: "#app",
  data() {
    return {
      message:"hello world"
  };
  },
  mounted() {
    $('#okBtn').on('click',function(){
      alert(vueApp.message);
    })
  }
})

See the Pen abdYzXO by koji miyazaki (@donkey-maru) on CodePen.

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

SPA(シングルページアプリケーション)って何者

はじめに

以前React.jsで開発していた際に、SPAについて調べる機会がありましたので、記載していきます。

SPAとは

「単一ページでアプリケーションを構成すること」
なんだかよくわかりませんね。。。。

まずは従来のアプリケーションとSPAを比較してみましょう。

◇従来のアプリケーション
image.png
 1.ユーザ操作
 2.サーバーにリクエスト
 3.サーバーでWEBページを生成
 4.クライアント側へWEBページを送信
 5.サーバーから受け取ったWEBページを描画

特徴
ユーザがリクエストする度にWEBページ全てが読み込まれることです。

◇SPA
image.png
 1.初期ページ読み込み(初期描画)
 2.ユーザ操作
 3.サーバーにリクエスト
 4.サーバーからクライアント側へ差分データを送信
 5.差分のみを更新

特徴
最初のリクエストのみWEBページ全体を読み込む
その後は差分データ(JSONなど)を受け取りJavaScriptで必要な場所だけを更新する
※従来のものと違い、毎回ページ全体の更新をする必要がなくなる

要するにSPAでは、ページ全体をロードするのは初回のみで
それ以降は、JavaScriptで差分のみを更新するということ。

これが「単一ページでアプリケーションを構成すること」とどうつながるのかというと、
一つのHTMLに対してJavaScriptを用いて更新しているというのがポイントです。

※おまけ
 SPAを作成できるフレームワークとして「React」「Vue」などがあります。
 これらは「仮想DOM」を用いて差分更新を実現しています。よければ調べてみてください。

SPAのメリット/デメリット

◇メリット
・画面全体のロードが最初の描画のみなので、通信負荷や通信容量が削減されて画面表示の高速化につながる
・画面を表示したまま、コンテンツの変更が可能になる
 (更新対象のみを変更するので「待ち」ストレスが無くなる)
・サーバー側でWEBページを生成する必要がなくなり、クライアント側とサーバー側が疎結合になる

◇デメリット
・初期ページを読み込むのに時間がかかる
  JavaScriptの記述量が増えるため、初期描画に時間がかかる
・開発の複雑化
  表示側の多くをJavaScriptで制御する必要があるため  

以前感じていた疑問

SPAとして作ったアプリケーションでもボタン押下等のアクション後にURLが変更され、
画面遷移しているのではと思ったことはないでしょうか。

あれは動的にURLをJavaScriptで変更し、画面の一部を更新しているだけで
擬似的な画面遷移を実現しているのです。
(ユーザ目線では画面遷移しているように見える。)

例として簡単にあげます
Vue.jsでは「vue-router」を使用して、動的にURLを変更しています。
(一部抜粋)

app.vue
<template>
  <div>
    <p>テスト</p>
    <router-view/>
  </div>
</template>

「router-view」と記載されている箇所のみがURLによって
動的に「component」(画面のパーツのようなもの)を切り替えています。

なので実際に画面遷移をしているのではなく、画面の一部がURLによって更新されているということです。
(ちょっと長くなってしまいそうなのでこの辺にさせていただきます。)

まとめ

SPAはユーザへのストレスを減らし、UXをより良いものにしてくれると思います。
そのためにもちゃんと理解をして実装をする必要があります。

ここまでずっとSPAを推しましたが、なんとなくSPAを選んだではダメです。
一つの手段にすぎないため、自分の知識を深め最適かどうかを判断することも重要です。
(自分にも言い聞かせてます。。。。。。。。)

参考文献

参考にさせていただきました。
【qiita】
https://qiita.com/takanorip/items/82f0c70ebc81e9246c7a

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

SPA(シングルページアプリケーション)っていったいなんだ

はじめに

以前React.jsで開発していた際に、SPAについて調べる機会がありましたので、記載していきます。

SPAとは

「単一ページでアプリケーションを構成すること」
なんだかよくわかりませんね。。。。

まずは従来のアプリケーションとSPAを比較してみましょう。

◇従来のアプリケーション
image.png
 1.ユーザ操作
 2.サーバーにリクエスト
 3.サーバーでWEBページを生成
 4.クライアント側へWEBページを送信
 5.サーバーから受け取ったWEBページを描画

特徴
ユーザがリクエストする度にWEBページ全てが読み込まれることです。

◇SPA
image.png
 1.初期ページ読み込み(初期描画)
 2.ユーザ操作
 3.サーバーにリクエスト
 4.サーバーからクライアント側へ差分データを送信
 5.差分のみを更新

特徴
最初のリクエストのみWEBページ全体を読み込む
その後は差分データ(JSONなど)を受け取りJavaScriptで必要な場所だけを更新する
※従来のものと違い、毎回ページ全体の更新をする必要がなくなる

要するにSPAでは、ページ全体をロードするのは初回のみで
それ以降は、JavaScriptで差分のみを更新するということ。

これが「単一ページでアプリケーションを構成すること」とどうつながるのかというと、
一つのHTMLに対してJavaScriptを用いて更新しているというのがポイントです。

※おまけ
 SPAを作成できるフレームワークとして「React」「Vue」などがあります。
 これらは「仮想DOM」を用いて差分更新を実現しています。よければ調べてみてください。

SPAのメリット/デメリット

◇メリット
・画面全体のロードが最初の描画のみなので、通信負荷や通信容量が削減されて画面表示の高速化につながる
・画面を表示したまま、コンテンツの変更が可能になる
 (更新対象のみを変更するので「待ち」ストレスが無くなる)
・サーバー側でWEBページを生成する必要がなくなり、クライアント側とサーバー側が疎結合になる

◇デメリット
・初期ページを読み込むのに時間がかかる
  JavaScriptの記述量が増えるため、初期描画に時間がかかる
・開発の複雑化
  表示側の多くをJavaScriptで制御する必要があるため  

以前感じていた疑問

SPAとして作ったアプリケーションでもボタン押下等のアクション後にURLが変更され、
画面遷移しているのではと思ったことはないでしょうか。

あれは動的にURLをJavaScriptで変更し、画面の一部を更新しているだけで
擬似的な画面遷移を実現しているのです。
(ユーザ目線では画面遷移しているように見える。)

例として簡単にあげます
Vue.jsでは「vue-router」を使用して、動的にURLを変更しています。
(一部抜粋)

app.vue
<template>
  <div>
    <p>テスト</p>
    <router-view/>
  </div>
</template>

「router-view」と記載されている箇所のみがURLによって
動的に「component」(画面のパーツのようなもの)を切り替えています。

なので実際に画面遷移をしているのではなく、画面の一部がURLによって更新されているということです。
(ちょっと長くなってしまいそうなのでこの辺にさせていただきます。)

まとめ

SPAはユーザへのストレスを減らし、UXをより良いものにしてくれると思います。
そのためにもちゃんと理解をして実装をする必要があります。

ここまでずっとSPAを推しましたが、なんとなくSPAを選んだではダメです。
一つの手段にすぎないため、自分の知識を深め最適かどうかを判断することも重要です。
(自分にも言い聞かせてます。。。。。。。。)

参考文献

参考にさせていただきました。
【qiita】
https://qiita.com/takanorip/items/82f0c70ebc81e9246c7a

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

Vite は本当に早いのか ~ Vue CLI と比較 ~

最近話題の Vite を試すついでに、 Vue CLI と比べてどれくらい早いのか確かめてみました。

Vite とは

Vue.js の生みの親、 Evan You 氏が作ったビルドツールです。
開発時は ES モジュールをそのままインポートするため、バンドル処理がなく高速に動作するのが特長です。
https://github.com/vitejs/vite

以下の記事が大変わかりやすくまとまっています。
【Vite】 Vue3.0もReactも!ノーバンドルなビルドツール「Vite」を試してみる

セットアップ

Vite

公式サイトに記載されているコマンドを実行すると、ディレクトリにプロジェクトが生成されました。
自分でパッケージをインストールします。

$ npm init vite-app project-vite
$ cd project-vite
$ npm install

Vite のバージョンは 1.0.0-beta.11 でした(package.json の記載は ^1.0.0-beta.3

Vue CLI

こちらは対話式でインストールを進めていきます。1
なるべく軽くなるよう、オプションは全部はずしました。
パッケージは自動でインストールされます。

$ npm install -g @vue/cli # インストール済なら不要
$ vue create project-vue-cli
$ cd project-vue-cli

開発サーバー起動

開発サーバー起動のコマンドは Vite が npm run dev、Vue CLI は npm run serve です。
(どちらも -- --open をつけるとブラウザでページが開きます)

コマンドを開始してからブラウザに表示されるまでの時間を比較してみましょう。
画面は「上: Vite、下: Vue CLI」です。それぞれ左側が VSCode(エディタ&ターミナル)、右側がブラウザです。
開発サーバー起動
ブラウザにページが表示されるまで Vite は 1.5 秒程度、Vue CLI が 3 秒程度なので、約半分の時間で起動しています。

HMR

次に HMR(Hot Module Replacement)の時間を比較してみます。
先ほど起動したページで、ロゴ画像部分をコメントアウトしてからファイルを保存している動画です。2
前回同様「上: Vite、下: Vue CLI」です。今回は画面中央あたりにキーボード入力が表示されます。
HMR

Vite はファイル保存してすぐにロゴが消えますが、Vue CLI はバンドル処理が入るので少し遅れて反映されていますね。

プロジェクトを巨大化してみる

さて、次はプロジェクトが大きくなった場合はどうなるのか確かめてみましょう。
全体のファイルサイズを大きくするために、重量級ライブラリの代名詞である lodash をまるごと追加してみました。

  1. typeof lodash を返す算出プロパティを作って画面に配置。
  2. 最初は lodash のインポート文をコメントアウトして、lodash: undefined と表示されている状態からスタート。
  3. lodash が読み込まれるようにしてファイルを保存し、lodash: function に変わるまでの時間を比較します。

HMR2

一目瞭然ですね!
Vite は 0.5 秒ほどで反映されますが、Vue CLI は 3 秒近くかかっています。3

ビルド

最後にビルド時間を比較します。
これまでどおり「上: Vite、下: Vue CLI」です。
ビルド
途中、 Vue CLI が先に終わったように見えますが、最後まで見ると Vite の方が早く終わっていることが分かります。

まとめ

Vue CLI でも遅いと感じることはなかったですが、一度 Vite に慣れてしまうと戻れなそうですね。
手軽に Vue 3 の環境を構築できるのも便利なので、次に何か作るときは Vite を使っていきたいです。

おまけ

動画の加工に使ったソフトたち
- デスクトップのキャプチャ: macOS の shift+cmd+5
- キーボード入力表示: KeyCast
- Mov → GIF 変換: ffmpeg


  1. GUI モードもあります。コマンドは vue ui 

  2. Vite は Vue 3 なので template 直下に複数要素を置くことができますが、VSCode の拡張機能が未対応なのでエラー表示になっています(2.x では単一要素しか置けない) 

  3. lodash を読み込んだ状態でロゴ画像の表示→非表示の反映時間は、前の動画と同じくらい(1 秒弱)です。 

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

Vuetifyでラジオボタン(v-radio)を横並びにする方法

Vuetifyのラジオボタン(v-radio)を横並びにしたい。
→propsに row を指定すればOK


まず、普通に書くと以下の画像のように縦並びになります

<v-radio-group>
  <v-radio label="はい"           value="radio-1"></v-radio>
  <v-radio label="どちらでもない"  value="radio-2"></v-radio>
  <v-radio label="いいえ"         value="radio-3"></v-radio>
</v-radio-group>


radio_tate.png

どうにかこれを横並びにしたかったのですが、
「Vuetify ラジオボタン 横」などのバカっぽい検索を繰り返してもなかなか情報が出てきませんでした。
Vuetifyを使わない素のラジオボタンなら、「インライン要素にせよ」などの情報が出てきますが
いろいろ試すも一生縦のまま。

が、公式リファレンスを眺めていると、ばっちり書いてありました。

Radios - Direction
ラジオグループは、それぞれのpropsを使用して、行(row)または列(column)にできます。既定値は column です。

"横並び"など、縦横という言葉に囚われていたので見落としていました。
ページ内検索だけでなく、ざっと全体を読むことも大事ですね……

<v-radio-group row >
  <v-radio label="はい"           value="radio-1"></v-radio>
  <v-radio label="どちらでもない"  value="radio-2"></v-radio>
  <v-radio label="いいえ"         value="radio-3"></v-radio>
</v-radio-group>


radio_yoko.PNG

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

【Vue.js】 Loading 付き Submit Button

Vue.js でのローディング付き submit ボタンのサンプル例を紹介します。
どのプロジェクトでも使えることでしょう。

クリック前

スクリーンショット 2020-07-07 1.08.52.png

クリック後

スクリーンショット 2020-07-07 1.09.01.png

Vue.js + Composition API のコード

ローディングコンポーネント

buttonLoader.vue
<template>
  <div class="loader"></div>
</template>

<style scoped>
.loader,
.loader:after {
  border-radius: 50%;
  width: 10em;
  height: 10em;
}
.loader {
  font-size: 2px;
  position: relative;
  text-indent: -9999em;
  border-top: 1.1em solid rgba(255, 255, 255, 0.2);
  border-right: 1.1em solid rgba(255, 255, 255, 0.2);
  border-bottom: 1.1em solid rgba(255, 255, 255, 0.2);
  border-left: 1.1em solid #ffffff;
  -webkit-transform: translateZ(0);
  -ms-transform: translateZ(0);
  transform: translateZ(0);
  -webkit-animation: load8 1.1s infinite linear;
  animation: load8 1.1s infinite linear;
}
@-webkit-keyframes load8 {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
@keyframes load8 {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
</style>

submit button コンポーネント

submitButton.vue
<template>
  <button type="submit" :class="styles" :disabled="isLoading">
    <button-loader v-if="isLoading" />
    <span v-else>{{ text }}</span>
  </button>
</template>

<script lang="ts">
import { defineComponent } from '@vue/composition-api'
import buttonLoader from '@/components/atoms/buttonLoader.vue'

export default defineComponent({
  components: {
    buttonLoader
  },
  props: {
    text: String,
    styles: String,
    isLoading: Boolean
  },
  setup() {}
})
</script>

利用側のコンポーネント

signup.vue
<template>
  <div>
    <form>
      <submit-button
        @click.native="login()"
        text="ログイン"
        styles="w-full flex justify-center ..etc"
        :isLoading="state.isLoading"
      />
    </form>
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive } from '@vue/composition-api'
import submitButton from '@/components/atoms/submitButton.vue'

export default defineComponent({
  components: {
    submitButton
  },
  setup() {
    const state = reactive({
      isLoading: false
    })
    const login = async () => {
      state.isLoading = true
      try {
        ...
      } catch (error) {
        ...
      } finally {
        state.isLoading = false
      }
    }
    return { state, login }
  }
})
</script>

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