vue nuxt 個人メモ

#vue nuxt 個人メモ

## データセット

dataメソッドで行う

```index.vue
<script>
export default Vue.extend({
  data() {
    return {
      modal: false,
      email: '',
      password: ''
    }
  }
})
</script>
```

## ハンドラー、イベント

methodsで行う

```vuejs:index.vue
<script>
export default Vue.extend({
  data() {
    return {
      modal: false,
      email: '',
      password: ''
    }
  },
  methods: {
    openModal() {
      this.modal = true
    },
    closeModal() {
      this.modal = false
    }
  }
})
</script>
```

## api取得 ライフサイクル

画面の描画前にデータを取得する場合 `asyncData`

画面の描画後にデータを取得する場合 `mounted`


```vue:index.vue
<script>
export default Vue.extend({
  data() {
    return {
      modal: false,
      email: '',
      password: ''
    }
  },
  async asyncData({ query, params, $axios }) {
    try {
      const response = await $axios
        .$get(
          `/api/~~${query.id}`,
          {...params},
          { withCredentials: true }
        )
        .catch((error) => error.response)
      if (response === undefined) {
        throw new Error('undefined')
      }
      if (response.status !== 'success') {
        throw new Error(response.data.message)
      }
      return { error: false }
    } catch (error) {
      console.error(error.message)
      return { error: true }
    }
  },
  async mounted() {
    await this.getAPI()
  }
})
</script>
```

大きな違いはSSRで画面を表示するかどうか？？
https://medium.com/veltra-engineering/in-ssr-vue-js-is-created-twice-7f9122de9b77

Nuxtでは特にユニバーサルなコードを書くことを意識するのが重要なので、
違いを理解する必要がある(まだ理解してない)



## props

v-forなどでデータを渡す際はv-bindでそのまま渡す

```vue:index.vue
  <ul>
    <ListData
      v-for="item in data"
      :key="item.id"
      v-bind="item"
    />
  </ul>

```

渡されたデータがスネークケースの場合で、
キャメルケースに変換したい場合はハイフンでつなぐ

```vue:index.vue
  <ul>
    <ListData
      v-for="item in data"
      :key="item.id"
      :index="index + 1"
      :start-date="item.start_date"
      :end-date="item.end_date"
    />
  </ul>

```

## watch method

dataで定義した値に変更が加わった時にフックして処理を実行したい場合などに使う



```vue

<script>
export default {
  props: {
    id: {
      type: Number,
      default: 0
    }
  },
  data() {
    return {
      value: ''
    }
  },
  watch: {
    value(newValue, oldValue) {
      console.log(
    },
    id(newValue, oldValue) {
      console.log(
    }
  }
}
</script>
```

## nuxt link

`to=""` でリンク先を指定するけど
変数を入れたい場合など

```vue

:to="`/myPage/${user.id}`"
```

## 親から子へ渡す props


### 親コンポーネント

書き方は下記

```vuejs

<template>
  <Child hoge1="ABC" hoge2="DEF"> 
</template>
```

値が変動する場合はデータバインドで渡す

```vuejs

<template>
  <Child :hoge1="dat1" :hoge2="dat2">
</template>
```

### 子コンポーネント

配列形式で受けとる場合

```vue

<script>
export default {
  props: ['hoge1', 'hoge2']
}
</script>
```

オブジェクトで受け取る場合

```vue

<script>
export default {
  props: {
    hoge1: {
      type: String,
      default: 'abc',
      required: true
    },
    hoge2: {
      type: String,
      default: '',
      required: false
    }
  }
}
</script>
```

## 子から親に伝達するemit


`v-on:`または`@`でイベントを紐づける

```vue:親コンポーネント

<Child  @click="onClick">

<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
  methods: {
    onClick(e: Event) {
      e.preventDefault()
      console.log(e)
    }
  }
})
</script>
```

```vue:子コンポーネント

<template>
    <button
      type="button"
      @click="$emit('click')"
    />
</template>
```

```vue:methodsなどで使用する場合

<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
  methods: {
    onClick(e: Event) {
      e.preventDefault()
      this.$emit('click')
      this.$emit('click', e) // 引数を渡す場合は第二引数
    }
  }
})
</script>
```

