質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Nuxt.js

Nuxt.jsは、ユニバーサルなSPAが開発可能なVue.jsベースのフレームワーク。UIの描画サポートに特化しており、SSRにおけるサーバーサイドとクライアントサイドのUIレンダリングなどさまざまな機能を持ちます。

Vuex

Vuexは、Vue.js アプリケーションのための状態管理ライブラリです。アプリケーション内で使用するコンポーネントのための集中データストアを提供。コンポーネント同士でデータをやり取りし、処理のフローを一貫させたり、データの見通しを良くすることができます。

Q&A

解決済

2回答

2747閲覧

【Nuxt.js】【Vue.js】【Vuex】watchでstore内の値が変更された際に検知する方法

tokuwgawa

総合スコア45

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Nuxt.js

Nuxt.jsは、ユニバーサルなSPAが開発可能なVue.jsベースのフレームワーク。UIの描画サポートに特化しており、SSRにおけるサーバーサイドとクライアントサイドのUIレンダリングなどさまざまな機能を持ちます。

Vuex

Vuexは、Vue.js アプリケーションのための状態管理ライブラリです。アプリケーション内で使用するコンポーネントのための集中データストアを提供。コンポーネント同士でデータをやり取りし、処理のフローを一貫させたり、データの見通しを良くすることができます。

0グッド

0クリップ

投稿2018/12/20 08:28

編集2018/12/21 04:44

######storeの値をローカルデータに代入してそれをwatchで監視しているのですが、storeの値が変更してもwatchが発火しません。
######直接thisで書き込んでもwatch内ではthisを使ってはいけないとエラーが出ます。

######どのような書き方をすれば、store内の値をwatchで監視できますか?

#store側のコード
creative.js

export const state = () => ({ template: { id: 2, width: 200, height: 200, layers: [ { type: 'logo', width: 50, height: 50, x_position: 10, y_position: 5, z_index: 1 }, { type: 'image', width: 20, height: 20, x_position: 10, y_position: 100, z_index: 0 }, { type: 'image', width: 60, height: 30, x_position: 10, y_position: 150, z_index: 2 }, ], }, colors: { logo: '#FF0000', text: '#00FF00', image: '#0000FF', }, list_flag: '', }) export const mutations = { setTemplate(state, template) { state.template.id = template.id state.template.width = template.width state.template.height = template.height state.template.layers = template.layers }, setSize(state, size) { state.template.width = size.width state.template.height = size.height if (state.template.layers) { state.template.layers = [] } }, setTypeColor(state, type) { switch (type) { case 'logo': return state.colors.logo break case 'text': return state.colors.text break case 'image': return state.colors.image break } }, setFlag(state, flag) { state.list_flag = flag } } export const actions = { writeTemplate(context, template) { context.commit('setTemplate', template) }, writeSize(context, size) { context.commit('setSize', size) }, changeTypeColor(context, type) { context.commit('setTypeColor', '#00FF00') }, changeFlag(context, flag) { context.commit('setFlag', flag) }, } export const getters = {}

