NodeおよびVueのWebアプリケーション、パート2:コンポーネント、フォーム、ルート

Node.js、Vue.js、MongoDBを使用してBudget Manager Webアプリケーションを作成するための一連の資料の2番目の部分を次に示します。 最初の部分では、サーバーを扱いました。つまり、RESTful APIの主要なメソッドを準備し、JWT認証を確立しました。 今日は、アプリケーションのクライアント部分で作業を開始し、フロントエンドフレームワーク、システムに登録およびシステムを入力するためのツールを作成し、ルートとその保護について説明します。



画像



Vue.jsをインストールし、vue-cliを使用します



Vue.jsのインストールは非常に簡単です。 webpack



テンプレートでvue-cli



を使用する予定です。 Vueマニュアルを参照すると、 vue-cli



インストールと作業環境の準備にvue-cli



が使用されてvue-cli



ことがわかります。



 #  vue-cli $ npm install --global vue-cli #       "webpack" $ vue init webpack my-project #   $ cd my-project $ npm install $ npm run dev
      
      





ルートディレクトリにapplication



フォルダーを作成して、プロジェクトの作業を続けます。 vue-cli



中にフォルダーを作成することにより、このステップをスキップできます。 フォルダーを作成しないことにした場合は、この種類のコマンドを実行してプロジェクトに名前を付ける必要があります。



 vue init webpack name-of-your-project
      
      





application



フォルダーを作成した後のプロジェクトは次のようになります。







コマンドラインインタープリターを使用して新しく作成したフォルダーに移動し、 vue-cli



がまだインストールされていない場合は、次のコマンドを実行します。



 npm i --g vue-cli
      
      





このコマンドを使用すると、 vue-cli



グローバルにインストールできるため、実行することでどのフォルダーに入るかは関係ありません。



次のコマンドを呼び出します。



 vue init webpack
      
      





コマンドはapplication



をホストするためにすでに作成されたapplication



フォルダーで実行されることが理解されるため、プロジェクト名はここに示されていないことに注意してください。



上記のコマンドを実行してテンプレートをダウンロードすると、一連の質問が表示されます。







必要に応じて、この段階でプロジェクトの名前、説明、作成者に関する情報を変更できます。 この資料から逸脱しないように、図に示すように他のすべてを残します。



次に、 application



フォルダーに残ったまま、依存関係をインストールしてプロジェクトを開始します。



 npm i npm run dev
      
      





これで、標準のVueページを鑑賞できます。



Vueアプリケーションをクリーンアップする



不要な標準要素をアプリケーションから削除します。 これを行うには、 application/src/assets



フォルダーに移動して、このファイルを使用しないため、 logo.png



を削除します。 次に、 application/src



フォルダーからApp.vue



のルートコンポーネントのファイルを開き、次のコードフラグメントで表される形式にします。



 <template> <div id="app">   <v-container>     <router-view/>   </v-container> </div> </template> <script> export default {   name: 'app' } </script>
      
      





次に、ルートをクリアする必要があります。 これを行うには、 router



フォルダーのindex.js



ファイルを開き、次のフォームに移動します。



 import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) export default new Router({ routes: [   {} ] })
      
      





ルートを構造化する方法は多数ありますが、プロジェクトを複雑にしないために、コンポーネントをインポートしてこのファイルにルートを設定するだけです。



ここで、標準アプリケーションのクリーニングの最後の段階で、 components



フォルダーからHelloWorld.vue



ファイルを削除します。



依存関係のインストール



アプリケーションのフロントエンドの開発を開始する前に、さらにいくつかの依存関係をインストールする必要があります。 次のコマンドを実行する前に、 application



フォルダーにいることを確認します。



 npm i --save axios vuetify vue-cookie
      
      





次に、開発依存関係をインストールします。



 npm i --save-dev sass-loader node-sass
      
      





axios



を使用してHTTPリクエストを処理します。 vuetify



、視覚的なコンポーネントと、メッシュベースのレイアウトを使用する機能に関心があります。 vue-cookie



を操作するには、 vue-cookie



ライブラリを使用します。 sass-loader



およびnode-sass



を使用すると、SCSSを使用できnode-sass







アプリケーションのフロントエンドで開始する



すべての準備活動が完了したので、開発を始めます。 components



フォルダーに移動して、その中にpages



フォルダーを作成します。そこにAuthentication



フォルダーを作成します。 このフォルダーに、認証に使用するコンポーネントを表すAuthentication.vue