## `@click`に引数を渡す
忘れガチなのでメモ


```vue

<template>
  <div id="app">
    <button @click="click">button</button>
    <button @click="superClick('引数です')">param button</button>
  </div>
</template>

<script>
export default {
  methods: {
    superClick(value) {
      alert(value);
    }
  }
};
```

## propsType

Typescript interface でpropsの受け取る型を指定


```vuejs:index.vue
<script lang="ts">
interface Schedule {
  id: Number,
  startDate: String,
  endDate: String,
  deliveryType: Number,
  afterTalkFlag: Number
}


export default Vue.extend({
  props: {
    userName: String,
    schedule: {
      type: Object as PropType<Schedule>,
      default: null
    }
  }
})
</script>
```

## nuxt での form入力

### input checkbox

まずデータを用意

```vuejs

<script>
export default {
  data() {
    return {
      dataList: [  // api から取得してきたデータ
        {name: "hoge"},
        {name: "fuga"},
        {name: "fugafuga"}
      ],
      formData: [] // form送信用
    }
  }
}
</script>
```

用意したデータをバインドする


```vue

<template>
  <div
    v-for="(item, index) in dataList"
    :key="'dataItem' + index"
  >
    <input
      :id="'dataItem_' + item.name"
      type="checkbox"
      :value="item.name"
      v-model="formData"
      name="'dataItem_' + item.name"
    />
    <label :for="'dataItem_' + item.name">
      {{ item.name }}
    </label>
  </div>
</template>
```

### デフォルトでチェックを入れる場合

デフォルトでチェックを入れる場合はv-modelで紐付ける
form送信用のdataオブジェクトに初期値をセットする

```vue

<script>
export default {
  data() {
    return {
      dataList: [  // api から取得してきたデータ
        {
          name: "hoge",
          value: true
        },
        {
          name: "fuga",
          value: true
        },
        {
          name: "hogege",
          value: false
        }
      ],
      formData: [] // form送信用
    }
  },
  mounted() {
    this.formData = this.dataList.map((item: any) => item.value)
  }
}
</script>
```


## 子のプロパティまたはメソッドを参照する(refs)

親のresetボタンを押した際に、子供のフォームの内容をresetする場合など


```ChildForm.vue

<script>
export default {
  name: 'ChildForm',
  data() {
    value: ''
  },
  methods: {
    onClear() {
      this.value = ''
    }
  }
}
</script>
```

```parent.vue
<template>
  <div>
    <ChildForm ref="childForm"/>
    <button @click="clear">
      Clear
    </base-button>
  </div>
</template>

<script>
import ChildForm from '@/components/ChildForm.vue'

export default {
  components: ChildForm,
  methods: {
    clear() {
      this.$refs.childForm.onClear()
    }
  }
}
</script>
```

## v-for での特定回数の繰り返し

記事データを表示する際、1 ~ 10 件のデータを表示する場合がある
他に、ページャーなどの機能で配列の10 ~ 20件の間のデータを抽出したいなど
`v-for`に整数値を与えることで繰り返しの回数を制御できるがそれだと実現したい機能とは違うのでまとめておく

```vuejs
<template>
  <div v-for="item in pages">
    <div>{{ item.name }}</div>
    <div>{{ item.age }}</div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      currentPage: 1, //現在のページ
      pageLimit: 50,  // 表示できるページ数
      limitItem: 10, // 表示できる要素数
      customerList: [
        { id:1, name: 'hoge', age: 20 },
        { id:2, name: 'fuga', age: 22 },
        { id:3, name: 'aaaa', age: 30 },
        { id:4, name: 'fugafuga', age: 10 }
        // 以降 200件のデータが続く
      ]
    }
  },
  computed: {
    pages() {
      const maxItem = Number(this.itemLimit)
      const start = this.currentPage === 1 ? 0 : (this.currentPage - 1) * maxItem
      const end = this.currentPage === 1 ? maxItem : this.currentPage * maxItem
      return this.customerList.filter((_element, index) => {
        return index >= start && index < end
      })
    }
  }
}
</script>
```