20201025のvue.jsに関する記事は6件です。

Vue.jsとDjangoでWebアプリケーションを作ってみる (Mac編) - (1) 環境構築、アプリケーション作成

はじめに

サーバーサイドをPythonのDjango、クライアントサイトをVue.jsで組んでみます。

Djangoアプリケーションは、cookiecutterで作成します。

環境構築

Python

pyenvインストール

Python3.9.0インストール

pyenv versions

でインストール済みのバージョン一覧を表示し、3.9.0がない場合はインストールします。

pyenv install 3.9.0

cookiecutter実行用仮想環境作成

pyenv shell 3.9.0
python -m venv ~/.venv/3.9.0/cookiecutter-3.9
pyenv shell --unset  # pyenvのshellを終了する。

Djangoアプリケーション実行用仮想環境作成

pyenv shell 3.9.0
python -m venv ~/.venv/3.9.0/django-sample-3.9
pyenv shell --unset  # pyenvのshellを終了する。

nodenv

nodenvインストール

node.js 13.11.0インストール

nodenv versions

でインストール済みのバージョン一覧を表示し、13.11.0がない場合はインストールします。

nodenv install 13.11.0

バージョン確認

nodenv versions

cookiecutterアプリケーション作成、実行

cookiecutterの環境を作成

mkdir cookiecutter
cd cookiecutter/
source ~/.venv/3.9.0/cookiecutter-3.9/bin/activate
pip install --upgrade pip
pip install cookiecutter

cookiecutter実行

cookiecutter https://github.com/pydanny/cookiecutter-django

対話式で色々聞かれるので、答えながら先へ進みます。

【注意】
Select cloud_providerで「3」(None)を選択し、use_whitenoiseで「n」とすると、下記のようなエラーになるので、Select cloud_providerで「1」か「2」を選択するか、あるいは、use_whitenoiseで「y」と答えます。

You should either use Whitenoise or select a Cloud Provider to serve static files
ERROR: Stopping generation because pre_gen_project hook script didn't exit successfully
Hook script failed (exit status: 1)
project_name [My Awesome Project]: django-sample
project_slug [django_sample]: app
description [Behold My Awesome Project!]: Django Sample Application
author_name [Daniel Roy Greenfeld]: *****
domain_name [example.com]: 
email [daniel-roy-greenfeld@example.com]: *****@*****.***
version [0.1.0]:
Select open_source_license:
1 - MIT
2 - BSD
3 - GPLv3
4 - Apache Software License 2.0
5 - Not open source
Choose from 1, 2, 3, 4, 5 [1]: 5
timezone [UTC]: Asia/Tokyo
windows [n]:
use_pycharm [n]:
use_docker [n]:
Select postgresql_version:
1 - 12.3
2 - 11.8
3 - 10.8
4 - 9.6
5 - 9.5
Choose from 1, 2, 3, 4, 5 [1]:
Select js_task_runner:
1 - None
2 - Gulp
Choose from 1, 2 [1]:
Select cloud_provider:
1 - AWS
2 - GCP
3 - None
Choose from 1, 2, 3 [1]: 3
Select mail_service:
1 - Mailgun
2 - Amazon SES
3 - Mailjet
4 - Mandrill
5 - Postmark
6 - Sendgrid
7 - SendinBlue
8 - SparkPost
9 - Other SMTP
Choose from 1, 2, 3, 4, 5, 6, 7, 8, 9 [1]: 9
use_async [n]:
use_drf [n]:
custom_bootstrap_compilation [n]:
use_compressor [n]:
use_celery [n]:
use_mailhog [n]:
use_sentry [n]:
use_whitenoise [n]: y
use_heroku [n]:
Select ci_tool:
1 - None
2 - Travis
3 - Gitlab
4 - Github
Choose from 1, 2, 3, 4 [1]:
keep_local_envs_in_vcs [y]:
debug [n]:
 [INFO]: .env(s) are only utilized when Docker Compose and/or Heroku support is enabled so keeping them does not make sense given your current setup.
 [WARNING]: You chose not to use a cloud provider, media files won't be served in production.
 [SUCCESS]: Project initialized, keep up the good work!
