20211015のvue.jsに関する記事は7件です。

【Vue.js】v-onについて

はじめに こんにちは! 松本 佑大(まつもと ゆうだい)と申します! 今回はv-onについてアウトプットしていきます! v-onとは v-onとはボタンをクリックしたり、スクロールなどのユーザーによる一連の挙動を『イベント』と呼びます。そして、それら様々なイベントに対応して発動させる処理のこと(関数)を『イベントハンドラ』と呼びます。 Vue.jsにおいて、イベントによってイベントハンドラを実行させるには、v-onを使用します。 書き方 今回はボタンclick!を押したら、現在の日時が表示されるプログラムを実行していきます。 HTML <button v-on:click="Onclick"> Click! </button> <p> {{ now }} </p> Vue.js var app = new Vue({ el:'#app', data:{ now='' } methods: { Onclick: function() { this.now = new Date().toLocaleString(); } } }) dataオプションにnowプロパティ(p要素と同じもの)を設置します。 イベントハンドラのメソッドmethodsを定義していきます。内容は、”ボタンをクリックしたらdataのnowに現在時刻を代入する”というふうにします。それが上記になります。 それをp要素 {{now}}とHTMLに記述すれば出力されます。 出力結果が画像のようになります。 ポイントまとめ ・<button v-on:〇〇="〇〇〇">を記述 ・<p>{{〇}}</p>を記述 ・メソッドmethodsを定義し関数の処理を書く。 ・dataに{{〇}}と共通のプロパティを記述する 最後に 今回はv-onについてアウトプットしました。 今回の記事を読んで気になったこと、質問等あればコメント等頂けると幸いです。 今後ともQiitaにてアウトプットしていきます! 最後までご愛読ありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JSでクラスの位置を取得する

nanikaはClass名 targetをconsole.log()で見てみると、offsetTopとoffsetLeftで位置が確認できる scrollTab (): void { const target: any = document.getElementsByClassName('nanika'); window.scrollTo({ top: target[0].offsetTop, left: target[0].offsetLeft, behavior: 'smooth' }) }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

kintoneプラグインの設定画面を作る

