nuxt3 + typescript + vuetify

● nuxt3 + typescript + vuetifyのインストール

npx nuxi init my-app
cd my-app
yarn install

yarn add vuetify@next mdi
yarn add -D sass

npx で実行するのは nuxi です。

● tsx を使用可能にする

tsconfig.json"jsx": "preserve" を追加します

{
  // https://v3.nuxtjs.org/concepts/typescript
  "extends": "./.nuxt/tsconfig.json",
  "compilerOptions": {
    "jsx": "preserve"
  }
}

● app.vue を tsx で記述する

pages/hoge.vue

<template>
  <div>
    <h1>hoge</h1>
    <p>hogeページです</p>
  </div>
</template>

 ↓ tsx を使うと以下のように記述することができます

<script lang="tsx">
export default defineComponent({
  render() {
    return (
        <div>
          <h1>hoge</h1>
          <p>hogeページです</p>
        </div>
    )
  }
})
</script>

React開発者を Vue3 に取り込むことができます。

参考 : https://tech.andpad.co.jp/entry/2021/07/01/170000

● Composition API

Option APIの書き方

import Vue from "vue"
export default Vue.extend({
})

  ↓

<script lang="ts">
import { defineComponent } from "@vue/composition-api"
 
export default defineComponent({
  setup() {
    const { data: posts } = await useFetch('/api/posts')
  }
})
</script>

  ↓ setup() の糖衣構文が <script setup> になります。次のように記述できます。

<script setup lang="ts">
const { data: posts } = await useFetch('/api/posts')
</script>

引用 : https://zenn.dev/coedo/articles/86bc31acb4ea47

また script setup はライフサイクルでいうところの、beforeCreate と created のライフサイクルで実行されます

https://v3.ja.vuejs.org/guide/composition-api-lifecycle-hooks.html

引用 : https://bit.ly/3RXRoJ7

Composition API での従来の data は ref, reactive に置き換わります

data → ref, reactive
dataはComposition APIでrefあるいはreactiveで表現される。
refはプリミティブな値を管理し、reactiveはオブジェクトや配列を管理する。
そのため、reactiveの方が今までの使い方に近い。
ただし、refにオブジェクトや配列を渡すと、内部でreactiveが呼ばれるため問題なく使える。

https://nansystem.com/nuxt-composition-api-v2-diff/

ref , reactive の使い分け

特に使い分けるベストプラクティスがあるわけではなさそう(どちらでもご自由に。)

● ref
・プリミティブ、オブジェクト両方で使用できる
・refで定義したリアクティブな変数の値にアクセスするには.valueを使用する必要がある

● reactive
・プリミティブ値は受け取れない
・リアクティビティの消失に注意(refも同じだと思われるが。。。要検証)

https://kobatech-blog.com/vue-composition-api-ref-reactive/

● nuxt3 の useStateでグローバルかつページ遷移しても消えない状態管理

composable/useCounter.ts

import type { Ref } from 'vue'
export const inc = (counter: Ref<number>) => () => counter.value++
export const dec = (counter: Ref<number>) => () => counter.value--

export const useSharedCounter = () => {

  // ページ遷移で消えてもいい場合はこちら
  const counter = ref(0)

  // ページ遷移でも値を保持したい場合はこちら。ただし第一引数の key はユニークであること
  const counter = useState('counter', () => (0))

  return {
    counter: readonly(counter),
    dec: dec(counter),
    inc: inc(counter),
  }
}

/pages/sample.vue

<template>
    <div>
      <h1>カウンター: {{ counter }}</h1>
      <button @click="dec" style="width: 28px; height: 28px; border: 1px solid red;"> - </button>
      <button @click="inc" style="width: 28px; height: 28px; border: 1px solid red;"> + </button>
    </div>
</template>

<script setup lang="ts">
const { counter, inc, dec } = useSharedCounter()
</script>

引用元 : https://zenn.dev/coedo/articles/use-state-nuxt3

No.2217
09/21 14:57

edit

nuxt2 + typescript + vuetify

● インストール

npx create-nuxt-app my-app

vuetify を選択しておきます

yarn add --dev @nuxt/typescript-build @nuxt/types
yarn add --dev nuxt-property-decorator
yarn add --dev vue-mixin-decorator

// Vue2 の 場合は version3 を入れます
yarn add vee-validate@3

https://github.com/justrhysism/vue-mixin-decorator

nuxt.config.js に こちらが追加されています

  buildModules: [
    // https://go.nuxtjs.dev/typescript
    '@nuxt/typescript-build',
    // https://go.nuxtjs.dev/vuetify
    '@nuxtjs/vuetify',
  ],

● tsconfig.json

vuetify を追加する

    "types": ["@nuxt/types", "@nuxtjs/axios", "@types/node", "vuetify"]