ファイルを作成する必要があります。 最終的には次のようになります。







Authentication.vue



ファイルに、次のコードを配置します。



 <template> <h1>Auth!</h1> </template> <script> export default {} </script>
      
      





このコンポーネントの拡張については後ほど説明しますが、ここではrouter



フォルダーに移動してルートを操作します。



まず、 Authentication



コンポーネントをインポートし、その使用のためにルートを構成します。



 import Vue from 'vue' import Router from 'vue-router' // Pages import Authentication from '@/components/pages/Authentication/Authentication' Vue.use(Router) export default new Router({ routes: [   {     path: '/login',     name: 'Authentication',     component: Authentication   } ] })
      
      





その後、アドレスhttp:// localhost:8080 /#/ loginにアクセスすると、「Auth!」という碑文のある空白ページが表示されます。 これは、認証ルートが機能していることを示しています。

src



フォルダーからmain.js



ファイルを開き、 main.js



vue-cookie



をインポートします。



 import VueCookie from 'vue-cookie' import Vuetify from 'vuetify' import('../node_modules/vuetify/dist/vuetify.min.css') Vue.use(VueCookie) Vue.use(Vuetify) Vue.config.productionTip = false
      
      





src



フォルダーからApp.vue



コンポーネントにApp.vue



App.vue



ましょう。 まず、 style



タグを準備する必要があります。 script



タグを閉じた直後に配置しscript







 <style lang="scss"> </style>
      
      





src/assets



フォルダーに移動し、 styles.scss



ファイルとその中のstyles.scss



フォルダーを作成します。 このフォルダーで、 _variables.scss



および_animations.scss



表される2つの部分的なテンプレートを作成し_animations.scss



。 結果は次の構造になります。







_variables.scss



ファイルで、次のパラメーターを設定します。



 // Colors $background-tint: #1734C1; $background-color: rgba(0, 0, 0, .5);
      
      





_animations.css



ファイルで、 bounceIn



およびslideInFromLeft



説明を追加します。



 @keyframes bounceIn { to {     animation-timing-function: cubic-bezier(.215, .61, .355, 1) } 0% {     opacity: 0;     transform: scale3d(.3, .3, .3) } 20% {     transform: scale3d(1.1, 1.1, 1.1) } 40% {     transform: scale3d(.9, .9, .9) } 60% {     opacity: 1;     transform: scale3d(1.03, 1.03, 1.03) } 80% {     transform: scale3d(.97, .97, .97) } to {     opacity: 1;     transform: scaleX(1) } } @keyframes slideInFromLeft { from {   transform: translateX(-2500px);   opacity: 0 } 50% {   transform: translateX(0);   opacity: 1; } 70% {   transform: translateX(-20px); } 90% {   transform: translateX(10px); } to {   transform: translateX(0); } }
      
      





部分的なパターンをstyles.scss



インポートしstyles.scss







 @import "./partials/variables"; @import "./partials/animations";
      
      





次に、 assets



フォルダーで、 images



フォルダーを作成します。 ここに、背景として使用される画像を配置できます。 ここでは、リポジトリで、この資料で使用されているイメージを見つけることができます。



アプリケーションの外観をカスタマイズして、 App.vue



ファイルのApp.vue



ブロックを次のビューに移動します。



 <style lang="scss"> @import "./assets/styles"; body {   background: url('./assets/images/background.jpg') no-repeat center center fixed;   &:after {     content: '';     position: fixed;     width: 100%;     height: 100%;     top: 0;     left: 0;     background-color: $background-tint;     opacity: .3;     z-index: -1;   } } </style>
      
      





ここでは、事前に準備されたscssスタイルをインポートし、アプリケーションの固定背景画像の使用を設定します。 どのデバイスでも、アプリケーション画面がほぼ同じになるように努めています。



body :after



擬似要素のbody :after



に、 $background-tint



変数の値を書き込むことでbackground-color



パラメーターを設定します。 これにより、マゼンタカラーフィルターが背景画像に適用されます。 背景画像のさまざまなバリエーションの外観を次に示します。







スタイリングと背景の操作に関連するすべてがアプリケーションの機能に影響を与えることはありません。したがって、これらの手順をスキップしたり、必要に応じてアプリケーションを装飾したりできます。



表示領域のスケーリングとアイコンの読み込み



この手順により、モバイルデバイスでアプリケーションが正しく表示されるようになります。 さらに、作業のこの段階で、マテリアルデザインのスタイルでアイコンをアップロードします。 これをすべて実行するには、 application