質問 デフォルト 設定 備考
project_name My Awesome Project django-sample
project_slug django_sample app
description Behold My Awesome Project! Django Sample Application そのままでも問題ないです
author_name Daniel Roy Greenfeld ***** 自分の名前を入れます
domain_name example.com (デフォルト) 後から変えることになると思いますが、 とりあえずそのままで大丈夫です
email daniel-roy-greenfeld@example.com 自分のメールアドレスを入れます ~
version 0.1.0 (デフォルト)
Select open_source_license
1 - MIT
2 - BSD
3 - GPLv3
4 - Apache Software License 2.0
5 - Not open source
Choose from 1, 2, 3, 4, 5
1 5 オープンソースにする場合はライセンスを選択します
timezone UTC Asia/Tokyo
windows n (デフォルト)
use_pycharm n (デフォルト) PyCharmを使う場合はyにしてもいいと思います
use_docker n (デフォルト)
Select postgresql_version:
1 - 12.3
2 - 11.8
3 - 10.8
4 - 9.6
5 - 9.5
Choose from 1, 2, 3, 4, 5
1 (デフォルト) 私の場合、MySQLやMariaDBを使う事が多いので、後で変更することになるため、ここでは適当にデフォルトで先へ進めます
Select js_task_runner:
1 - None
2 - Gulp
Choose from 1, 2
1 (デフォルト)
Select cloud_provider:
1 - AWS
2 - GCP
3 - None
Choose from 1, 2, 3
1 3 クラウドプロバイダが決まっていないので3にします。すでに決まっている場合は1〜2でも大丈夫だと思います。
Select mail_service:
1 - Mailgun
2 - Amazon SES
3 - Mailjet
4 - Mandrill
5 - Postmark
6 - Sendgrid
7 - SendinBlue
8 - SparkPost
9 - Other SMTP
Choose from 1, 2, 3, 4, 5, 6, 7, 8, 9
1 9 メール送信のサービスで使うものが決まっている場合は選択します。
use_async n (デフォルト)
use_drf n (デフォルト)
custom_bootstrap_compilation n (デフォルト)
use_compressor n (デフォルト)
use_celery n (デフォルト)
use_mailhog n (デフォルト)
use_sentry n (デフォルト)
use_whitenoise n y クラウドプロバイダでNoneを指定した場合、ここでyを選ぶ必要があるようです
use_heroku n (デフォルト)
Select ci_tool:
1 - None
2 - Travis
3 - Gitlab
4 - Github
Choose from 1, 2, 3, 4
1 (デフォルト)
keep_local_envs_in_vcs y (デフォルト)
debug n (デフォルト)

cookiecutterの実行が完了すると、project_slugで回答したスラグ名のディレクトリが作成されます。
そのディレクトリを、ホームディレクトリ直下にdjango-sampleとして移動します。

/bin/cp -Ra app ~/django-sample

Vue.jsアプリケーション作成

mkdir ~/vue-sample/
cd ~/vue-sample/
nodenv local 13.11.0
node -v  # nodeのバージョンがv13.11.0であることを確認

npm init --yes
npm install npm  # npmを最新化

npm install @vue/cli
npm install @vue/cli-init

次に、Pathを通すため、以下を実行します。

npm bin

Macの場合、

/Users/*****/vue-sample/node_modules/.bin

のように表示されるので、そのパスをPATHに追加します。

export PATH="/Users/*****/vue-sample/node_modules/.bin:$PATH"

プロジェクトを作成します。

vue init webpack vue-sample
? Project name vue-sample
? Project description A Vue.js project
? Author
? Vue build standalone
? Install vue-router? No
? Use ESLint to lint your code? No
? Set up unit tests No
? Setup e2e tests with Nightwatch? No
? Should we run `npm install` for you after the project has been created? (recommended) npm

アプリケーションの作成に成功すると、

# Project initialization finished!
# ========================

To get started:

  cd vue-sample
  npm run dev

のように表示されるので、以下のコマンドを実行し、アプリケーションを実行します。

cd vue-sample
npm run dev
Your application is running here: http://localhost:8080

と表示されるので、http://localhost:8080へアクセスします。

image.png

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

Vue3の基本構文③

Vueの構文についてコードベースで簡単にまとめます。
ちなみにシリーズ最終回です。
基本構文①
基本構文②

今回は以下の2つです。

  • コンポーネントとProps
  • コミュニケーティングevent

コンポーネントとProps