● ホットリロード

nuxt.config.js

  // hot reload
  webpack: (config) => {
    config.watchOptions = {
      aggregateTimeout: 100,
      poll: 300,
      ignored: ["/node_modules/", "/.nuxt/", "/dist/"],
    }
  } ,

● テーマをデフォルト light に設定

nuxt.config.ts

dark: false にします

  vuetify: {
    customVariables: ['~/assets/variables.scss'],
    theme: {
      dark: false,

続きはこちらを行うと理解が深まります
https://tech.mof-mof.co.jp/blog/nuxt-vuetify/

nuxt/content
https://bit.ly/3DuvM2p

No.2215
09/16 15:56

edit

Vue.js 省略記法

v-bind は 「:」
v-onは「@」
v-slotは「#」
No.2181
06/30 10:33

edit

Vue.js で emit を await で待つ

callback function を利用します。 thisを利用する場合はアロー関数で記述してthisを固定しましょう。

子コンポーネント

submit() {
    this.$emit('submit', () => this.closeDialog())
},

親コンポーネント

async submit(closeDialog) {
    await this.foo1();
    await this.foo2();
    closeDialog()
}

引用 : https://bit.ly/3b4iMEy

No.2179
06/21 16:14

edit

「Vue-Router」でパラメータを直接渡したい場合

●「Vue-Router」でパラメータを直接渡したい場合

パラメーターは param , query で渡す方法がありますが、直接 query で渡したい場合(あまりないですが。。。)

<router-link to="/mypage">マイページ</router-link>

   ↓

<router-link :to="{ path: '/mypage', query: { plan: 'private' }}">
    マイページ
</router-link>

https://router.vuejs.org/api/#to

No.2176
06/16 11:55

edit

外部(html)からVue.jsのメソッドを実行する

● 外部(html)からVue.jsのメソッドを実行する

    <div id="app"></div>
    <!-- 外部からVue.jsのメソッドを実行する -->
    <script>
    document.querySelector('#app').__vue__.testMethod();
    </script>
No.2098
11/05 15:14

edit

Vue.js index.html から json で props を渡す

● Vue.js index.html から json で props を渡す

index.html

<div id="app"
    my-option='{ "styles": { "td":"width" } }'
>

main.js

    const myOption           = JSON.parse(this.$el.getAttribute('my-option'));
No.2002
05/24 18:26

edit

Vue 起動時に html から Vue コンポーネントに変数を渡す

● Vue 起動時に html から Vue コンポーネントに変数を渡す

index.html に 渡したい引数をセット

<div id="app" arg1="hoge" arg2="fuga"></div>></div>

1. まず main.js で引数を受け取る

new Vue({
  render: h => h(App),
).$mount('#app')

↓ このように書き換えます

new Vue({
  render: function(createElement) {
    const arg1 = this.$el.getAttribute('arg1')
    alert( arg1 );
    return createElement(App,
      {
        props: {
          arg1: arg1
        }
      })
  }
}).$mount('#app')

2. 次に App.vue で引数を受け取る

export default {
  name: 'App',
  components: {
    MyComponent ,
  },
  props: {
    arg1: {
      type: String,
      required: true,
    } ,
  },
  created: function () {
    alert( 'App.vue : ' + this.arg1 );
  },
}
No.1969
03/12 09:26

edit

Vue-cli でビルドするときに .js .css ファイルにランダムなハッシュ値をつけないようにする

● Vue-cli でビルドするときに .js .css ファイルにランダムなハッシュ値をつけないようにする

● 1.vue.config.js がなければ新規作成する

touch vue.config.js

● 2. vue.config.js を以下の内容にして保存します

例: sample-app.js のような命名になります。

module.exports = {
  configureWebpack: {
    output: {
      filename: 'sample-[name].js',
      chunkFilename: 'sample-[name].js'
    }
  },
  css: {
    extract: {
      filename: 'sample-[name].css',
      chunkFilename: 'sample-[name].css'
    },
  },
}

● 3. ビルドする

npm run build
No.1964
03/09 11:02

edit

実は簡単なVueの双方向( two way )バインディング

1.子コンポーネントに value という名前の Props を作成する

必ず value という名前で作成しましょう

export default {
  props: {
    value: {
      type: String,
      required: true
    }
  }
}

2.子コンポーネントに computed を作成する

export default {
  computed: {
    inputValue: {
      get() {
        return this.value; 
      },
      set(value) {
        this.$emit('input', value); 
      }
    }
  } ,
}

$emitの書式は

$emit( '任意のイベント名' )

です。

3.子コンポーネントの input タグに v-modelを指定する

  <input type="text" v-model="inputValue" />

以上です。

4.呼び出し元の親コンポーネントの v-model を指定する

<my-component v-model="item.content.value"></my-component>

引用: https://b1tblog.com/2019/10/17/vue-vscode-addons/


補足

・補足1. v-model とは何か? (答: 次の書式のシンタックスシュガーです)

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

  ↓ 同じ

<input type="text" :value="value" @input="e => value = e.target.value">
・「htmlタグのvalue」 に 変数 value の値をセットします。
・inputイベントに無名関数をセットしてその中で 変数valueに「htmlタグのvalue」をセットします。

なお、自動で付与されるイベントはhtmlタグによって異なります。

テキストと複数行テキストは、value プロパティと input イベントを使用します
チェックボックスとラジオボタンは、checked プロパティと change イベントを使用します
選択フィールドは、value プロパティと change イベントを使用します

・補足2. v-model="xxxxx" で指定する xxxxx はどこで宣言するのか?

data または computed(get() ,set() 両方指定)で宣言します。
同名で両方存在するときは data が使用されるので、同じ名前をつけるのはやめておきましょう(ややこしい)

data で変数 hoge を定義しておく

  data(){
    return {
      hoge: 1 ,
    }
  },

computed で変数 hoge を定義しておく
ゲッター(アクセサ)、セッター(ミューテータ) 、両方定義しておきましょう。

  computed: {
    hoge: {
      get() {
        return this.$store.state.myState.hoge;
      },
      set(value) {
        const key = 'hoge';
        this.$store.commit('myState',[key,value]);
      }
    }
  },

Vue3 での違いについて

https://v3.ja.vuejs.org/guide/migration/v-model.html#はじめに

2.x では、コンポーネントで v-model を使うことは、value プロパティを渡して input イベントを発火することと同じでした。

<ChildComponent v-model="pageTitle" />
<!-- これは下記の省略形です -->
<ChildComponent :value="pageTitle" @input="pageTitle = $event" />
No.1959
05/06 09:44

edit

vue draggable

● vue draggableのインストール

インストール

yarn add vuedraggable

cssがめんどくさい場合は bootstrapも入れておきましょう

yarn add bootstrap-vue

コレクションの操作がめんどくさい場合は lodashも入れておきましょう

yarn add lodash
yarn add @types/lodash

xhr を使用するときは axios も入れておきましょう

yarn add axios

main.js に 以下も追加します

import Axios from 'axios'
Vue.use(Axios)

● TypeScript用 ファイルの作成

mkdir src/types
vi src/types/vuedraggable.d.ts

src/types/vuedraggable.d.ts

declare module 'vuedraggable'

● 片方のリストからもう片方のリストコピーをさせる

コピーをさせたいリストを次のように変更します

    <draggable
      group="items"
    >

    <draggable 
      :group="{ name: 'items', pull: 'clone', put: false }"
    >
No.1958
03/05 22:32

edit

vue.js で ng-container のように非表示なタグを使用する

● templateを使用します

<template v-if="data == 'aaa' ">
   <img src="cool-img" alt="awesome">
   <h1>AAA</h1>
   <p>Cool Text AAA</p>
</template>
<template v-else-if="data == 'bbb' ">
   <img src="cool-img" alt="awesome">
   <h1>BBB</h1>
   <p>Cool Text BBB</p>
</template>

● テンプレートで switch を使用したいときはこちらを使います

https://www.npmjs.com/package/v-switch-case

No.1947
03/02 15:01

edit

vue.js 3 + TypeScript 環境を作成する

1. Vue CLI をインストールします

npm install --global @vue/cli

一度ターミナルを再起動してから

バージョンの確認

vue -V
@vue/cli 4.5.11

2. 新規のプロジェクトを作成し、続いて "Manually select features" を選択します

vue create my-project-name

Typescript を利用するために Manually select features を選択します。

3. ローカルサーバー起動

cd my-project-name
npm run serve

4. ビルド

dist フォルダにビルド結果が出力されます

npm run build

5. ローカルファイルを表示した場合画面が真っ白になる場合は相対パスを指定します

vue 2 の場合は

vue.config.js

module.exports = {
    publicPath: './'
}

vue 3 の場合は 

vue.config.js

module.exports = {
    baseUrl: './'
}

● 「Vue.extend」と「クラスコンポーネント」どちらで書くかを決定する

クラスコンポーネントのがおすすめですが、こちらを参考に決定するといいでしょう。↓

https://zenn.dev/kata_n/articles/233ee8e03c5cb1
https://qiita.com/aLiz/items/5f7cab2b86116b496586
https://meetup-jp.toast.com/1843

● 「Vue.extend」→「クラスコンポーネント」変換する

基本形

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { Component, Vue } from 'nuxt-property-decorator' // nuxtの場合

@Component
export default class extends Vue {

}
</script>

あとは、こちらを参考に。
https://qiita.com/ryo2132/items/4d43209ea89ad1297426#created-mounted-updated-destroyed-etc

No.1946
09/15 16:22

edit

vue.js の v-if を使った時の「Cannot read property ..... of undefined"」エラーに対処する

● vue.js の「Cannot read property ..... of undefined"」エラーに対処する

これはオブジェクトが undefined なのに、オブジェクトのメンバ変数にアクセスしようとした時によくおこります。
次のようにあらかじめ存在チェックを入れて回避しましょう。

{{ props.row.client.tel }}

  ↓ ( v-if を使って props.row.client の存在を確認する )

<span v-if="props.row.client">{{ props.row.client.tel }}</span>

● オブジェクトの中身がある場合の v-if

(例: projects の中身が3つ以上ある場合 )

<li v-if="props.row.projects.length > 2">

 ↓ エラーが出る場合はこのように書き換えます

<li v-if="props.row.projects && props.row.projects.length > 2">

参考 : https://bit.ly/2NPKyWB

No.1770
07/03 11:28

edit

Nuxt.js による静的サイト制作

● yarn のインストール

npm install -g yarn

● nuxt.js サイトの新規作成

プロジェクト名を mysite としています。

yarn create nuxt-app mysite

● サイトの起動

cd mysite
yarn dev

http://localhost:3000/
でサイトにアクセスできるようになります。

● ページの追加

pages ディレクトリの中に works ディレクトリを作成して 1001.vue を次の内容で保存します。

<template>
  <div>
アイウエオ
  </div>
</template>

http://localhost:3000/works/1001
でアクセスできるようになります。

● 静的サイトを htmlに書き出し

yarn generate

dist/ ディレクトリが作成されてそこに書き出されます。

No.1688
02/04 10:46

edit

vue.js で エスケープしない記法 「 v-html=メソッド() 」「v-html=パラメータ名」

● vue.js で エスケープしない記法 「v-html=メソッド名()」

<div v-html="my_calc(props.row.sum_no)"></div>

  ↑

props.row.sum_no を my_calc メソッドを通した結果を エスケープせずに表示します

● vue.js で エスケープしない記法 「v-html=パラメータ名」

<span v-html="rawHtml"></span>

  ↑

この span のコンテンツは rawHtml プロパティの値に置き換えられ、プレーンな HTML として解釈されます。
No.1463
06/30 23:16

edit

vue.js の wysiwygエディタ

● vue-html-editor

http://haixing-hu.github.io/vue-html-editor/

jQueryのsummer note の vue.js移植版

● toast-ui.vue-editor

https://github.com/nhnent/toast-ui.vue-editor

添付ファイル1
No.1399
12/21 11:04

edit

添付ファイル

vue.js レンダリング前 のテンプレートや変数を見せないようにする

・cssを作成する

[v-cloak] {
  display: none;
}

・見せたくない要素に v-cloak をつける

<div v-cloak>

これだけでレンダリング前は非表示にして、レンダリング後に自動的に表示されるようになります。

No.1340
11/01 10:31

edit

transition-groupでリストにtransitionアニメーションをつける

● transition-groupでリストでデータを作成、削除した時に、transitionアニメーションをつける

・アニメーションさせたいリスト全体を<transition-group>タグで囲います

<transition-group>
    <div v-for="v,i in data_loop" :key="v.id">
        (% v.tanto_name %)
    </div>
</transition-group>

 ↓ これはレンダリングするとこのようになります

<span>
<div>担当者A</div>
<div>担当者B</div>
<div>担当者C</div>
</span>

transition-group タグspan タグ に変わります

任意のタグにするには

<transition-group>

 ↓

<transition-group tag="div">

とします。(div タグになります)

・アニメーション用のCSSを用意する

.v-enter-active, .v-leave-active {
  transition: opacity 1s;
}
.v-enter, .v-leave-to {
  opacity: 0;
}

以上で vue.js のデータを削除した時にアニメーションがつけられます。 簡単ですね。

拡張は色々できます。

公式ドキュメント参照
https://jp.vuejs.org/v2/guide/transitions.html

No.1339
11/01 10:19

edit

Vue.js で 数字に3桁ごとにカンマをつけるフィルター「number_format」を作成する

● Vue.js でフィルターを作成する

数字に3桁ごとにカンマをつけるフィルター「number_format」を作成する

Vue.filter('number_format', function (value) {
    if (! value) { return false; }
    return value.toString().replace( /([0-9]+?)(?=(?:[0-9]{3})+$)/g , '$1,' );
});

● Vue.js で使用する

よくあるテンプレートのフィルターと同じ書き方で使えます。

{{ props.row.price_with_shipping_no|number_format }}
{{ 123456789 | number_format }}
No.1335
10/30 17:22

edit