フォルダーにあるindex.html



ファイルに移動し、次の内容をhead



タグに追加します。



 <meta name="viewport" content="initial-scale=1"> <link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' rel="stylesheet">
      
      





認証コンポーネントの開発



少なくとも退屈なホワイトページを取り除き、アプリケーションを少し装飾したので、 Authentication



コンポーネントの作業を続けます。 Authentication



フォルダーにindex.js



ファイルを作成します。







必要なものをインポートし、APIへのパスを記述する定数を宣言します。



 import Axios from 'axios' import router from '@/router' const BudgetManagerAPI = `http://${window.location.hostname}:3001`
      
      





次に、必要なメソッドを含むAuthentication



オブジェクトを作成します。



 export default { user: { authenticated: false } }
      
      





ユーザーが認証されているかどうかに関する情報を保存するuser



というオブジェクトを宣言することで、このコンポーネントの作業を開始します。



それでは、メソッドを書きましょう。



 import Axios from 'axios' import router from '@/router' const BudgetManagerAPI = `http://${window.location.hostname}:3001` export default { user: { authenticated: false }, authenticate (context, credentials, redirect) {   Axios.post(`${BudgetManagerAPI}/api/v1/auth`, credentials)       .then(({data: {token}}) => {         context.$cookie.set('token', token, '1D')         context.validLogin = true         this.user.authenticated = true         if (redirect) router.push(redirect)       }).catch(({response: {data}}) => {         context.snackbar = true         context.message = data.message       }) }, signup (context, credentials, redirect) {   Axios.post(`${BudgetManagerAPI}/api/v1/signup`, credentials)       .then(({data: {token}}) => {         context.$cookie.set('token', token, '1D')         context.validSignUp = true         this.user.authenticated = true                 if (redirect) router.push(redirect)       }).catch(({response: {data}}) => {         context.snackbar = true         context.message = data.message       }) }, checkAuthentication () {   const token = document.cookie   if (token) this.user.authenticated = true   else this.user.authenticated = false }, getAuthenticationHeader (context) {   return `Bearer ${context.$cookie.get('token')}` } }
      
      





最初の方法は3つの引数を使用します。





ここでAxiosを使用して、 credentials



引数を渡すことによりAPIへのPOSTリクエストを実行します。 次に、 token



値のみに関心があるため、応答data



を破棄し、この値をCookieに保存し、このデータの有効期間を1日に設定します。 また、 validLogin



変数とuser



オブジェクトのauthenticated



値をtrue



に設定し、最後にredirect



引数からパスに沿ってユーザーをredirect



ます。



それ以外の場合は、 snackbar



オブジェクトのsnackbar



フィールドをtrue



に設定し、メッセージにエラーメッセージを書き込みます。



2番目の方法は最初の方法と非常によく似ており、新しいアカウントを作成するために使用します。 このメソッドと最初のメソッドの違いは、使用するエンドポイントにあります。

3番目の方法は、ユーザーが認証されているかどうかを確認するために使用されます。

最後のメソッドでは、 Authorization



ヘッダーを返すことができます。



ここで、 Authentication.vue



ファイルを開いてコンポーネントの作業を続けます。 ここでは、Vuetifyツールを使用します。



 <template> <div class="l-auth-container">   <div class="l-auth">     <v-form v-model="validLogin">       <v-text-field label="Username"                     v-model="credentials.username"                     prepend-icon="account_box"                     :rules="rules"                     required                     color="light-blue lighten-1">       </v-text-field>       <v-text-field label="Password"                     v-model="credentials.password"                     prepend-icon="lock"                     :rules="rules"                     :append-icon="loginPasswordVisible ? 'visibility' : 'visibility_off'"                     :append-icon-cb="() => (loginPasswordVisible = !loginPasswordVisible)"                     :type="loginPasswordVisible ? 'text' : 'password'"                     color="light-blue lighten-1"                     required>       </v-text-field>       <v-btn flat color="light-blue lighten-1" @click.native="signUpVisible = true">Create account</v-btn>       <v-btn color="light-blue lighten-1" @click.native="submitAuthentication()">Login</v-btn>     </v-form>   </div>   <div class="l-signup" v-if="signUpVisible">     <v-form v-model="validSignUp">       <v-text-field label="Username"                     v-model="newUser.username"                     prepend-icon="account_box"                     :rules="rules"                     required                     color="light-blue lighten-1">       </v-text-field>       <v-text-field label="Password"                     v-model="newUser.password"                     prepend-icon="lock"                     :rules="rules"                     :append-icon="signUpPasswordVisible ? 'visibility' : 'visibility_off'"                     :append-icon-cb="() => (signUpPasswordVisible = !signUpPasswordVisible)"                     :type="signUpPasswordVisible ? 'text' : 'password'"                     color="light-blue lighten-1"                     required>       </v-text-field>       <v-btn block color="light-blue lighten-1" @click.native="submitSignUp()">Sign Up</v-btn>     </v-form>   </div>   <v-snackbar timeout="6000"               bottom="bottom"               color="red lighten-1"               v-model="snackbar">     {{ message }}   </v-snackbar> </div> </template>
      
      





