あっくんブログ Written by Akihiro Tsuji

Vue3のv属性を使いこなす

Vue.js プログラミング

こんにちは、あっくんです。一昨日は、奈良県いみたらい渓谷というところに行ってきました。河がエメラルドグリーンに見えてすごい綺麗でした。人生で初めて川で泳ぎました。水が想像以上に冷たく驚きでした。やっぱり自然は心身ともに浄化されますね。今回はVue.js3のv属性を使いこなすをやっていきましょう。

v-bindで属性を設定する

v-bind:○○で属性を指定することでVueオブジェクトに用意した値をコンポーネント・タグの属性に指定して、表示させる事ができます。

helloタグをv-bindで設定する

<!DOCTYPE html> <html> <head> <title>My first Vue app</title> <!-- CSS only --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous" /> <!-- JavaScript Bundle with Popper --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous" ></script> <script src="https://unpkg.com/vue@next"></script> </head> <body> <h1 class="bg-secondary text-white display-4 px-3">Vue3</h1> <div id="app" class="container"> <p>{{message}}</p> <hello v-for="item in data" v-bind:name="item"> </div> <script> const appdata = { data() { return { message : '*コンポーネントを表示する', data : ['Taro', 'Hanako', 'Sachiko', 'Jiro'] } } } let app = Vue.createApp(appdata) app.component('hello', { props: {name: String}, data() { return { message: 'これは新しいメッセージです。' } }, template:'<p class="alert alert-primary">Hello, {{name}}!</p>', }) app.mount('#app') </script> </body> </html>
Code language: HTML, XML (xml)
Image from Gyazo

↑アプリケーションのdataに用意した配列を使い、helloコンポーネントを表示する。

Webブラウザで表示すると、<hell/>によるメッセージが4つ表示されます。この4つは、アプリケーション・オブジェクトのdataに用意した値を使って表示を作成しています。

data() { return { message : '*コンポーネントを表示する', data : ['Taro', 'Hanako', 'Sachiko', 'Jiro'] } }
Code language: JavaScript (javascript)

このdataにある配列の値が、そのままhelloコンポーネントのメッセージに使われています。<hell/>タグの記述は↓のようになっています。

<hello v-for="item in data" v-bind:name="item"/>

v-forは繰り返しの属性です。item in dataにより、変数dataから値を順にitemタグに取り出して、タグを繰り返し出力するようになっています。name属性は、v-bind:name=”item”というようにv-bindで値をバインドされています。v-forでdataから値を取り出したitemが、そのままv-bind:nameの 値に設定されています。

v-modelで値をバインド

値を入力し、その値をコンポーネントを表示することをやっていきましょう。コンポーネントでは、「v-modal」という機能が用意されています。<input>の入力値をVueのdataプロパティの値にバインドする機能です。入力された値を変更すると、リアルタイムにバインドされた変数の値が更新されるのです。

値には、Vueオブジェクトのdata内に用意する変数の名前を指定します。これで、入力値が指定の変数にバインドされます。このバインドされた変数を使って、コンポーネントの表示をつくれば、「入力すると即座に表示に反映されるコンポーネント」というのが、作れるようになります。

入力された名前でコンポーネントを表示する

<!DOCTYPE html> <html> <head> <title>My first Vue app</title> <!-- CSS only --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous" /> <!-- JavaScript Bundle with Popper --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous" ></script> <script src="https://unpkg.com/vue@next"></script> </head> <body> <h1 class="bg-secondary text-white display-4 px-3">Vue3</h1> <div id="app" class="container"> <p>{{message}}</p> <div><hello v-bind:name="name" /></div> <div class="form-group"> <input type="text" v-model="name" class="form-control" /> </div> </div> <script> const appdata = { data() { return { message: "*コンポーネントを表示する。", name: "no-name", }; }, }; let app = Vue.createApp(appdata); app.component("hello", { props: ["name"], template: '<p class="alert alert-info">Hello,{{name}}!</p>', }); app.mount("#app"); </script> </body> </html>
Code language: HTML, XML (xml)
Image from Gyazo

↑v-modelを使い、input>の値をバインドしてコンポーネントに表示する。

v-modelの仕組み

<input>タグに↓のようにv-modelの設定を行います。

<input type="text" v-model="name" >

変数nameにバインドしています。

data() { return { message: "*コンポーネントを表示する。", name: "no-name" } }
Code language: JavaScript (javascript)

このnameに、v-modelのvalueがバインドされています。

template: '<p class="alert alert-info">Hello,{{name}}!'</p>