コンポーネントとは構成要素を意味し、再利用可能なVueインスタンス要素のことです。
Webページ構成する様々な要素、例えばヘッダーやサイドバーなどを分割し、コンポーネント化することで、設計・開発・テストがコンポーネント単位で行えるようになったりというメリットがあります。
そして、コンポーネントには親コンポーネントと子コンポーネントがあり、親コンポーネントから子コンポーネントに値を渡す際に使用されるのがpropsです。

main.js
const app = Vue.createApp({})

app.component('programming', {
  props: ['title'],
  template: `<h4>{{ title }}</h4>`
})

app.mount('#component-demo')
}

Vueコンポーネントを作成し、その中でprops(title)をVueインスタンスのdataの様に定義します。上のコードから分かる様に、テンプレートからpropsで定義した値にアクセスすることができます。

index.html
<div id="component-demo" class="demo">
  <programming title="Angular"></programming>
  <programming title="React"></programming>
  <programming title="Vue"></programming>
</div>    

コンポーネント側でpropsが登録されたので、引数としてdata(title)をコンポーネントに送ることができます。

Screen Shot 2020-10-24 at 18.39.06.png

実践的な使われ方

main.js
const App = {
    data() {
      return {
        languages: [
          { id: 1, title: 'Angular' },
          { id: 2, title: 'React' },
          { id: 3, title: 'Vue' }
        ]
      }
    }
  }

const app = Vue.createApp(App)

app.component('programming', {
  props: ['title'],
  template: `<h4>{{ title }}</h4>`
})

app.mount('#component-demo')
index.html
<div id="component-demo">
  <programming
    v-for="language in languages"
    :key="language.id"
    :title="language.title"
   ></programming>
</div>  

上記のようにVueインスタンスのdataの中で配列で定義し、htmlでv-forを使いレンダリングする方法が実際のアプリケーションでよく見られます。また、v-bindを使用することでpropsをダイナミックに渡すことができます。

コミュニケーティングevent

コミュニケーションは親コンポーネント->子コンポーネントだけではなく、子->親でもできます。
試しに子コンポーネントのボタンクリックから親にあるメソッドを走らせて、colorプロパティーを変更します。

main.js
const App = {
    data() {
      return {
        languages: [
          { id: 1, title: 'Angular' },
          { id: 2, title: 'React' },
          { id: 3, title: 'Vue' }
        ],
        languageColor: "black"
      }
    }
  }

VueインスタンスのdatalanguageColorプロパティーを追加。

index.html
<div :style="{ color: languageColor }">
  <programming
    v-for="language in languages"
    :key="language.id"
    :title="language.title"
  >
  </programming>
</div>   

htmlでスタイルのcolorを追加

main.js
app.component('programming', {
  props: ['title'],
  template: `
  <h4>{{ title }}</h4>
  <button>
    赤色に変更
  </button>
  `
})

テンプレートにボタンを追加。現状はまだボタンが機能しない。

index.html
<programming
  v-for="language in languages"
  :key="language.id"
  :title="language.title"
  @change-color="languageColor = 'red'"
>
</programming>
</div>   

html側でv-onもしくは@を使うことで子コンポーネントのイベントをリッスンすることができます。@を使用してchange-colorメソッドの実装する。

main.js
<button @click="$emit('change-color')">
  赤色に変更   
</button>

子コンポーネントから親にイベントを発行してくれる$emitを使います。すると、親であるhtmlでイベントを受け取りリスナーのchange-colorメソッドを実行し、以下の様にtitleが赤くなりました。

qiita pic1.gif

おわりに

シリーズ三回に分けてVue3の基本構文を紹介してきました。Vue2とほとんど変わらないものばかり紹介してきましたが、これからもVue3を勉強してアウトプットしていきたいと思います。

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

Vueでtransition-groupの再利用とscoped CSSを組み合わせるにはdeepする必要がある

こんにちは、猫チーズです。

Vue公式ドキュメント「Enter/Leave とトランジション一覧 - Vue.js」の「トランジションの再利用」を参考にしながら、transition-groupを再利用するコンポーネントを作っていたら、リスト移動トランジションが適用されなくてハマりました。

海外系の質問サイトを漁ってもそもそも同様の問題にぶつかってる人が見当たらなかったので、transition-groupの再利用とscoped CSSを組み合わせること自体レアケースなんでしょうか。
何時間か試行錯誤した結果、タイトルの通り原因が分かったのでここに記しておきます。