#現在のコード
一部抜粋

 data() { return { //ローカルでstoreのstateデータを代入 template: this.$store.state.creative.template } }, watch: { //watchでローカルデータのtemplateが変更した際にメソッドを発火させる template: function () { this.draw() } }

#.vueの全体コード
preview.vue

<template> <div> <div style="width:800px;height:300px;padding:50px;border:solid 1px #DDD;background-color:#EFEFEF;overflow:scroll"> <canvas :style="{ border: 'solid 1px #DDD' }"></canvas> </div> </div> </template> <script> export default { data() { return { //ローカルでstoreのstateデータを代入 template: this.$store.state.creative.template } }, watch: { //watchでローカルデータのtemplateが変更した際にメソッドを発火させる template: function () { this.draw() } }, mounted() { this.ctx = this.$el.firstChild.firstElementChild.getContext('2d') this.draw() }, methods: { draw() { console.log('ikeruyo') this.ctx.canvas.width = this.template.width this.ctx.canvas.height = this.template.height this.ctx.beginPath() this.ctx.clearRect(0,0,this.template.width, this.template.height) this.template.layers.forEach(layer => { this.ctx.strokeStyle = this.test(layer.type) this.ctx.strokeRect(layer.x_position, layer.y_position, layer.width, layer.height) }); this.ctx.fill() }, createImage() { console.log(this.template) html2canvas(document.querySelector("#preview")).then(function(canvas){ let result = document.querySelector("#result") result.innerHTML = '' let image = result.appendChild(canvas) let canvasImage = document.getElementById("result").firstElementChild let link = document.createElement("a") link.href = canvasImage.toDataURL("image/png") link.download = "test.png" link.click() }) }, test: function(t) { switch ( t ) { case 'text': return '#CC7777' break; case 'logo': return '#77CC77' break; case 'image': return '#7777CC' break; } } }, } </script>

change.vue

<template> <div> <div v-for="size in creative_data.sizes"> <el-button class="size" :style="{ width: size.width / 3 + 'px', height: size.height / 3 + 'px', }" @click="$store.dispatch('creative/writeSize', size)" > {{ size.width }}×{{ size.height }} </el-button> </div> </div> </template> <script> export default { props: { }, data() { return { radius: 3, } }, computed: {}, components: {}, data() { return { creative_data: { sizes: [ { width: '300', height: '400', }, { width: '300', height: '100', }, { width: '400', height: '500', }, { width: '200', height: '200', }, { width: '100', height: '500', }, ], }, } }, mounted: function() {}, methods: { }, } </script> <style scoped lang="scss"> @import '../../../../assets/css/creative/size.css'; </style>

イメージ説明

稚拙な画像なのですが、現在の自分のデータ間構成についてです。
shou6さんが貼ってくださった通りのコードだとwatch呼び出しに成功しているのですが、自分のコードの場合watch呼び出しできませんでした。
説明すると、「change.vue」でstorestate内データのtemplateの値を変更しています。watch処理を行っていない別ファイルで。(変更処理はstoreactions等を使ってcommitしています)
憶測なのですが、自身のファイル内で変更の行われない値は監視されないのでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

おそらくこれで大丈夫かと思います。

vue

1# Creative.vue 2 3<template> 4 <div> 5 <div class="canvas-frame"> 6 <canvas/> 7 </div> 8 </div> 9</template> 10 11 12<script> 13export default { 14 computed: { 15 template() { 16 return this.$store.state.creative.template 17 } 18 }, 19 watch: { 20 template(val) { 21 console.log(val) 22 this.draw() 23 } 24 }, 25 mounted() { 26 this.ctx = this.$el.firstChild.firstElementChild.getContext("2d") 27 this.draw() 28 }, 29 methods: { 30 draw() { 31 console.log("ikeruyo") 32 this.ctx.canvas.width = this.template.width 33 this.ctx.canvas.height = this.template.height 34 this.ctx.beginPath() 35 this.ctx.clearRect(0, 0, this.template.width, this.template.height) 36 this.template.layers.forEach(layer => { 37 this.ctx.strokeStyle = this.test(layer.type) 38 this.ctx.strokeRect(layer.x_position, layer.y_position, layer.width, layer.height) 39 }) 40 this.ctx.fill() 41 }, 42 createImage() { 43 console.log(this.template) 44 html2canvas(document.querySelector("#preview")).then(canvas => { 45 const result = document.querySelector("#result") 46 result.innerHTML = "" 47 const image = result.appendChild(canvas) 48 49 const canvasImage = document.getElementById("result").firstElementChild 50 const link = document.createElement("a") 51 52 link.href = canvasImage.toDataURL("image/png") 53 link.download = "test.png" 54 link.click() 55 }) 56 }, 57 test(t) { 58 switch (t) { 59 case "text": 60 return "#CC7777" 61 case "logo": 62 return "#77CC77" 63 case "image": 64 return "#7777CC" 65 } 66 } 67 } 68} 69</script> 70 71<style lang="scss" scoped> 72.canvas-frame { 73 width: 800px; 74 height: 300px; 75 padding: 50px; 76 border: solid 1px #ddd; 77 background-color: #efefef; 78 overflow: scroll; 79 80 canvas { 81 border: "solid 1px #DDD"; 82 } 83} 84</style>

vue

1# Change.vue 2 3<template> 4 <div> 5 <div v-for="(size,index) in creative_data.sizes" :key="index"> 6 <el-button 7 class="size" 8 :style="{ 9 width: size.width / 3 + 'px', 10 height: size.height / 3 + 'px', 11 }" 12 @click="sizeChange(size)" 13 >{{ size.width }}×{{ size.height }}</el-button> 14 </div> 15 </div> 16</template> 17 18<script> 19export default { 20 data() { 21 return { 22 radius: 3, 23 creative_data: { 24 sizes: [ 25 { 26 width: 300, 27 height: 400 28 }, 29 { 30 width: 300, 31 height: 100 32 }, 33 { 34 width: 400, 35 height: 500 36 }, 37 { 38 width: 200, 39 height: 200 40 }, 41 { 42 width: 100, 43 height: 500 44 } 45 ] 46 } 47 } 48 }, 49 mounted() {}, 50 methods: { 51 sizeChange(size) { 52 this.$store.dispatch("creative/writeSize", size) 53 } 54 } 55} 56</script>

js

1# store/creative.js 2 3export const state = () => ({ 4 template: { 5 id: 2, 6 width: 200, 7 height: 200, 8 layers: [ 9 { type: "logo", width: 50, height: 50, x_position: 10, y_position: 5, z_index: 1 }, 10 { type: "image", width: 20, height: 20, x_position: 10, y_position: 100, z_index: 0 }, 11 { type: "image", width: 60, height: 30, x_position: 10, y_position: 150, z_index: 2 } 12 ] 13 }, 14 colors: { 15 logo: "#FF0000", 16 text: "#00FF00", 17 image: "#0000FF" 18 }, 19 list_flag: "" 20}) 21 22export const mutations = { 23 setTemplate(state, payload) { 24 state.template = payload 25 }, 26 setSize(state, payload) { 27 state.template = payload 28 }, 29 setTypeColor(state, payload) { 30 // ここは何がやりたいのか不明の為触れません 31 }, 32 setFlag(state, payload) { 33 state.list_flag = payload 34 } 35} 36 37export const actions = { 38 writeTemplate({ commit }, template) { 39 commit("setTemplate", template) 40 }, 41 42 writeSize({ commit, state }, size) { 43 commit("setSize", { 44 id: state.template.id, 45 width: size.width, 46 height: size.height, 47 layers: state.template.layers ? state.template.layers : [] 48 }) 49 }, 50 51 changeTypeColor({ commit }, color) { 52 // ここは何がやりたいのか不明の為触れません 53 }, 54 55 changeFlag({ commit }, flag) { 56 commit("setFlag", flag) 57 } 58} 59 60export const getters = {}

投稿2018/12/21 03:35

編集2018/12/21 06:26
shou6

総合スコア305

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tokuwgawa

2018/12/21 08:28

ありがとうございました! 無事動きました!しかしなぜこのようコードだとwatchが実行されるのかわからないので、調べてみたいと思います。
guest

0

ちょっと全てのコード確認してないので分かりませんが、storeのtemplateは取得出来ているんですよね?

そしたら下記の様にcomputedで定義してあげたらいいかと

vue

1computed: { 2 template() { 3 //ローカルでstoreのstateデータを代入 4 return this.$store.state.creative.template 5 } 6}, 7watch: { 8 //watchでローカルデータのtemplateが変更した際にメソッドを発火させる 9 template() { 10 this.draw() 11 } 12}

投稿2018/12/20 09:54

shou6

総合スコア305

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tokuwgawa

2018/12/21 01:40

storeのtemplateは取得できています。 こちらの方法で行って見たのですが、storeのtemplateの値変更は確認できているのですが、watch側のメソッド変更が行われません。 computedが値変更に対応できないのでしょうか。。
shou6

2018/12/21 01:57

そうなんですね。。 下記のdataの方は消してありますか? data() { return { template: - } } あとは下記コードでtemplate変更した時に値の更新を取れますか? watch: { template(val) { console.log(val) }
tokuwgawa

2018/12/21 02:12

回答ありがとうございます。 data側のtemplateは削除済みです。 template(val)はhtml内でclickでもなんでもいいので、htmlに埋め込む形で実行すればよろしですか? それとも computed: { template(val) { return this.$store.state.creative.template } }, こちらのようにcomputedを書き直して実行すればよろしいですか?
shou6

2018/12/21 02:39

いえ、watchで値変更を取得出来ていますか?という意味になります。 watch: { template(val) { console.log(val) }
tokuwgawa

2018/12/21 03:13

回答ありがとうございます。 試した結果、値変更を検知できていないそうなので、watch内のコードは呼び出されませんでした。
shou6

2018/12/21 03:38 編集

うーん、取れてますね変更。 回答の方にコード書きますね。。
tokuwgawa

2018/12/21 03:36

詳しい説明ありがとうございます。 もう少し自分でも調べて見ます。
tokuwgawa

2018/12/21 04:03

急ぎ作った画像で線がぐちゃっとしているのですが、これが自分のファイル情報とデータ送受信の情報です
shou6

2018/12/21 04:17 編集

store/creative.jsのコード全部見せてもらっていいですか? storeのtemplateを更新しているならば、他にもコードがあるかと思うので。
tokuwgawa

2018/12/21 04:22

失礼いたしました。一部抜き出してコード記載していたので、全てのコード記載に変更いたしました。
shou6

2018/12/21 04:27

ありがとうございます。 その変更を行うchange.vueではどのような処理をしているのでしょうか。
tokuwgawa

2018/12/21 04:41

コード追記します。
tokuwgawa

2018/12/21 05:40

コード追記しました!
shou6

2018/12/21 06:12

回答のコードを修正しました。 mutationsの処理で、state.template.height = ...とありましたがそれだと検知されなかったので、state.templeteに入れる形にしてあります。 変わらない部分はそのままstateのデータを入れればいいので。
shou6

2018/12/21 06:27

mutationsはデータを書き換えるだけにして、actionsで格納するデータにしてからcommitすると良いと思います。
tokuwgawa

2018/12/21 09:04

「mutationsの処理で、state.template.height = ...とありましたがそれだと検知されなかった」これがなぜ検知されなかったか原因わかりますか? 自分でも調べてたのですが、原因がわかりませんでした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問