<input>の値を書き換えると、dataプロパティのnameが更新され、更にhelloコンポーネントの{{name}}が更新されて、表示が書き換わります。つまり、v-modelは「入力されたvalueをそのままVueオブジェクトの変数にバインドする」という働きをします。

v-onでイベントをバインドする

クリックすると数字をカウントする」というものを作っていきましょう。

v-on:イベント名 = "・・・処理・・・"

イベント名には、属性として用意する値から「on」を取り除いたものを使います。例えば、onclickなら、v-on:clickです。

<!DOCTYPE html> <html> <head> <title>My first Vue app</title> <!-- CSS only --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous" /> <!-- JavaScript Bundle with Popper --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous" ></script> <script src="https://unpkg.com/vue@next"></script> </head> <body> <h1 class="bg-secondary text-white display-4 px-3">Vue3</h1> <div id="app" class="container"> <p>{{message}}</p> <hello /> </div> <script> const appdata = { data() { return { message: "*コンポーネントの表示する。", name: "no-name", }; }, }; let app = Vue.createApp(appdata); app.component("hello", { data() { return { counter: 0, }; }, template: '<p v-on:click="counter++" class="alert alert-info">clicked: {{counter}}.</p>', }); app.mount("#app"); </script> </body> </html>
Code language: HTML, XML (xml)
Image from Gyazo

↑クリックすると数字が増えるようになった。

イベント処理を別途用意する

イベント処理を呼び出すメソッドは、コンポーネントの「method」というプロパティを用意します。

method: { 名前(event) {・・・・} 名前(event) {・・・・} ・・・必要なだけ用意・・・ }

method内にまとめてた「名前」をv-onの値として指定すると、その名前に設定されたメソッドが実行されます。

クリックするとクラスを変更する

<!DOCTYPE html> <html> <head> <title>My first Vue app</title> <!-- CSS only --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous" /> <!-- JavaScript Bundle with Popper --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous" ></script> <script src="https://unpkg.com/vue@next"></script> </head> <body> <h1 class="bg-secondary text-white display-4 px-3">Vue3</h1> <div id="app" class="container"> <p>{{message}}</p> <hello /> </div> <script> const appdata = { data() { return { message: "*コンポーネントを表示する。", name: "no-name", }; }, }; let app = Vue.createApp(appdata); app.component("hello", { data() { return { counter: 0, isInfo: true, isDark: false, }; }, methods: { doAction() { this.counter++; console.log("counter"); if (this.counter % 2 == 0) { this.isInfo = true; this.isDark = false; console.log("true"); } else { this.isInfo = false; this.isDark = true; console.log("false"); } }, }, template: '<p v-on:click="doAction" v-bind:class="{\'alert-warning\' :isInfo,\'alert-dark\':isDark}" class="alert">clicked:{{counter}}.</p>', }); app.mount('#app') </script> </body> </html>
Code language: HTML, XML (xml)
Image from Gyazo

↑クリックすると数字をカウントする。数字が偶数か奇数で色が変わる。

<p v-on:click="doAction" v-bind:class="{\'alert-warning\' :isInfo,\'alert-dark\':isDark}" class="alert">clicked:{{counter}}.</p>

alert-warningとalert-darkというクラスをisInfo/isDarkという2つの変数の操作でON/OFFできるようにしています。v–on:clickでdoActionというメソッドを呼び出しています。

