29
24

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Vue.js+TypeScriptでコンポーネントをv-modelでつなげてみる

Last updated at Posted at 2018-09-03

概要

以下の記事でやり方がわかったので、TypeScriptでどう書くかまとめてみました。

vueでv-modelをネストして使いたい
https://qiita.com/xsota/items/010e7116c895b782b7a4

準備

Vue-Cliで環境を作ります。

GitHubに利用したプロジェクトをUPしています。実際に試してみたい方どうぞ^^
https://github.com/kai-kou/vue-js-typescript-nest-v-model

ここではDockerを利用して環境構築していますが、ローカルで構築してもらってもOKです。

> mkdir 任意のディレクトリ
> cd 任意のディレクトリ
> vi Dockerfile
> vi docker-compose.yml
Dockerfile
FROM node:10.8.0-stretch

RUN npm install --global @vue/cli

WORKDIR /projects
docker-compose.yml
version: '3'

services:
  app:
    build: .
    ports:
      - "8080:8080"
    volumes:
      - ".:/projects"
    tty: true
> docker-compose up -d
> docker-compose exec app bash
コンテナ内
> vue create app

Vue CLI v3.0.1
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, TS, Linter
? Use class-style component syntax? Yes
? Use Babel alongside TypeScript for auto-detected polyfills? Yes
? Pick a linter / formatter config: TSLint
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
? Pick the package manager to use when installing dependencies: (Use arrow keys)
❯ Use Yarn
  Use NPM
コンテナ内
> cd app
> yarn serve

これで実装の準備が整いました。

親コンポーネントに子コンポーネントを追加する

今回はVue-Cliでプロジェクト作成時に含まれているHelloWorldコンポーネントに子コンポーネントを足してみます。

> touch src/components/ChildComponent.vue
> vi src/components/ChildComponent.vue
src/components/ChildComponent.vue
<template>
  <input type="text" v-model="localValue"/>
</template>

<script lang="ts">
  import {
    Component,
    Emit,
    Prop,
    Vue,
  } from 'vue-property-decorator';
  
  @Component
  export default class ChildComponent extends Vue {
    @Prop() public value!: string;

    @Emit()
    public input(value: string) {}

    private get localValue(): string {
      return this.value;
    }

    private set localValue(value: string) {
      this.input(value);
    }
  }
</script>

親から受け取るvalue を直接v-model に指定できないので、get、setプロパティを間に挟んで、set時にEmit してあげるわけですね。
へぇ。わかれば簡単。

注意点はvalue プロパティとinput メソッド名を変更するとだめ。ってところでしょうか。

Vue.js:v-modelと$emitを使ってデータを読み書きする子コンポーネントをつくる
https://qiita.com/ozone/items/b75efe5c449cbc469b1e

公式で以前読んだはずなのにすっかり忘れていたのですが、v-modelは実はただの糖衣構文。:value(prop)と@input(event)に展開して扱われます。

だそうです。

では、HelloWorldコンポーネントも変更します。
msg プロパティをv-model で取り扱えるようにvalue に変更します。
こちらもvalue を直接v-model に設定せず、get、setプロパティを間に挟みます。

src/components/HelloWorld.vue
<template>
  <div class="hello">
    <child-component v-model="localValue"/>
    <h1>{{ value }}</h1>
    (略)
  </div>
</template>

<script lang="ts">
import { Component, Emit, Prop, Vue } from 'vue-property-decorator';
import ChildComponent from './components/ChildComponent.vue';

@Component({
  components: { ChildComponent },
})
export default class HelloWorld extends Vue {
  @Prop() private value!: string;

  @Emit()
  public input(value: string) {}

  private get localValue(): string {
    return this.value;
  }

  private set localValue(value: string) {
    this.input(value);
  }
}
</script>
(略)

最後にApp.vueを変更します。HelloWorldコンポーネントのmsg プロパティがなくなったので、v-model に変更します。

src/App.vue
<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <HelloWorld v-model="msg"/>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import HelloWorld from './components/HelloWorld.vue';

@Component({
  components: {
    HelloWorld,
  },
})
export default class App extends Vue {
  private msg = 'Welcome to Your Vue.js + TypeScript App';
}
</script>
(略)

確認

ではブラウザで確認してみましょう。
テキストボックスの内容を変更すると、ちゃんと反映されると思います。
スクリーンショット 2018-08-28 17.54.18.png

get、setプロパティを挟むのが手間ですが、まあまあ良いのではないでしょうか。

参考

vueでv-modelをネストして使いたい
https://qiita.com/xsota/items/010e7116c895b782b7a4

Vue.js:v-modelと$emitを使ってデータを読み書きする子コンポーネントをつくる
https://qiita.com/ozone/items/b75efe5c449cbc469b1e

Vue.js+TypeScriptで開発するときの参考記事まとめ
https://qiita.com/kai_kou/items/19b494a41023d84bacc7

29
24
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
24

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?