前回は、webpack-plugin-kintone-pluginを使ってサンプルプラグインをビルドして使えるようにするまでのお話でした。 今回は、kintoneプラグインの設定画面を Vue.js を使う方法と、kintone UI Component を使う方法の2通りのやり方で作ってみたいと思います。 Vue.jsを使って設定画面を作る まず、manifest.json ファイルの config の js に Vue の CDN "https://unpkg.com/vue@next" を追加します。 manifest.json "config": { "html": "html/config.html", "js": [ "https://unpkg.com/vue@next", "js/dist/config.js" ], "css": ["css/config.css"], "required_params": ["message"] }, htmlファイルの編集 config.htmlを編集します。 config.html <div id="app"> <label for="msg">表示したい文字列:</label> <input type="text" id="msg" v-model="myMessage"> <button @click="register">登録</button> </div> jsファイルの編集 config.js を編集します。 kintone プラグイン開発手順によると、 ↓こんな感じのお作法があるようです。 ((PLUGIN_ID) => { // 設定更新するプログラムをかく })(kintone.$PLUGIN_ID); APIはこんな感じで使います。 プラグインの設定を読み込む kintone.plugin.app.getConfig(PLUGIN_ID) プラグインの設定を更新する kintone.plugin.app.setConfig(param, callback) 設定のsetConfigで送信する param の中身は manifest.json で設定している "required_params": ["message"] です。 const param = { message: this.myMessage }; こんなふうに作成しましょう。 config.js ((PLUGIN_ID) => { "use strict"; // 設定を読み込む const config = kintone.plugin.app.getConfig(PLUGIN_ID); const app = Vue.createApp({ data() { // 初期表示は設定内容通りに表示する。 return { myMessage: config.message }; }, methods: { // 登録ボタン(htmlの方で作成)をクリックしたら設定を登録する register() { const param = { message: this.myMessage }; // 設定を登録する kintone.plugin.app.setConfig(param, () => { alert("登録しました"); // プラグイン一覧画面に移動する window.location.href = "../../" + kintone.app.getId() + "/plugin/#/"; }); }, }, }); const vm = app.mount("#app"); })(kintone.$PLUGIN_ID); 結果 cssを適用していないこともあり質素な感じになりましたが、動作には問題ありません。 kintoneぽくしたい場合は↓こちらを忍ばせてください。 kintoneライクなスタイルシートの利用 kintone UI Component を使って設定画面を作る npmでパッケージをインストールする方法 もありますが、今回はCDNを使ってみます。 manifest.json ファイルの config の js に kintone UI Component の CDN "https://unpkg.com/kintone-ui-component/umd/kuc.min.js" を追加します。 manifest.json "config": { "html": "html/config.html", "js": [ "https://unpkg.com/kintone-ui-component/umd/kuc.min.js", "js/dist/config.js" ], "css": ["css/config.css"], "required_params": ["message"] }, htmlファイルの編集 htmlは次の一行だけです。 config.html <div id="sp"></div> jsファイルの編集 ※テキストボックスだとサイズ変えられなかったのでテキストエリアにしました^^; ((PLUGIN_ID) => { "use strict"; // 設定内容取得 const config = kintone.plugin.app.getConfig(PLUGIN_ID); // テキストエリア作成 const text = new Kuc.TextArea({ label: "表示したい文字列", value: config.message, // 初期表示は設定内容 }); // ボタン作成 const button = new Kuc.Button({ text: "登録", type: "submit", }); // divを取得 const sp = document.getElementById("sp"); // テキストエリア配置 sp.appendChild(text); // 改行配置 const br = document.createElement("br"); sp.appendChild(br); // ボタン配置 sp.appendChild(button); // ボタンクリックで設定登録 button.addEventListener("click", (event) => { const param = { message: text.value }; kintone.plugin.app.setConfig(param, function () { alert("登録しました"); window.location.href = "../../" + kintone.app.getId() + "/plugin/#/"; }); }); })(kintone.$PLUGIN_ID); 結果 kintone UI Component だと CSS を気にせずに kintone ぽくできるので、個人的にはVue.jsよりもkintone UI Componentの方が好きだったりします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[WebRTC] Vue.jsとFirebaseでWebRTC簡単入門

はじめに 先日のハッカソン型インターンで使用したWebRTCという技術がとても興味深くまたFirebaseを用いることで簡単に実装ができたのでVue.jsとFirebaseを用いたWebRTCの実装方法を紹介します。 Demo、Githubは下記からアクセスできます。 Demo: https://webrtcqiita.web.app/ Github: https://github.com/hond0413/webrtc WebRTCとは WebRTCはビデオ、音声、及び一般的なデータをPeer間で送信することをサポートしたものです。全てのモダンブラウザと、主要プラットフォームのネイティブクライアントで利用可能です。 https://webrtc.org/ 準備 Vue: 2.6.11 Firebase: 8.1.1 Vueプロジェクトの作成 初めに下記手順でVueプロジェクトを作成します。vue-cliを用いたプロジェクトの作成方法を理解している方はvue-router、Vuetifyの設定をしてFirebase、Firestoreの設定まで飛ばしてもらって大丈夫です。 $ cd [working directory] $ vue create [project name] 下記のように表示されるので vue-router導入のためManually select featuresを選択してください。 ? Please pick a preset: Default ([Vue 2] babel, eslint) Default (Vue 3 Preview) ([Vue 3] babel, eslint) ❯ Manually select features 下記のように表示されるのでRouterを追加で選択してください。 ? Check the features needed for your project: ◉ Choose Vue version ◉ Babel ◯ TypeScript ◯ Progressive Web App (PWA) Support ❯◉ Router ◯ Vuex ◯ CSS Pre-processors ◉ Linter / Formatter ◯ Unit Testing ◯ E2E Testing 今回はVue2を使用しているため2.xを選択してください。 ? Choose a version of Vue.js that you want to start the project with (Use arrow keys) ❯ 2.x 3.x (Preview) 今回はどちらを選択しても問題はありませんがhistoryを使用します。 ? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n) Lintもデフォルトのもので問題ありません。 ? Pick a linter / formatter config: (Use arrow keys) ❯ ESLint with error prevention only ESLint + Airbnb config ESLint + Standard config ESLint + Prettier 下記もEnterで大丈夫です。 ? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i > to invert selection) ❯◉ Lint on save ◯ Lint and fix on commit 下記もEnterで大丈夫です。 ? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys) ❯ In dedicated config files In package.json 設定を保存する必要はないのでNで次に進みます。 ? Save this as a preset for future projects? (y/N) 最後にVueプロジェクトの作成が成功したら下記のように表示されるのでプロジェクトディレクトリに移動してVuetifyを追加しましょう。 13 packages are looking for funding run `npm fund` for details ⚓ Running completion hooks... ? Generating README.md... ? Successfully created project test. ? Get started with the following commands: $ cd [project name] $ npm run serve $ cd [project name] $ vue add vuetify vuetifyの設定はEnterで問題ありません。 Firebase、Firestoreの設定 Firebase及びFirestoreの設定は下記記事がとても参考になるので参照してください。 https://qiita.com/Dchi412/items/e0859e5df65de6f78591 事前にFirestoreに"calls"という名前のcollectionを追加しておいてください。 .envファイルの設定 vueのプロジェクトディレクトリ直下に.envファイルを設けそこにFirebaseのSDKを設定してください。デフォルトで.envは.gitignoreに追加されていないので追加することを強くお勧めします。 .env VUE_APP_API_KEY=**************** VUE_APP_AUTH_DOMAIN=**************** VUE_APP_DATABASE_URL=**************** VUE_APP_PROJECT_ID=**************** VUE_APP_STORAGE_BUCKET=**************** VUE_APP_MESSAGING_SENDER_ID=**************** VUE_APP_ID=**************** VUE_APP_MEASUREMENT_ID=**************** main.tsの設定 今回はFirebaseのSDKを環境変数として定義したためmain.tsのfirebaseConfigでは環境変数を呼び出します。 main.ts import Vue from 'vue' import App from './App.vue' import router from './router' import store from './store' Vue.config.productionTip = false import firebase from 'firebase' import vuetify from './plugins/vuetify' const firebaseConfig = { apiKey: process.env.VUE_APP_API_KEY, authDomain: process.env.VUE_APP_AUTH_DOMAIN, databaseURL: process.env.VUE_APP_DATABASE_URL, projectId: process.env.VUE_APP_PROJECT_ID, storageBucket: process.env.VUE_APP_STORAGE_BUCKET, messagingSenderId: process.env.VUE_APP_MESSAGING_SENDER_ID, appId: process.env.VUE_APP_APP_ID, measurementId: process.env.VUE_APP_MEASUREMENT_ID }; // Initialize Firebase if (!firebase.apps.length) { firebase.initializeApp(firebaseConfig) } new Vue({ router, store, vuetify, render: h => h(App) }).$mount('#app') componentの作成 以下よりVueプロジェクトのcomponentのコードの詳細を解説します。 WebRTC component WebRTCの処理を行うcomponentは以下のようになっております。コード全体下に主要部の解説します。 WebRTC.vue <template> <div> <v-row> <v-col> <video class="media_v" id="webcamVideo" autoplay playsinline></video> </v-col> <v-col> <video class="media_v" id="remoteVideo" autoplay playsinline></video> </v-col> </v-row> </div> </template> <script> import firebase from "firebase" import "firebase/firestore" export default { name: "Webrtc", data () { return { db: null, servers: { iceServers: [ { urls: [ "stun:stun1.l.google.com:19302", ], }, ], iceCandidatePoolSize: 10, }, localStream: null, remoteStream: null, pc: null, webcamVideo: null, remoteVideo: null, } }, async created() { this.db = firebase.firestore() await this.startWebcam(); const name = this.$route.query.name if (name) { await this.createCall(); } else { await this.answerBtn(this.$route.query.id); } }, mounted() { this.pc = new RTCPeerConnection(this.servers); this.webcamVideo = document.getElementById("webcamVideo"); this.remoteVideo = document.getElementById("remoteVideo"); }, methods: { async startWebcam() { this.localStream = await navigator.mediaDevices.getUserMedia({ video: true, // audio: true, }). catch(error => { console.error("can't connect mediadevices") }) this.remoteStream = new MediaStream(); this.localStream.getTracks().forEach((track) => { this.pc.addTrack(track, this.localStream); }); this.pc.ontrack = (event) => { console.log(event) event.streams[0].getTracks().forEach((track) => { this.remoteStream.addTrack(track); }); }; this.webcamVideo.srcObject = this.localStream; this.remoteVideo.srcObject = this.remoteStream; }, async createCall() { const callDoc = this.db.collection("calls").doc(); const offerCandidates = callDoc.collection("offerCandidates"); const answerCandidates = callDoc.collection("answerCandidates"); this.pc.onicecandidate = (event) => { event.candidate && offerCandidates.add(event.candidate.toJSON()); }; const offerDescription = await this.pc.createOffer(); await this.pc.setLocalDescription(offerDescription); const offer = { sdp: offerDescription.sdp, type: offerDescription.type, }; await callDoc.set({offer}); await callDoc.update({ name: this.$route.query.name }); callDoc.onSnapshot((snapshot) => { const data = snapshot.data(); if (!this.pc.currentRemoteDescription && data?.answer) { const answerDescription = new RTCSessionDescription(data.answer); this.pc.setRemoteDescription(answerDescription); } }); answerCandidates.onSnapshot((snapshot) => { snapshot.docChanges().forEach((change) => { if (change.type === "added") { const candidate = new RTCIceCandidate(change.doc.data()); this.pc.addIceCandidate(candidate); } }); }); }, async answerBtn(val) { const callDoc = this.db.collection("calls").doc(val); const answerCandidates = callDoc.collection("answerCandidates"); const offerCandidates = callDoc.collection("offerCandidates"); this.pc.onicecandidate = (event) => { event.candidate && answerCandidates.add(event.candidate.toJSON()); }; const callData = (await callDoc.get()).data(); const offerDescription = callData.offer; await this.pc.setRemoteDescription( new RTCSessionDescription(offerDescription) ); const answerDescription = await this.pc.createAnswer(); await this.pc.setLocalDescription(answerDescription); const answer = { type: answerDescription.type, sdp: answerDescription.sdp, }; await callDoc.update({ answer }); offerCandidates.onSnapshot((snapshot) => { snapshot.docChanges().forEach((change) => { if (change.type === "added") { let data = change.doc.data(); this.pc.addIceCandidate(new RTCIceCandidate(data)); } }); }); } } } </script> WebRTC コネクションの実現 RTCPeerConnectionインターフェイスを使用してWebRTC コネクションを表現します。 WebRTC.vue mounted() { this.pc = new RTCPeerConnection(this.servers); <--省略--> } RTCPeerConnectionに関する詳しい情報は下記を参照すると良いです。 https://developer.mozilla.org/ja/docs/Web/API/RTCPeerConnection startWebcam method 下記コードでメディアデバイスの設定をすることでwebカメラを用いた通信を可能にしています。 WebRTC.vue async startWebcam() { this.localStream = await navigator.mediaDevices.getUserMedia({ video: true, // audio: true, }). catch(error => { console.error("can't connect mediadevices") }) this.remoteStream = new MediaStream(); this.localStream.getTracks().forEach((track) => { this.pc.addTrack(track, this.localStream); }); this.pc.ontrack = (event) => { console.log(event) event.streams[0].getTracks().forEach((track) => { this.remoteStream.addTrack(track); }); }; this.webcamVideo.srcObject = this.localStream; this.remoteVideo.srcObject = this.remoteStream; }, 下記コードでメディアデバイスの検出設定を行っています。自分のローカル環境で二つのタブを開いてWebRTCのテストを行う場合audioを使用しているとハウリングの原因となるためコメントアウトしています。実際にaudioを利用して遠くの方と通話を行いたい方はコメントアウトを解除して実装してもらうと可能になります。 WebRTC.vue this.localStream = await navigator.mediaDevices.getUserMedia({ video: true, // audio: true, }). 先ほど登録したtracksを取得してpeer connectionにセットします。 WebRTC.vue this.localStream.getTracks().forEach((track) => { this.pc.addTrack(track, this.localStream); }); peer connectionから通信相手のtracksを取得してremote streamに追加します。 WebRTC.vue this.pc.ontrack = (event) => { console.log(event) event.streams[0].getTracks().forEach((track) => { this.remoteStream.addTrack(track); }); }; createCall method 下記コードではホスト側(ルーム作成側)の処理を行なっています。 WebRTC.vue async createCall() { const callDoc = this.db.collection("calls").doc(); const offerCandidates = callDoc.collection("offerCandidates"); const answerCandidates = callDoc.collection("answerCandidates"); this.pc.onicecandidate = (event) => { event.candidate && offerCandidates.add(event.candidate.toJSON()); }; const offerDescription = await this.pc.createOffer(); await this.pc.setLocalDescription(offerDescription); const offer = { sdp: offerDescription.sdp, type: offerDescription.type, }; await callDoc.set({offer}); await callDoc.update({ name: this.$route.query.name }); callDoc.onSnapshot((snapshot) => { const data = snapshot.data(); if (!this.pc.currentRemoteDescription && data?.answer) { const answerDescription = new RTCSessionDescription(data.answer); this.pc.setRemoteDescription(answerDescription); } }); answerCandidates.onSnapshot((snapshot) => { snapshot.docChanges().forEach((change) => { if (change.type === "added") { const candidate = new RTCIceCandidate(change.doc.data()); this.pc.addIceCandidate(candidate); } }); }); }, 下記コードで事前に準備しておいた"calls" collectionにdocumentを追加します。なおこの処理では自動でidをふりわかるためdocumentにid等の指定はしません。また、"calls" collection下に"offerCandidates"、"answerCandidates" collectionを設けます。これらはstun serverにアクセスして得られた情報等を格納するために使います。 WebRTC.vue const callDoc = this.db.collection("calls").doc(); const offerCandidates = callDoc.collection("offerCandidates"); const answerCandidates = callDoc.collection("answerCandidates"); offer側のCandidateを取得しFirebaseに追加 WebRTC.vue this.pc.onicecandidate = (event) => { event.candidate && offerCandidates.add(event.candidate.toJSON()); }; const offerDescription = await this.pc.createOffer(); await this.pc.setLocalDescription(offerDescription); const offer = { sdp: offerDescription.sdp, type: offerDescription.type, }; await callDoc.set({offer}); await callDoc.update({ name: this.$route.query.name }); Remote answerの情報を読み込みDescriptionに追加 WebRTC.vue callDoc.onSnapshot((snapshot) => { const data = snapshot.data(); if (!this.pc.currentRemoteDescription && data?.answer) { const answerDescription = new RTCSessionDescription(data.answer); this.pc.setRemoteDescription(answerDescription); } }); Firebaseに変更が会った時読み込みCandidateを追加する WebRTC.vue answerCandidates.onSnapshot((snapshot) => { snapshot.docChanges().forEach((change) => { if (change.type === "added") { const candidate = new RTCIceCandidate(change.doc.data()); this.pc.addIceCandidate(candidate); } }); }); answerBtn method 上記methodではcreateCallと同様の処理を行います。 CreateRoom component 上記componentではroomのhost側がroomを作成するための処理を行います。 CreateRoom.vue <template> <v-card> <v-card-text> <v-text-field v-model="roomName" label="RoomName" required /> </v-card-text> <v-card-actions> <v-btn @click="roomCreate(roomName)"> Create </v-btn> <v-btn @click="clear()"> Clear </v-btn> </v-card-actions> </v-card> </template> <script> export default { data() { return { roomName: "" } }, methods: { roomCreate(val) { this.$router.push({path: 'video', query: { name: val }}) }, clear() { this.roomName = "" } } } </script> RoomTable component 上記componentではFirebaseに登録してあるRoomの一覧を表示しJoinボタンを押すことでRoomに参加することができます。 RoomTable.vue <template> <v-simple-table> <template v-slot:default> <thead> <tr> <th class="text-left"> RoomName </th> <th class="text-left"> Join </th> </tr> </thead> <tbody> <tr v-for="item in tableDataset" :key="item.id"> <td>{{ item.data().name }}</td> <td> <v-btn @click="toVideo(item.id)">Join</v-btn> </td> </tr> </tbody> </template> </v-simple-table> </template> <script> import firebase from "firebase" import "firebase/firestore" export default { name: "RoomTable", data() { return { db: null, tableDataset: [], } }, async created() { this.db = firebase.firestore() this.tableData = this.db.collection("calls").get(). then( (querySnapshot) => { querySnapshot.forEach((doc) => { this.tableDataset.push(doc) }) } ) }, methods: { toVideo(val) { this.$router.push({path: 'video', query: { id: val }}) } } } </script> 以上で主要componentsの作成は終了です。views等はGithubを参照してください。 実行方法 以下コマンド実行しプロジェクトを実行します。 $ cd [working directory]/[project name] $ npm run serve ローカルで動作の確認をする際は二つのタブを開いて片方でhostとなりroomを作成しもう片方でjoinしてください。実際に実行できると以下のようになります。 おわりに FirebaseとVue.jsを使うことで簡単にWebRTCを実装することができます。この記事が参考になったら幸いです。 参考 https://webrtc.org/ https://qiita.com/Dchi412/items/e0859e5df65de6f78591 https://fireship.io/lessons/webrtc-firebase-video-chat/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

v-modelとpropsとstore(vuex)

※ ぱっと見でわかるように説明と文法の省略をしています。 前提知識 <input v-model="title" /> は ⇩ の 糖衣構文 (シンタックスシュガー = 簡単な書き方) <input :value="title" @input="title = $event.target.value" /> 親子間の v-model パターン 親コンポーネント // Parent <child-component v-model="title" /> data() { return { title: "", }; }, ノーマル なやり方 親コンポーネントは v-model 子コンポーネントは v-bind と v-on // Child <input :value="title" @input="$emit('input', $event.target.value)" > props: { title: { type: String, }, }, computed 使ったやり方 親コンポーネントは v-model 子コンポーネントは computed の get と set get は値を取得 set は値の変更を検知してイベント発火 // Child <input v-model="inputedValue" /> props: { title: { type: String, }, }, computed: { inputedValue: { get() { return this.title; }, set(newValue) { this.$emit("input", newValue); }, }, }, store(vuex)絡み store.js state: { title: '', }, mutations: { updateTitle(state, title) { state.title = title; }, }, 親コンポーネント <child-component :title="title" @update-title="updateTitle($event)" /> computed: { title() { return this.$store.state.title; }, }, methods: { updateTitle(value) { this.$store.commit('updateTitle', value); }, }, 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

vue3 のref() reactive()について

はじめに vue3の学んでいく中で、新しく実装されたref reactiveの違いが曖昧だったので調べてみました。 参考にしてもらえると幸いです。 vue3 ref() reactive()とは refとreactiveはどちらも値をリアクティブな状態にするときに使うメソッドです。 使い方としては、vueからimportで利用することが出来ます。 import方法 import { reactive, ref } from 'vue' それぞれの役割 refメソッド refは独立したプリミティブ値をリアクティブにする際に利用します。 refの例 import { ref } from 'vue' const count = ref(0) console.log(count.value) // 0 count.value++ console.log(count.value) // 1 refを実行すると、返り値としてミュータブルなオブジェクトを返すようになります。 そのため、.valueで呼び出す必要がある点注意が必要です。 また、refがレンダーコンテキストかつ、テンプレート内でアクセスする必要がある場合、自動的に浅くアンラップされる仕様になっています。 入れ子になったrefがテンプレート内で.valueが必要になります。 refのアンラップ <template> <div> <span>{{ count }}</span> <button @click="count ++">Increment count</button> <button @click="nested.count.value ++">Nested Increment count</button> </div> </template> <script> import { ref } from 'vue' export default { setup() { const count = ref(0) return { count, nested: { count } } } } </script> reactiveメソッド refの単数に対してreactiveは単数ではなくオブジェクトをリアクティブにするメソッドです。 reactiveの例 import { reactive } from 'vue' // リアクティブな状態 const state = reactive({ count: 0 }) vue2におけるVue.observable()APIに相当するメソッドになります。 vue3にアップデートされたことにより改名されました。 reactiveメソッドを実行した場合、オブジェクトの中身はすべてリアクティブになります。 デフォルトにdeepモードが影響しているためです。 そのため、入れ子になっていた場合でもリアクティブになります。 実はdata()でオブジェクトを返す際にもこのreactiveメソッドが内部で実行されています。 最後に 良いVueライフを〜 参考にさせてもらったサイト
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue.js】 親子コンポーネント間のライフサイクルフック

Vue.js 親子コンポーネント間のライフサイクルフック はじめに ・Vue.jsの単一コンポーネントのライフサイクルフックはこちらの記事などにもあるように、実装をするうえで避けては通れない概念です。 ただ、親子間のライフサイクルについて、あまり言及されている記事が無く、実装中に詰まった箇所がありましたので、こちらでまとめようと思います。 前提 Vue.jsのライブラリとしてVuetityを使用。 起こった事象 下記のような親子コンポーネントを想定する。 parent.ts <template> : <v-row> <v-expansion-panels accordion> <v-expansion-panel @click="openAcordion()"> <v-expansion-panel-header>XXXX</v-expansion-panel-header> <v-expansion-panel-content> <Child :reportText.sync="reportText" :parentsParams="parentsParams" /> </v-expansion-panel-content> </v-expansion-panel> </v-expansion-panels> </v-row> : </template> <script> private mounted (): void { this.parentsParams = 'thisIsTest' } </script> Child.ts <script> mounted (): void { this.getTextArea() } //バック側のAPIにパラメータをpostする処理を記述 ~~~~~ </script> ■改修点 親コンポーネントを、アコーディオンメニューではなく、普通に表示をしたい。 v-row以下を下記のように修正したい parent.ts <v-row> <v-col> <Child :reportText.sync="reportText" :parentsParams="parentsParams" /> </v-col> </v-row> ■エラーの内容 バック側にpostしたとき、親コンポーネントで定義しているはずのparentsParamsがnullだとエラーが出る。 (実際にAPIへpostをしているのはchildコンポーネント側) ■エラーの原因 子コンポーネントではparentsParamが定義されていないため なぜ、parentsParamが定義されていなかったのか? →親子間のライフサイクルの違い ◆親子間のライフサイクルフック 親created ↓ 子created ↓ 子mount ↓ 親mount 上のように、親のmount時に定義しても、それより早く子の方がmountされるため、上記のようなエラーが出た。 改修時にこのエラーが起こったのは、 改修前はアコーディオンメニューを使っており、アコーディオンメニューボタンクリック時に 子コンポーネントが読み込まれる。つまり初期表示時のライフサイクルの影響を受けていなかった。 対策 子コンポーネントでmountされるよりも前に(つまり、親のcreated時など)値を定義する。 親子間でのデータ受け渡しがされている値は、どのタイミングで定義されているか、を常に意識しておく必要がある。 定義されているよりも前に使うとエラーになる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む