動作環境:Vue 2.6.12

問題のコード

問題の部分を簡潔に切り出すと以下のような単一ファイルコンポーネントです。

<template>
    <transition-group>
        <slot></slot>
    </transition-group>
</template>

<script>
    // 略
</script>

<style lang='scss' scoped>
    .v-move {
        transition: transform 400ms;
    }
</style>

slotの部分には、呼び出し側でv-forを使って要素たちを並べます。
その要素たちの順番が入れ替わった時には、入れ替わりのトランジションが自動で付く想定です。
ところがこのコードだと、どうしてもトランジションされませんでした。

解決法を探る

❶ slotの代わりに適当な要素を配置して、動的に順番入れ替えしてみる。
トランジションされた。単一ファイルコンポーネントだからうまくいかない、という訳ではない。原因はslot周りにある。

❷ 一つのslotに複数要素を読み込ませるのではなくて、要素数分だけslotを動的に用意して、それらをtransition-groupで囲ってみる。
トランジションされない。templateの段階でtransition-groupの子要素が複数あればいい、という訳ではない。

❸ templateの代わりにrenderオプションを使い、slotの中身を要素ごとにバラし、それぞれの要素を新しいdivで囲ってtransition-groupの子要素として配置する。
トランジションされた。このコンポーネント内で生成された要素がtransition-groupの子要素なら、トランジションされる?

❹ ふと、CSSをカプセル化するためのカスタム属性(data-v-abcd1234みたいなもの)によってtransition-groupの子要素を選別してしまってるのでは?と思い、cssからscopedを除いてみる。
トランジションされた。これが原因ぽい。

❺ このコンポーネントに割り当てられたカスタム属性を手動でコピーして、呼び出し元のslotへ読み込む要素たちに手動でカスタム属性を貼り付けてみる。
トランジションされた。やっぱりScoped CSS用のカスタム属性がtransition-groupの子要素たちにもつけられていないと、トランジションが適用されない。

❻ scopedを取り除く代わりに、トランジション指定用のCSSのセレクタ .v-move に/deep/を付ける。
トランジションされた。カスタム属性がマッチしてようがマッチしてなかろうが、トランジション中にはtransition-groupの子要素に .v-move クラスが付けられるらしい。トランジションが適用されてなかったのは、scopedしてるが故にCSSのセレクタ側で暗黙的にカスタム属性 .v-move[data-v-abcd1234] によって選別してしまっていたからだった。

ということで解決法

コンポーネントのCSSをscopedで安全にカプセル化しつつ、問題の箇所だけ限定的にカプセル化を解くと、下のようなコードになった。

<template>
    <transition-group class='items'>
        <slot></slot>
    </transition-group>
</template>

<script>
    // 略
</script>

<style lang='scss' scoped>
    .items > /deep/ .v-move {
        transition: transform 400ms;
    }
</style>

変更したのは2箇所。
1. transition-groupにクラス名を付ける。
2. .v-move に/deep/を付けてカプセル化を解きつつ、完全に解いてしまうと影響範囲が広いので、 .items > によってtransition-groupの子要素のみに縛っている。

私が実際に作っているコンポーネントはもう少し複雑なので、影響範囲が最小限となるようにこのようにdeepや子要素縛りなどをしているけど、もっと緩めの環境の人は単にscopedを取るだけでもいいかも。

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

脳死でアップデートは危険!Vue3.0の破壊的変更点を要チェック!!

はじめに

Vue3.0がリリースされましたが、Vue2系からアップデートしましたか?
実は破壊的な変更点があり、脳死でアップデートすると危険です。
今回は破壊的変更点の中で特に影響が大きそうな部分を抽出して解説します!!

動画でも解説してるので、動画が好きな方はそちらを確認してみてください!!
【YouTube動画】 Vue3.0の破壊的変更点
Vue3.0の破壊的変更点

Global API

実際のコードの変更をみていきましょう!
以前は以下のように使っていた部分が

import Vue from 'vue'
import App from './App.vue'

Vue.use(/* ... */)
Vue.mixin(/* ... */)
Vue.component(/* ... */)
Vue.directive(/* ... */)

new Vue({
  render: h => h(App)
}).$mount('#app')