l-auth-container



として機能するクラスl-auth-container



持つdiv



要素があります。 次に、 l-auth



クラスを持つ別のdiv



があります。これには、入力フォームを整理するための要素の構造が含まれています。特に、 validLogin



変数のデータにバインドされたv-form



要素です。



内部には、 credentials



からのデータに関連付けられた1対の署名されたv-text-field



入力フィールドがありcredentials



(このデータについては後述します)。 フィールドにはhttps://material.io/icons/から取得したアイコンが提供され、入力をチェックするルールもあります(同じルールがあり、同じルールがあり、プロジェクトを複雑にしません)。さらに、これらのフィールドは両方ともバインディング。



2番目の入力フィールドはパスワード用で、入力されているパスワードをユーザーが見ることができるかどうかを示すアイコンが提供されます。 このアイコンにはコールバックがあります。これは、 loginPasswordVisible



変数の値をtrue



からfalse



、またはその逆に切り替えることができる矢印関数です。 この変数がtrue



に設定されているtrue



、入力フィールドのtype



パラメーターはtext



に設定され、そうでない場合はpassword







最後に、新しいアカウントを作成したり、システムに入るためのフォームを送信したりするために使用するボタンの説明があります。



次のコードは、システムの登録フォームの構造を示しています。これは、変数signUpVisible



true



設定されている場合にのみ表示されtrue



。 このフォームのデバイスは、ログインフォームのデバイスに似ていますが、ここでは数行のみが変更されています。 特に、ここではloginPasswordVisible



およびボタンクリックを処理する別のメソッドの代わりに変数signUpPasswordVisible



が使用されます。



さらに、パネルv-snackbar



があり、認証中にメッセージを表示するために使用されます。



次に、同じAuthentication.vue



ファイルで、コンポーネントスクリプトについて説明します。



 <script> import Authentication from '@/components/pages/Authentication' export default {   data () {     return {       snackbar: false,       validLogin: false,       validSignUp: false,       signUpVisible: false,       loginPasswordVisible: false,       signUpPasswordVisible: false,       rules: [ (value) => !!value || 'This field is required' ],       credentials: {         username: '',         password: ''       },       newUser: {         username: '',         password: ''       },       message: ''     }   },   methods: {     submitAuthentication () {       Authentication.authenticate(this, this.credentials, '/')     },     submitSignUp () {       Authentication.signup(this, this.newUser, '/')     }   } } </script>
      
      





このファイル内で定義されたauthenticate



メソッドが必要なため、すべてはAuthentication



フォルダーからindex.js



ファイルをインポートすることから始まります。



次に、コンポーネントデータを格納する変数を見てみましょう。





このコンポーネントにはいくつかのメソッドがあります。 submitAuthentication



メソッドは、 authenticate



ファイルからauthenticate



メソッドを呼び出し、コンテキスト、資格情報、およびリダイレクトパスを渡します。 submitSignUp



メソッドsubmitSignUp



signup



メソッドを呼び出すために使用されます。



そして最後に、同じAuthentication.vue



ファイルに配置する必要のあるコンポーネントスタイリングコードを示します(ここでは、空想を自由に変えて、あらゆるものを自由に作成できます)。



 <style lang="scss"> @import "./../../../assets/styles"; .l-auth {   background-color: $background-color;   padding: 15px;   margin: 45px auto;   min-width: 272px;   max-width: 320px;   animation: bounceIn 1s forwards ease; } .l-signup {   background-color: $background-color;   padding: 15px;   margin: 45px auto;   min-width: 272px;   max-width: 320px;   animation: slideInFromLeft 1s forwards ease; } </style>
      
      





ログインして新しいユーザーを登録するためのコンポーネントを次に示します。







ホームコンポーネント開発



pages



フォルダーに移動し、コンポーネントファイルHome.vue



