Vue.jsとは
- コンポーネントを配置してアプリケーションを作る
- コンポーネントは「.vue」というファイル
- 「.vue」のファイルはシングルファイルコンポーネントと呼ぶ
- vueファイルの中身はvue独自のもの
ブラウザはそのままだと読み込むことができない - ブラウザが理解できるようにjavascriptなどの形に変換する必要がある
- ※vue.jsが内部的に変換する機能も持っている
- こちらで「js」を押すとvue.jsの機能で変換されたjavascriptのコードを見ることができる
この画面が何なのかはわからない - 変換処理は毎回やっていたら大変なので自動でやってほしい
- それを自動でやってくれるのが→「Vite」(ビート)
※vue.jsとは直接関係はない、ただ作ったひとが同じなのでvue.jsと非常に相性がいい
環境づくり
-
Vite自体もjavascriptで書かれている
-
コンピュータ上でjavascriptを実行する環境を整える必要がある
-
そこでインストールするのが「Node.js」
-
「Node.js」→Javascriptを実行するソフトウェア
※これがないとブラウザ以外ではコンピュータ上でJavascriptを実行できない(Viteも使えない) -
ここでインストールした(よくわからないがとりあえずインストールまでやった)
https://nodejs.org/en
基本作業はvs codeで行う
- viteとvue.jsを使うには、HTMLのファイルや設定ファイルを準備する必要があって面倒。
- vue.jsはViteを使う場合に必要となるファイルをまとめて作ってくれるコマンドがある
- ユーザーの階層で「npm create vue@latest」を入力→エンター
- proceedはyで進めた。
- 名前を付けるなどする、そのあとは講座通りに設定した。
「npm create vue@latest」の意味とは
- 「create-vue」というソフトウェアの最新バージョンをインストールした上で、「create-vue」というコマンドを入力する、という処理が1行で行われている
- 色んなファイルが作成されたのは「create-vue」の機能によるもの
- 「create-vue」はファイルを作ってくれるもの、とざっくりおぼえておく
「npm create vue@latest」で作られたファイルの中身
- Vite.config.js
→Viteの設定ファイル - READMR.md
→このプロジェクトの説明 - package.json
→重要なファイル!プロジェクト全体における様々な設定が書かれているファイル
{
"name": "vue-lesson",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore",
"format": "prettier --write src/"
},
"dependencies": {
"vue": "^3.4.21"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.8.0",
"@vitejs/plugin-vue": "^5.0.4",
"@vue/eslint-config-prettier": "^9.0.0",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.23.0",
"prettier": "^3.2.5",
"vite": "^5.2.8"
}
}
-
dependencies
、devDependencies
の中身
→プロジェクト内で必要な第三者が作成したソフトウェア(パッケージと呼ぶ)が一覧で書かれている
※vueやViteも書かれている -
dependencies
、devDependencies
の違い
→「devDependencies」は開発の時だけ使うパッケージ
→「dependencies」は本番環境、実際にブラウザに渡されるパッケージ(vueのみ)
ここに書いているパッケージはまだインストールされていない!
-
create-vueが必要なパッケージをjsonの中に羅列したにすぎない状態
-
インストールする必要がある
-
インストールされたパッケージは「node_modules」というフォルダにすべて入る
「scripts」の意味
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore",
"format": "prettier --write src/"
},
- コマンドと関係している
npm run dev
-
Viteコマンドが実行されて、Viteが開発用のサーバーを起動する
-
http://localhost:5173/
にブラウザでアクセスすると開発中のアプリケーションを見れる -
開発用サーバーを閉じたい場合は「ctrl + c」でできる
npm run build
- 開発がすべて終わった場合に入力するコマンド
- 入力すると、「dist」フォルダができる
- distフォルダの中に入っているファイルはすべて公開用に最適化(軽量化など?)された状態になっている
- distフォルダをアプリを公開してくれるようなサービス(静的ホスティングサービス)に渡すことでアプリを世界中に公開できる
npm run preview
- buildで作ったdistフォルダが正しく動いているかチェックするもの
- 入力するとサーバーが立ち上がる
- 「dist」フォルダの中身をシンプルにレスポンスとして返すサーバーになっている
- 実行して表示されるURLを見ると本番も開発用サーバーと同様に表示されているかを確かめることができる
※これも「ctrl + c」で止めれる
npm run lint
npm run format
- prettierがコードを綺麗にフォーマットしてくれる
- 最初のコードがすでにきれいな状態なので現状とくに修正されない
「npm create vue@latest」で作られたファイルの中身の続きに戻る
-
pacakge-lock.json
※そんなに重要じゃない
→npm install
のコマンドを打った時にインストールされたNode_modulesの中にあるパッケージの厳密な一覧が表示されている -
jsconfig.json
→vscodeが効率よくコードを管理するために必要な設定ファイル
特に普段意識する必要はない -
index.html
→アプリケーション全体の元になるHTMLファイル
ルート直下にあるindex.htmlは開発用、distの中にあるindex.htmlは本番用として返している
中身は少しだけ違う状態になっている
distの中にあるindexはルート直下を元にして作られている -
.prettierrc.json
→prettierの設定ファイル -
.gitignore
→gitの設定ファイル -
.eslintrc.cjs
→eslintの設定ファイル -
srcフォルダ
→ここが開発者がもっとも使用するフォルダとなる
基本的に.vueファイルや、css、javascriptはすべてこの中に置く
※Viteはsrcフォルダの中身にはさまざまな変換処理を行っている
(vueのファイルをjavascriptに変換する処理、公開時の最適化の処理) -
基本的には色んな処理をViteがやってくれる
-
Viteはpublicフォルダの中だけは一切なにも手を加えない
-
publicフォルダに関しては開発中というよりはリリースするタイミングでしようすることが多い
-
とりあえずなんとなく把握しておけばよさそう
-
.vscode
→vscodeの設定をするファイル
ここは長くなるので項目分けて説明
.vscode
-
settings.json
インストールしたeslintとprettierの拡張機能に対する設定が書かれている
{
"editor.codeActionsOnSave": {
"source.fixAll": "explicit"
},
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
"editor.codeActionsOnSave": {
"source.fixAll": "explicit"
},
こちらがeslintの拡張機能の設定
eslintのエラーを保存時に自動で修正してくれる。
※「!!!true」→「!true」でよい
保存時に「!true」に変換してくれる
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
こちらがprettierの設定
prettierも保存時に自動でフォーマット化してくれる
eslintやprettierの細かい設定は各設定ファイルでできる
- .eslintrc.cjs
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-prettier/skip-formatting'
],
parserOptions: {
ecmaVersion: 'latest'
}
}
-
'plugin:vue/vue3-essential',
→'plugin:vue/vue3-recommended',
に変更する
これでeslintがvue.jsのコードに対してかなり厳密なエラーを出す。
今回はその設定にした。
createAppを使ってVueのアプリを作る方法
いったんやったこと
- main.jsの中身削除した
- 「assets」フォルダ、「components」フォルダ、app.vueを削除した(その後、新しく作成した)
main.js
import { createApp } from 'vue'
- vueから提供される「create」という値をインポートする必要がある。
- このように書くことによってViteが良い感じにNode_modulesフォルダの中にあるvueのパッケージの中で定義されている「createApp」を引っ張って使えるようにしてくれる
import { createApp } from 'vue'
createApp()
- createAppは関数になっていて、関数として呼び出すことができる
- この関数を呼び出すことがvue.jsのアプリケーションを作りだす第一ステップとなる
import { createApp } from 'vue'
import App from './App.vue'
createApp(App)
- createApp()関数には引数としてコンポーネントを1つ渡してあげる必要がある
- コンポーネントとは?→vueファイル
- vueファイルを準備→1番最初のvueファイルには「App.vue」と名付けることが多い
- javascriptのデフォルトインポート文(波カッコなどを使わないインポート文)
-
import App from './App.vue'
こちらの「App」の箇所は任意だが、ファイル名に合わせることが多い - 設定した「App」を
createApp()
の引数として渡すことで引数にコンポーネントを渡すことができる - Viteがvueファイル内部でデフォルトインポートできるようなjavascriptのファイルに変換している
- 実際には変換されたjavascriotのファイルをここでインポートしているようなこと
- vueのファイルを使う時はデフォルトインポート文を使う、と覚える
createApp()関数は具体的になにをしているのか
- 引数に指定されたコンポーネントを元にしてvue.jsのメイン機能であるユーザーインターフェイスを作るという処理をしている
- createApp()はvue.jsの根幹的働きをしている。必ず呼び出す必要がある。
- インターフェイスを作るだけで、作ったものを表示する処理はしていない!
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.mount('#app')
- 表示のための処理
- createApp()関数は返り値を返している
- 返り値の「App」が持っている「mount」というメソッドを呼び出す
- こうすることで実際にcreateup関数が作成したインターフェイスを表示することができる
- ユーザーインターフェイスをどこに表示するのか
→mountの引数に文字列でcssセレクタと同じルールで指定する必要がある
この<div id="app"></div>
の中(divタグの中)に表示を指定
※divタグの中になにか記述があった場合、そちらは削除される
vueファイルの中身とは
-
<script>
、<template>
、<style>
の3つの要素から構成されている
- 厳密に言うとscriptタグにはsetupというhtmlの属性みたいなものを書く必要がある
- scriptの中にはjavascriptを書くことができる
- templateにはhtmlを書ける
- styleにはcssを書ける
<script setup>
const userName = 'Test'
console.log(userName)
</script>
<template>
<h1>Title</h1>
</template>
<style>
h1 {
color: red;
}
</style>
-
<template>
の中身が<div id="app">
の中に入っている状態
- scriptとstyleはなくても動くのは動く
- templateは無いとエラーになる
- Appをcosole.logした状態
- コンポーネントはファイルだが、最終的には複雑なオブジェクトとなる
vueファイルにおいて重要なもの
- templateとscript
- templateとscriptをうまく組み合わせることが重要
- それによって複雑なユーザーインターフェイスを作り出すことができる
Javascriptのデータを表示させる方法
- scriptとtemplateを組み合わせる方法を確認
<script setup>
const title = 'Vue.js Course'
</script>
<template>
<h1>Title {{ title }}</h1>
</template>
- 二重波括弧の中に定数を書くと表示することができる
<script setup>
const title = 'Vue.js Course'
let price = 9.99
</script>
<template>
<h1>Title: {{ title }}</h1>
<h1>Price: ${{ price }}</h1>
</template>
<script setup>
const title = 'Vue.js Course'
let price = 9.99
</script>
<template>
<h1>Title: {{ title }}</h1>
<h1>Price: ${{ price - 1 }}</h1>
</template>
クリックされた時に処理を実行する
<script setup>
const title = 'Vue.js Course'
let price = 9.99
function increment() {
console.log('click!')
}
</script>
<template>
<h1>Title: {{ title }}</h1>
<h1>Price: ${{ price - 1 }}</h1>
<button @click="increment">button</button>
</template>
- 関数incrementとbuttonを追加
- 記述した関数に対してタグ内で
<button @click="increment">button</button>
と指定するだけでボタンをクリックするとイベントが発火する
リアクティビティ
<script setup>
const title = 'Vue.js Course'
let price = 9.99
function increment() {
price += 1
console.log(price)
}
</script>
<template>
<h1>Title: {{ title }}</h1>
<h1>Price: ${{ price - 1 }}</h1>
<button @click="increment">button</button>
</template>
変数を更新したにも関わらず一切反映されない理由
- ↑【例】最後にaの数値を変えてもcの値に変化は無い
- 変数を更新したからといってそれを使っている場所まで更新されないのはjavascriptでは当たり前の状態
できれば変数が更新されたら表示も更新されてほしい!
- vue.jsではそのような動きにする機能がある
- なにかしらのデータが変わった時にそれに依存するデータも自動的に更新されるような動きのことを抽象的に「リアクティビティ」と呼ぶ
- vue.jsはリアクティビティシステムをjavascriptで使える機能を提供している
- その機能こそがvue.jsにおける根幹的な基礎の部分となる
ref()を使ってリアクティブなデータを作る方法
<script setup>
import { ref } from 'vue'
const title = 'Vue.js Course'
let price = ref(9.99)
function increment() {
price.value += 1
console.log(price)
}
</script>
<template>
<h1>Title: {{ title }}</h1>
<h1>Price: ${{ price - 1 }}</h1>
<button @click="increment">button</button>
</template>
-
import { ref } from 'vue'
→名前付きimport文でrefという関数をインポートする -
let price = ref(9.99)
→リアクティビティデータを提供したいデータに対して引数に入れて呼び出す
(その返り値を元のデータのように扱う)
- ボタン押すと表示上の数値も増えるようになる
注意点
- javascriptに本来存在しないリアクティブシステムを提供するために技術的な問題でデータをオブジェクトとして管理する必要がある
- refを利用した場合のpriceをコンソールしてみると、9.99という数値ではなく複雑なオブジェクトとして扱われている
- vue.jsはリアクティビティシステムを提供するために裏で複雑な動きをしている(データをオブジェクト管理している)
- ref関数が返す複雑なオブジェクトのことを「ref関数」と呼んだりもする
オブジェクトじゃなくて、単純に9.99という値が欲しい場合はどうする?
-
price.value
とすることで単純に9.99という値を取得できる
値を更新したい場合
price.value = 3.33
のように.valueを付ける必要がある
- eslintの拡張機能を追加していれば、データ保存時に勝手に.value付けてくれる(基本的に付け忘れることは少なさそう?)
templateの方には.value不要
- templateは自動的に変数や定数に関してはそれがrefオブジェクトかどうかを毎回内部的にチェックしている
- refオブジェクトであれば.valueを自動で付けるという動きになっている
<template>
<h1>Title: {{ title }}</h1>
<h1>Price: ${{ price.value - 1 }}</h1>
<button @click="increment">button</button>
</template>
-
<h1>Price: ${{ price.value - 1 }}</h1>
ここに.valueを付けると表示はエラーになる
price.value.value
のようになってしまっている状態 - templateの方には.valueは付けないようにする!
refの引数にオブジェクトを入れることも可能
const info = ref({
student: 1000,
rating: 4
})
- 受講者数が1000人で評価レートが4の情報を持ったリアクティブなオブジェクトデータのようなものも作ることができる
const info = ref({
students: 1000,
rating: 4
})
console.log(info.value.students)
-
info.value.students
と指定することでオブジェクトの中身まで取得できる
<template>
<h1>Title: {{ title }}</h1>
<h1>Price: ${{ price.value - 1 }}</h1>
<button @click="increment">button</button>
<h2>Students: {{ info.students }}</h2>
</template>
- templateの方では
<h2>Students: {{ info.students }}</h2>
とすることで表示できる - templateはvalueが不要なので
info.students
でOK!
reactive()を使ってオブジェクトをリアクティブにする方法
- ref関数以外のデータをリアクティブにする方法
- データをリアクティブにするには技術的な問題でそのデータをオブジェクトで管理する必要がある
- だからref関数は9.99をオブジェクトとして管理していた
- しかし、infoに関してはもともとのデータがオブジェクト。
{
students: 1000,
rating: 4
}
- この部分がオブジェクト
- わざわざこのオブジェクトをリアクティブにするためにもう1新しいオブジェクトを作り出してvalueプロパティでアクセスするのは2度手間
↑意味があんまりわからん! - もともとがオブジェクトなんだからそれをそのままリアクティブにすればよい
<script setup>
import { ref, reactive } from 'vue'
const title = ref('Vue.js Course')
let price = ref(9.99)
function increment() {
price.value += 1
}
const info = ref({
students: 1000,
rating: 4
})
const instructor = reactive({
name: 'Testname',
age: 25
})
console.log(instructor.age)
</script>
<template>
<h1>Title: {{ title }}</h1>
<h1>Price: ${{ price.value - 1 }}</h1>
<button @click="increment">button</button>
<h2>Students: {{ info.students }}</h2>
</template>
- 冒頭のimportと、const instructorを追加
import { ref, reactive } from 'vue'
- ractive関数をインポートに設定
const instructor = reactive({
name: 'Testname',
age: 25
})
console.log(instructor.age)
- reactive関数の引数にオブジェクトを設定することで、
instructor.age
で取得ができる。 - reactive関数で作られるリアクティブなデータはあたかも元のデータがそのまま使われているかのように扱うことができる
- recative関数から生成されるオブジェクトはrefオブジェクトと差別化してリアクティブオブジェクトと呼ばれる
incrementに処理を追加する場合でも、、
function increment() {
price.value += 1
instructor.age += 1
}
- ここにも「.value」は不要になる
refの場合は、、
const instructor = ref({
name: 'Testname',
age: 25
})
console.log(instructor.value.age)
- このように書く必要があった。「.value」を省略できることになる
-
reactiveの中にオブジェクト以外を入れると警告が出るので必ずオブジェクトを入れる
-
ref関数の引数にオブジェクトを入れたとき、内部的にreactive関数を使っている。
reactive関数を使ってその関数の第1引数に指定されたオブジェクトをリアクティブにしている。
そのリアクティブになったものをvalueプロパティに格納している。
const instructor = reactive({
name: 'Testname',
age: 25
})
instructor.bio = 'hello'
-
instructor.bio = 'hello'
で普通に新しいプロパティを追加できる - 「bio」はリアクティブになっている
<script setup>
import { ref, reactive } from 'vue'
const title = ref('Vue.js Course')
let price = ref(9.99)
function increment() {
price.value += 1
instructor.age += 1
instructor.bio = 'hi'
}
const info = ref({
students: 1000,
rating: 4
})
const instructor = reactive({
name: 'Testname',
age: 25
})
instructor.bio = 'hello'
console.log(instructor.age)
</script>
<template>
<h1>Title: {{ title }}</h1>
<h1>Price: ${{ price.value - 1 }}</h1>
<button @click="increment">button</button>
<h2>Students: {{ info.students }}</h2>
<h2>Instructor age: {{ instructor.age }}</h2>
<h2>Instructor bio: {{ instructor.bio }}</h2>
</template>
- こんな感じで変更した
function increment() {
price.value += 1
instructor.age += 1
instructor.bio = 'hi'
}
<h2>Instructor bio: {{ instructor.bio }}</h2>
- こちらを追記。
- ボタンを押すとhelloがhiに変わる
オブジェクトの中にオブジェクトを追加した場合
const instructor = reactive({
name: 'Testname',
age: 25,
sns:{
twitter:'@test_twitter',
youtube: '@test_youtube'
}
})
- snsオブジェクトの内部もリアクティブになる
- リアクティブオブジェクトの中のオブジェクトはすべてリアクティブになる!
reactive()とref()はこうして一緒に使える
- reactiveオブジェクトの中でrefオブジェクトが使われているパターン
const instructor = reactive({
name: 'Testname',
age: 25,
sns: {
twitter: '@test_twitter',
youtube: '@test_youtube'
},
email: ref('test@example.com')
})
-
email: ref('test@example.com')
を追加
console.log(instructor.email.value)
- このように書く必要がありそうに思うが違う!
console.log(instructor.email)
- このようにvalueを省略できる!
- むしろ付けるとエラーになる
- vue.jsはリアクティブオブジェクトのプロパティにアクセスするときは、毎回そのプロパティがrefオブジェクトかどうかをチェックしている。
- もしrefオブジェクトだった場合、valueを毎回自動的に内部で付ける、というテンプレート内でおこなわれているような処理をしている。
function increment() {
price.value += 1
instructor.age += 1
instructor.bio = 'hi'
instructor.sns.twitter = 'hello'
instructor.email = 'info@example.com'
}
- データを更新するときも同じ。
-
instructor.email = 'info@example.com'
でvalueは不要となる - reactiveオブジェクトの中にあるrefオブジェクトはすべて.valueを気にせず使用できる!
【注意点】「.value」が自動で付く動きは配列の時だけは機能しないようになっている
const items = reactive([ref(1), ref(2).ref(3)])
console.log(items[0].value)
- reactive関数の引数にはオブジェクトを入れることができる
- 配列もオブジェクトの1種なので入れることができる
- その配列要素にrefオブジェクトを入れた場合、この配列の要素を取得する時は、reactiveオブジェクトの要素の中身であっても「.value」は自動で付かない!!
console.log(items[0])
- これだとrefオブジェクトがそのままの状態で返ってきてしまう
なぜ配列にだけ「.value」が自動で付かないのか?
- 配列特有のメソッドと動きがバッティングしないように最初から「.value」の自動付与が無しになっている
普通のオブジェクトとref()を一緒に使う
- refオブジェクトが、reactiveオブジェクトの中ではなく、普通のオブジェクトの中にある場合
const courseInfo = {
section: ref(10),
language: ref('Japanese')
}
console.log(courseInfo.sections.value)
- 普通のオブジェクトの中にrefオブジェクトがある場合、呼び出しは通常通り「.value」を付ける形で問題ない
templateの中でアクセスしようとするときが要注意
<template>
<h2>Course Info Sections: {{ courseInfo.sections }}</h2>
</template>
- この場合、
courseInfo.sections
に「.value」は自動で付かない!
<template>
<h2>Course Info Sections: {{ courseInfo.sections.value }}</h2>
</template>
- 末尾に.value付けてあげる必要がある。