data() { return { counter: 0, isInfo: true, isDark: false } }, methods: { doAction() { this.counter++; console.log("counter") if (this.counter % 2 == 0) { this.isInfo = true this.isDark = false console.log("true") } else { this.isInfo = false this.isDark = true console.log("false") } },
Code language: JavaScript (javascript)

isInfo/isDarkの値によって出力されるタグのクラス属性にalert-infoとalert-darkが追加されます。methodsではdoActionというメソッドでcounterとisInfo/isDarkを操作しています。

イベント処理とmethods

<!DOCTYPE html> <html> <head> <title>My first Vue app</title> <!-- CSS only --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous" /> <!-- JavaScript Bundle with Popper --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous" ></script> <script src="https://unpkg.com/vue@next"></script> </head> <body> <h1 class="bg-secondary text-white display-4 px-3">Vue3</h1> <div id="app" class="container"> <p>{{message}}</p> <hello /> </div> <script> const appdata = { data() { return { message: "*コンポーネントを表示する。", }; }, }; let app = Vue.createApp(appdata); app.component("hello", { data() { return { num: 0, message: "type a number.", }; }, methods: { calc() { var total = 0; for (var i = 1; i < this.num; i++) { total += i; } this.message = "total:" + total; }, }, template: `<div> <p class="alert alert-info h4">{{message}}</p> <div> <input type="number" class="form-control" v-on:input="calc" v-model="num"> </div> </div>`, }); app.mount("#app"); </script> </body> </html>
Code language: HTML, XML (xml)
Image from Gyazo

↑入力フィールドの数字を変更すると、瞬時にその合計にメッセージが切り替わる。

<input type=”number” >の属性にバインド設定します。

v-on:input="calc" v-model="num"

v-modelでnumがバインドされます。v-onを使って、入力されたら、calcメソッドを実行するようにしています。calcメソッドは↓のようにしています。

methods: { calc() { var total = 0 for (var i = 1; i < this.num; i++) { total += i } this.message = "total:" + total } },
Code language: JavaScript (javascript)

ゼロからthis.numの値までの数字をtotalに加算して得られた合計の数値をthis.messageにメッセージを設定しています。

算術プロパティ

算術プロパティは「計算できるプロパティ」です。予め用意した処理を実行して設定するものです。
つまり「イベントを使ってリアルタイムに処理を実行する」というものです。算術プロパティは「computed」というプロパティに用意します。

computed: { 名前(引数) {・・・処理・・・}, 名前(引数) {・・・処理・・・}, ・・・・必要なだけ用意・・・・・ }
<!DOCTYPE html> <html> <head> <title>My first Vue app</title> <!-- CSS only --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous" /> <!-- JavaScript Bundle with Popper --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous" ></script> <script src="https://unpkg.com/vue@next"></script> </head> <body> <h1 class="bg-secondary text-white display-4 px-3">Vue3</h1> <div id="app" class="container"> <p>{{message}}</p> <hello /> </div> <script> const appdata = { data() { return { message: "*コンポーネントを表示する。", }; }, }; let app = Vue.createApp(appdata); app.component("hello", { data() { return { num: 0, }; }, computed: { calc: function (event) { var total = 0; for (var i = 1; i <= this.num; i++) { total += i; } return "total:" + total; }, }, template: `<div> <p class="alert alert-info h4">{{calc}}</p> <div><input type="number" class="form-control" v-model="num" /></div> </div> `, }); app.mount("#app"); </script> </body> </html>
Code language: HTML, XML (xml)
Image from Gyazo

↑先程のイベントを利用したものと同じ。

イベントとの違い

イベントと算術プロパティの違いは、「呼び出されるタイミング」です。イベント利用はユーザーが操作するなどをしてイベントが発生します。状態が変更されようがされまいがイベントが発生されルト実行されます。算術プロパティは、「値が変更されたとき」飲み呼び出されます。つまり「必要最小限の動作」担っていると考えて良いでしょう。算術プロパティを使うほうが必要以上の負担をかけることがないと思います。

ローカルコンポーネント

これまでのcomponentを使って定義するものを「グローバルコンポーネント」と呼びます。グローバルコンポーネントはグローバル変数でコンポーネントを用意されると常にリロードされるので、負荷がかかります。
Vue3のアプリケーション・オブジェクト内に組み込まれたコンポーネントは「ローカルコンポーネント」と呼びます。ローカルコンポーネントはアプリケーション・オブジェクト内にコンポーネントをまとめることができるので余計な負荷をかけることがありません、
Vueオブジェクトの「copmponets」というプロパティに用意されています。

components: { 名前: {・・・設定情報・・・}, 名前: {・・・設定情報・・・}, ・・・必要なだけ用意・・・ }

helloをローカルに配置する。

<!DOCTYPE html> <html> <head> <title>My first Vue app</title> <!-- CSS only --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous" /> <!-- JavaScript Bundle with Popper --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous" ></script> <script src="https://unpkg.com/vue@next"></script> </head> <body> <h1 class="bg-secondary text-white display-4 px-3">Vue3</h1> <div id="app" class="container"> <p>{{message}}</p> <div><hello /></div> <div><hello /></div> <div><hello /></div> </div> <script> const appdata = { data() { return { message: "*コンポーネントを表示する。", }; }, components: { hello: { data() { return { counter: 0, }; }, template: `<p v-on:click="counter++" class="alert alert-info h5">clicked: {{counter}}.</p> `, }, }, }; let app = Vue.createApp(appdata); app.mount("#app"); </script> </body> </html>
Code language: HTML, XML (xml)
Image from Gyazo

↑3つの<hello/>を配置し、それぞれ機能する。

ローカルコンポーネントはVue内にプロパティとして用意するため、まとまっている感じがあります。Vueから切り離して単独ファイルで使用する時はグローバルコンポーネントが良いとも思います。

ここまで読んでいただいてありがとうございます。掌田津耶乃さんのVue.js3超入門で勉強をしています。語りかけるような文章ですごいわかりやすいです。