を作成します。







現時点では、このコンポーネントのテンプレートにはコードが以下に示されていますが、テキストメッセージはわずかしかありません。



 <template> <div>   <h3>Hi! this is our App's Home</h3>   <ul>     <li v-if="users != null" v-for="user in users">       {{ user.username }}     </li>   </ul> </div> </template> <script> import Axios from 'axios' import Authentication from '@/components/pages/Authentication' const BudgetManagerAPI = `http://${window.location.hostname}:3001` export default {   data () {     return {       users: []     }   },   mounted () {     this.getAllUsers()   },   methods: {     getAllUsers (context) {       Axios.get(`${BudgetManagerAPI}/api/v1/users`, {         headers: {           'Authorization': Authentication.getAuthenticationHeader(this)         }       }).then(({data}) => (this.users = data))     }   } } </script>
      
      





このコンポーネントは、このシリーズの次のパートで説明するホームページの基礎です。 それまでの間、APIへのGETリクエストを実行し、APIデバッグメソッドを使用して登録済みのすべてのユーザーを取得し、リクエストヘッダーでトークンを渡します。 これがどのように見えるかです:







ナビゲーション保護



router



フォルダーからindex.js



ファイルを開きます。 以下に、どのようなフォームを持ち込む必要があるかを示します。



 import Vue from 'vue' import Router from 'vue-router' import * as Auth from '@/components/pages/Authentication' // Pages import Home from '@/components/pages/Home' import Authentication from '@/components/pages/Authentication/Authentication' Vue.use(Router) const router = new Router({ routes: [   {     path: '/',     name: 'Home',     component: Home,     meta: {       requiredAuth: true     }   },   {     path: '/login',     name: 'Authentication',     component: Authentication   } ] }) router.beforeEach((to, from, next) => { if (to.meta.requiredAuth) {   if (Auth.default.user.authenticated) {     next()   } else {     router.push('/login')   } } else {   next() } }) export default router
      
      





このコードを検討してください。



 import * as Auth from '@/components/pages/Authentication'
      
      





この行では、 Authentication



コンポーネントもインポートされているため、 Authentication



ファイルをインポートしてAuth



と呼びます。



 const router = new Router({ routes: [   {     path: '/',     name: 'Home',     component: Home,     meta: {       requiredAuth: true     }   },   {     path: '/login',     name: 'Authentication',     component: Authentication   } ] })
      
      





ここでは、後でナビゲーションシステムの保護を作成するために、 Router



オブジェクトに名前を付けます。 また、 Home



コンポーネントへのパスを追加します。 meta.requiredAuth



true



になりtrue



。 これは、認証されていないユーザーがこのコンポーネントにアクセスしようとすると、ログインページにリダイレクトされることを意味します。



 router.beforeEach((to, from, next) => { if (to.meta.requiredAuth) {   if (Auth.default.user.authenticated) {     next()   } else {     router.push('/login')   } } else {   next() } })
      
      





ここでは、ナビゲーションシステムを保護します。 つまり、グローバルウォッチドッグフックを登録しtrue



。これを使用して、各ルートを通過する前にmeta.requiredAuth



パラメーターがtrue



meta.requiredAuth



ているかどうかを確認しtrue



。 その場合、 Authentication



からユーザーオブジェクトを確認します。 ユーザーが認証されない場合、ログインページにリダイレクトします。



 export default router
      
      





このコマンドは、ルーターをエクスポートします。



ここで、 application



フォルダーのmain.js



ファイルを開きます。 ここでは、 Authentication



ファイルをインポートし、 checkAuthentication



メソッドを呼び出します。



 import Vuetify from 'vuetify' import Authentication from '@/components/pages/Authentication' import('../node_modules/vuetify/dist/vuetify.min.css') Vue.use(VueCookie) Vue.use(Vuetify) Vue.config.productionTip = false Authentication.checkAuthentication()
      
      





これがなければ、ユーザーがページをリロードするか閉じてから再び開くと、ログインページにリダイレクトされます。



まとめ



今日は、Vue.jsアプリケーションの作成方法、Vueコンポーネントの開発方法、HTTPリクエストの実行、アプリケーションルートの保護について説明しました。 次の部分では、Homeコンポーネントの最終化に焦点を当て、アプリケーションのクライアント部分とサーバー部分の開発を継続します。



親愛なる読者! Vue.jsに精通している場合は、どのプロジェクトに使用したか、何に満足しているかについて教えてください。



All Articles