こうなります!

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.use(/* ... */)
app.mixin(/* ... */)
app.component(/* ... */)
app.directive(/* ... */)

app.mount(App, '#app')

createAppでインスタンスを作成した後に、Vueの設定を追加していきます。
Vue.xxxxと書いていた部分は修正しないといけませんね。

Global API Tree Shaking

Tree Shakingは使われないコードを除去する仕組みです。
webpackではサポートされてますね。

以前のバージョンでは使わないメソッドもバンドルされていましたが、新しいバージョンでは明示的に書かないとバンドルされないようになりました。
これのおかげで、ファイルサイズがより小さくなります!

影響を受けるのは以下のAPIなので、使ってる方は修正が必要です。

Vue.nextTick
Vue.observable
Vue.version
Vue.compile
Vue.set
Vue.delete

修正するときはimportで使うAPIを指定します。

// Before
import Vue from 'vue'

Vue.nextTick(() => {
  // something DOM-related
})

// After
import { nextTick } from 'vue'

nextTick(() => {
  // something DOM-related
})

v-model

v-modelの書き方も変わりました。
例えば、以下のように書いていた場合

<Comp :value='pageTitle' @input='pageTitle=$event'/>

このように変更する必要があります。

<Comp :modelValue='pageTitle' @update:modelValue='pageTitle=$event'/>

Functional Component

Functional Componentを使っていた方は書き方が簡単になりました。
以下のようにhをインポートして使います。

import { h } from 'vue'

まとめ

いかがでしたか?
間違ってる部分やもっと解説して欲しい部分があれば、コメントいただけると嬉しいです!

また、twitteryoutubeでのコメントもお待ちしています!

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

【Vue.js】動的なデータの反映まとめ

Vue.jsの十八番であるリアクティブなデータの反映の種類をまとめてみました

ディレクティブ等 紐付け先 どうしたいか 実例
v-model data 入力内容や選択内容を動的にしたい input(type="text", v-model="todo.message")
v-bind data htmlタグの属性を動的にしたい img(:src="todo.image)
{{ }} data 表示させる文字を動的にしたい p{{ todo.message }}
{{ }} computed dataの値を変化させたものを動的にしたい p{{ remaining }}

v-model

<template>
  <input type="text" v-model="todo.title">
</template>

<script>
let vm = new Vue({
  el: '#app',

  data: {
    todo: {
      { title: '' },
    }
  },
})
</script>

v-bind

<template>
  <img :src="todo.image">
</template>

<script>
let vm = new Vue({
  el: '#app',

  data: {
    newItem: '',
    todo: {
      { title: 'task1', image: "" },
    }
  },
})
</script>

{{ }}

dataオプションと連動

<template>
  <span>{{ todos[0].title }}</span>
</template>

<script>
let vm = new Vue({
  el: '#app',

  data: {
    todo: {
      { title: 'task1', isDone: false },
    }
  },
})
</script>

computedオプションと連動

<template>
  <span>{{ remaining }}</span>
</template>

<script>
let vm = new Vue({
  el: '#app',

  data: {
    todos: [
      { title: 'task1', isDone: true },
      { title: 'task2', isDone: false },
      { title: 'task3', isDone: false },
    ]
  },
  computed: {
    remaining: function(){
      let remainItems = this.todos.filter(function(todo){
        return !todo.isDone;
      });
      return remainItems.length;
    }
  }
})
</script>

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

Require self-closing on Vue.js custom components (<〇〇>).の解決方法

ESLintを導入後にRequire self-closing on Vue.js custom componentsという警告が出たので解決方法を記載しておきます。

app.vue
<template>
  <v-app id="app">
    <Header></Header>
    <Todolist></Todolist>
  </v-app>
</template>

上記のコードで以下のような警告出ました。

警告
Require self-closing on Vue.js custom components (<Header>).
Require self-closing on Vue.js custom components (<Todolist>).

原因は開始タグと終了タグの間に何も記載がないのが理由ですが、
今回はタグの間に何も書く必要が無いので別の解決方法を使います。

app.vue
<template>
  <v-app id="app">
    <Header />
    <Todolist />
  </v-app>
</template>

このように自己終了タグを使うと警告が出なくなります。

参考
[https://kojimanotech.com/2019/09/22/187/]

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