はじめに
いわゆるウェブアプリを作るのに自分は Vue.js を使っています。
Vue.js を使ってみた - Qiita
Onsen UI+Vue.js を使ってみた - Qiita
ただし、Vue 3 を使っていませんでした。また、コンポーネントも使っていませんでした。
今後の開発に使うかどうか分かりませんが、勉強しておこうと思いました。
Vue.js を使ってみた
・Vue.2.7
・Vue 3.3
インストールする
Vue.js のアプリを作るには、Node.js を使ってローカルな開発環境を構築するのが一般的なようです。
Vue.jsのインストール → プロジェクト作成と起動まで~ - Qiita
今回はあくまでも HTML ファイル一つで、ブラウザだけで動く Vue.js アプリを作っていきたいと思います。
HTML ファイルに以下を追記します。
<script src="https://unpkg.com/vue@2.7.10/dist/vue.min.js"></script>
Vue 3 のとき↓
<script src="https://unpkg.com/vue@3.3.7/dist/vue.global.prod.js"></script>
マウントする
Vue
オブジェクトで管理する対象になる HTML タグを指定するのに、オプション指定の el
プロパティを使います。↓
<div id='root'>
<p>Hello, {{ name }}.</p>
</div>
<script>
var name = "Vue.js";
new Vue({
el: '#root',
data: {
name: name
}
});
Vue
オブジェクトを生成しておいて、HTML タグに mount
する書き方があります。↓
<script>
var name = "Vue.js";
var vm = new Vue({
data: {
name: name
}
});
vm.$mount('#root');
Vue 3 の書き方↓
参考:Vue2 Vue3 比較(new Vue() vs createApp())- Qiita
let name = "Vue.js";
const app = Vue.createApp({
data() {
return {
name: name
};
}
});
app.mount('#root');
data
の書き方を変えないといけません。↑
コンポーネントを作成する
Vue.js も React.js のように、コンポーネントを作って利用することができます。
<script>
Vue.component('v-element', {
props: [ 'name' ],
template: `<p>Hello, {{ name }}.</p>`
});
new Vue({
el: '#root'
});
<div id='root'>
<v-element name="Vue.js" />
</div>
独自タグを作れると言ってよさそうです。↑
呼出元から値を渡してコンポーネントで受取して使用できます。
HTML タグはマウントするポイントだけにして、Vue オブジェクトの template
に内容を記述してマウントする書き方もできます。
<div id='root' />
<script>
var vm = new Vue({
template: `<v-element name="Vue.js" />`
});
Vue.component('v-element', {
props: [ 'name' ],
template: `<p>Hello, {{ name }}.</p>`
});
vm.$mount('#root');
Vue 3 のとき↓
参考:【vue3】component基礎 #JavaScript - Qiita
<script>
const app = Vue.createApp({
template: '<v-element name="Vue.js" />'
});
app.component('v-element', {
props: [ 'name' ],
template: `<p>Hello, {{ name }}.</p>`
});
app.mount('#root');
コンポーネントに状態を加える
コンポーネントは、呼出元から値を受取って使うだけでなく、内部で値を保持して使用します。
data
と methods
を用意します。
カウントアップするボタンのコンポーネントを作ってみます。↓
Vue.component('v-element', {
data() {
return {
count: 0
}
},
methods: {
addCount() {
this.count += 1;
}
},
template: `
<div>
<p>count: {{ count }}</p>
<button v-on:click='addCount'>+</button>
</div>
`
});
Vue 3 の書き方↓
app.component('v-element', {
data() {
return {
count: 0
}
},
methods: {
addCount() {
this.count += 1;
}
},
template: `
<div>
<p>count: {{ count }}</p>
<button v-on:click='addCount'>+</button>
</div>
`
});
コンポーネント間で状態を共有する①
親のコンポーネントで定義された変数を、埋込された子のコンポーネントで参照して使用したいことがあります。
参考:Vue.jsコンポーネント間でデータをやり取りする方法
子コンポーネントで props
を定義します。親コンポーネントから v-bind
で子コンポーネントに値を渡せるようになります。
Vue.component('v-child', {
props: [ 'count' ],
template: `
<div>
<p>Child</p>
<p>count: {{ count }}</p>
</div>
`
});
Vue.component('v-parent', {
data() {
return {
count: 0
}
},
methods: {
addCount(){
this.count += 1;
}
},
template: `
<div>
<p>Parent</p>
<p>count: {{ count }}</p>
<button v-on:click='addCount'>+</button>
<v-child v-bind:count='count' />
</div>
`
});
Vue 3 の書き方↓
app.component('v-child', {
props: [ 'count' ],
template: `
<div>
<p>Child</p>
<p>count: {{ count }}</p>
</div>
`
});
app.component('v-parent', {
data() {
return {
count: 0
}
},
methods: {
addCount() {
this.count += 1;
}
},
template: `
<div>
<p>Parent</p>
<p>count: {{ count }}</p>
<button v-on:click='addCount'>+</button>
<v-child v-bind:count='count' />
</div>
`
});
親コンポーネントで値を変えると子コンポーネントの値も変わります。
コンポーネント間で状態を共有する②
上記の例は、子のコンポーネントで値を変えても、親のコンポーネントの値は変わりません。
親コンポーネントで定義された変数を、子コンポーネントで参照して変更して、それを親コンポーネントで使用したいことがあります。
参考:Vue.jsコンポーネント間でデータをやり取りする方法
親コンポーネントに値を渡したいタイミングで、子コンポーネントでイベントを emit
します。親コンポーネントは v-on
でイベントを受取して、そこでメソッドを呼出して値を受取できます。
Vue.component('v-child', {
props: [ 'count' ],
methods: {
addCount() {
this.count += 1;
this.$emit('CountChanged', this.count);
}
},
template: `
<div>
<p>Child</p>
<p>count: {{ count }}</p>
<button v-on:click='addCount'>+</button>
</div>
`
});
Vue.component('v-parent', {
中略
methods: {
中略
countChanged(value) {
this.count = value;
}
},
template: `
<div>
<p>Parent</p>
<p>count: {{ count }}</p>
中略
<v-child v-bind:count='count' v-on:CountChanged='countChanged' />
</div>
`
});
Vue 3 の書き方↓
app.component('v-child', {
props: [ 'count' ],
emits: [ 'CountChanged' ],
setup(props, context) {
return {
addCount() {
props.count += 1;
context.emit('CountChanged', props.count);
}
}
},
template: `
<div>
<p>Child</p>
<p>count: {{ count }}</p>
<button v-on:click='addCount'>+</button>
</div>
`
});
app.component('v-parent', {
中略
methods: {
中略
countChanged(value) {
this.count = value;
}
},
template: `
<div>
<p>Parent</p>
<p>count: {{ count }}</p>
中略
<v-child v-bind:count='count' v-on:CountChanged='countChanged' />
</div>
`
});
子コンポーネントで値を変えると親コンポーネントの値も変わります。
コンポーネント間で状態を共有する③
<v-child v-bind:count='count' v-on:CountChanged='countChanged' />
v-on
と v-bind
を v-bind
に書換してみます。
<v-child v-model='count' />
Vue 2 の場合、これは以下と同じです。
<v-child v-bind:value='count' v-on:input='count = $event.target.value' />
参考:v-model を正しく理解して親子間コンポーネントのデータ伝播をマスターする - Qiita
これに合わせて子コンポーネントの props
と emit
を書換します。
Vue.component('v-child', {
props: [ 'value' ],
methods: {
addCount() {
this.value += 1;
this.$emit('input', this.value);
}
},
以下略
Vue 3 の書き方↓
v-model
に引数を指定できるので、引数 count
で子に渡すようにします。子で emit
するイベントは、引数 count
を指定して update
します。
<v-child v-model:count='count' />
app.component('v-child', {
props: [ 'count' ],
emits: [ 'update' ],
setup(props, context) {
return {
addCount() {
props.count += 1;
context.emit('update:count', props.count);
}
}
},
以下略
コンポーネント間で状態を共有する④
コンポーネント間で状態を共有する、別の方法です。
参考:Vue.jsでコンポーネント間のデータ受け渡し(Provide/Inject) - Qiita
親コンポーネントで provide
して、子コンポーネントで inject
します。
Vue.component('v-parent', {
data() {
return {
count: 0
}
},
provide() {
return {
count: Vue.computed(() => this.count),
updateCount: (value) => this.count = value,
};
},
以下略
Vue.component('v-child', {
inject: [ 'count', 'updateCount' ],
methods: {
addCount() {
this.updateCount(this.count + 1);
}
},
以下略
Vue 3 の書き方↓
app.component('v-parent', {
data() {
return {
count: 0
}
},
provide() {
return {
count: Vue.computed(() => this.count),
updateCount: (value) => this.count = value,
};
},
以下略
app.component('v-child', {
inject: [ 'count', 'updateCount' ],
methods: {
addCount() {
this.updateCount(this.count + 1);
}
},
以下略
親コンポーネントで用意した変数 count
に対して、これを更新するメソッド updateCount
と一緒に provide
します。この変数とメソッドを、子コンポーネントで inject
して利用できるようにします。子コンポーネントで updateCount
を使って変数 count
を更新すると、親コンポーネントの count
が更新されます。