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

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

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

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

受付中

vue-routerのpathに外部ファイル化したコンポーネントを設定したい。

redux
redux

総合スコア0

Vue.js

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

0回答

0評価

0クリップ

897閲覧

投稿2020/08/10 22:25

前提・実現したいこと

vue-routerのpathに外部ファイル化したコンポーネントを設定したい。

発生している問題・エラーメッセージ

設定したいコンポーネントが画面に表示されない。

該当ソース

html

<div id="router"> <router-link to="/top" >トップページ</router-link> <router-view></router-view> </div>

js

//top.js Vue.component('top', { template: `<div>トップページです。</div>` }); new Vue({ el: '#app' })

js

//router.js var router = new VueRouter({ routes: [ { path: '/top', component:{ template: '<top></top>' } }, }) new Vue({ router: router }).$mount('#router')

試したこと

router.jsとtop.jsのマウント先IDを同一にする等してみましたが、どうしてもtop.jsのtemplateが非表示となってしまいます。

参考書を使って学習しているのですが、そこではx-templateを使って実施していました。
その方法ならばできそうなのですが、htmlファイルが冗長になってしまうのでできれば避けたいです。

また、node.jsやvue cliに詳しくないので単一コンポーネントもできれば避けたいと考えています。

補足情報(FW/ツールのバージョンなど)

php     :7.4.4
vue     :2.5.17
vue-router :3.0.1

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

dameo
dameo

2020/08/11 09:53

私自身がvueやvue/cliやその係累に詳しくないので、何を目的に何がしたいのかイマイチ分かりません。 多分もう少し具体的に書いた方がいいと思います。 「外部ファイル化したコンポーネント」が何を意味しているのか分かりません。vueファイルを動的に生成したいとかですか? 「htmlファイルが冗長になってしまう」のはどうしてですか? 「単一コンポーネント」とはどういうのもを指してますか?
redux
redux

2020/08/11 10:27 編集

top\.jsで記述したtemplateとscriptの処理のセットを、router\.jsのpathにアクセスした際に表示したいです。 このtop\.jsが「外部ファイル化したコンポーネント」です。 今後はrouter\.js内のroutesの中身を追加していき、pathと「外部ファイル化したコンポーネント」の組み合わせを増やしてSPAを実装しようとしています。 pathに対応したコンポーネント(またはテンプレート)が<router-view></router-view>に動的に反映されるのがvuerouterの仕組みです。 単一コンポーネントはvue拡張子のファイルです。今回は使用するつもりがありません。 htmlファイルが冗長になるのは、x-templateを使用した場合、ページを追加した分だけ、同一HTML内にページ毎のhtml文を羅列しなければいけないためです。
dameo
dameo

2020/08/11 10:41 編集

「Webpack や Browserify のビルドツールにより実現された \.vue 拡張子の 単一ファイルコンポーネント」を使用しないということは、つまり、vue-cliやwebpackも使わずに、自前でhtmlとコンポーネントごとなどに分かれた複数の\.jsファイルを使って複数のコンポーネントを使ったUIを実現したいってことですか? で、ルーティングにはvue-routerを単品で使いたい・・・と。
redux
redux

2020/08/11 10:44

その通りです。 「外部ファイル化したコンポーネント」の中のtemplate要素だけをHTMLファイルにxtemplateとして記述する方法は見たことがあるので模倣できるのですが、質問内容以外にもコンポーネントは作成してしまっている事と、折角なら今回目指している方法での記述方法も知りたいので質問しています。
redux
redux

2020/08/11 10:54 編集

xtemplateも外部ファイル化してrequireする方法でもできるような気がしてきたので、HTMLファイルが冗長になる現象は避けられるかもしれませんが、今回のパターンも知っておきたいです。
dameo
dameo

2020/08/11 12:14 編集

# とりあえず、commonjs以前のグローバル汚染で書いてみました。Unix系なら空のディレクトリ上でコピペ実行するとファイルになると思います。 sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >index\.html <script src="https://unpkg\.com/vue/dist/vue\.js"></script> <script src="https://unpkg\.com/vue-router/dist/vue-router\.js"></script> <div id="router">  <div id="nav">   <router-link to="/top" >トップページ</router-link>|<router-link to="/sample">サンプル</router-link>  </div>  <router-view></router-view> </div> <script src="top\.js"></script> <script src="sample\.js"></script> <script src="router\.js"></script> __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >router\.js //router\.js var router = new VueRouter\({   routes: \[     {       path: '/top',       component: Top     },     {       path: '/sample',       component: Sample     },   \] }\) new Vue\({   router: router }\)\.$mount\('#router'\) __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >top\.js const Top = {   template: '<div>トップページです。</div>' }; __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >sample\.js Sample = {   template: '<div>サンプルページです。</div>' }; __END_OF_TERMINAL_CODE__
dameo
dameo

2020/08/11 13:13

#ES6の静的import版です。ルートモジュールだけ使えます。 sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >index\.html <script src="https://unpkg\.com/vue/dist/vue\.js"></script> <script src="https://unpkg\.com/vue-router/dist/vue-router\.js"></script> <div id="router">  <div id="nav">   <router-link to="/top" >トップページ</router-link>|<router-link to="/sample">サンプル</router-link>  </div>  <router-view></router-view> </div> <script src="\./router\.js" type="module"></script> __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >router\.js //router\.js import Top from '\./top\.js'; import Sample from '\./sample\.js'; var router = new VueRouter\({   routes: \[     {       path: '/top',       component: Top     },     {       path: '/sample',       component: Sample     },   \] }\) new Vue\({   router: router }\)\.$mount\('#router'\) __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >sample\.js export default {   template: '<div>サンプルページです。</div>' } __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >top\.js export default {   template: '<div>トップページです。</div>' } __END_OF_TERMINAL_CODE__
dameo
dameo

2020/08/11 13:32

# 本当にトップモジュールだけなのかなぁと調べてみたら出来たのでよく分からなくなりました。 sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >index\.html <script src="https://unpkg\.com/vue/dist/vue\.js"></script> <script src="https://unpkg\.com/vue-router/dist/vue-router\.js"></script> <div id="router">  <div id="nav">   <router-link to="/top" >トップページ</router-link>|<router-link to="/sample">サンプル</router-link>  </div>  <router-view></router-view> </div> <script src="\./router\.js" type="module"></script> __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >router\.js //router\.js import Top from '\./top\.js'; import Sample from '\./sample\.js'; var router = new VueRouter\({   routes: \[     {       path: '/top',       component: Top     },     {       path: '/sample',       component: Sample     },   \] }\) new Vue\({   router: router }\)\.$mount\('#router'\) __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >sample\.js import SampleSub from '\./samplesub\.js'; export default {   template: '<div>サンプルページです。<sample-sub></sample-sub></div>',   components: {     'sample-sub': SampleSub   }, } __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >samplesub\.js export default {   template: '<div>サンプルサブコンポーネントです。</div>', } __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >top\.js export default {   template: '<div>トップページです。</div>' } __END_OF_TERMINAL_CODE__
dameo
dameo

2020/08/11 13:37

動的は静的が出来ればそれほど要らないと思ったので、とりあえずここまでで。 他のパターン\(requireとかexport\.moduleとか\)はご自分で調べてください。テンプレート部分を外に出すのはまた別の話かと思うので、こちらは除外します。
redux
redux

2020/08/11 23:05

丁寧な回答ありがとうございます。 色々試してみたいと思います。 自分自身のソースは一旦x-templateで作成したのですが、propsが使えないため、phpからデータを送れない問題が発生してしまいました。 また別枠で質問してみます。
dameo
dameo

2020/08/12 02:33

何がどういうことなんだかよく分かりませんが\.\.\. 結局テンプレート部分をjsと分けたかったってことなんでしょうか? propsが使えないって起こり得ない気がするし、使えない場合困るのはリアクティブな反応=プロパティ変化によるUIの変更ができなくなることで、APIをどうするのか知りませんが、PHPで作成したHTMLに埋め込む際にdata経由でデータを送ることができるのでPHPから送れないこともないと思うのですが、、、 API側\(ajax\)もPHPならそれはpropsがないとそもそもvueとして機能しないとは思います。 多分諸々含めて、PHP側の実装がどういう仮定なのか分からないので、なんとも言えません。
dameo
dameo

2020/08/12 03:48

これで終わりもアレなのでphpのAPI部分も付けてみました。 sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >api\.php <\?php // https://www\.indetail\.co\.jp/blog/6053/ より拝借、変更 $daysInJapanese = \["日", "月", "火", "水", "木", "金", "土"\]; parse_str\($_SERVER\['QUERY_STRING'\], $queryString\); $targetDate = strtotime\($queryString\['date'\], 0\); $dayInJapanese = $daysInJapanese\[date\("w", $targetDate\)\] \. "曜日"; $response = array\(   'target_date' => $targetDate,   'day_in_japanese' => $dayInJapanese \); echo json_encode\($response\); \?> __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >index\.html <html lang='ja'> <head>  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <script src="https://unpkg\.com/vue/dist/vue\.js"></script> <script src="https://unpkg\.com/vue-router/dist/vue-router\.js"></script> <div id="router">  <div id="nav">   <router-link to="/top" >トップページ</router-link>|<router-link to="/sample">サンプル</router-link>  </div>  <router-view></router-view> </div> <script src="\./router\.js" type="module"></script> </html> __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >router\.js //router\.js import Top from '\./top\.js'; import Sample from '\./sample\.js'; var router = new VueRouter\({   routes: \[     {       path: '/top',       component: Top     },     {       path: '/sample',       component: Sample     },   \] }\) new Vue\({   router: router }\)\.$mount\('#router'\) __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >sample\.js import SampleSub from '\./samplesub\.js'; export default {   template: '<div>サンプルページです。<sample-sub></sample-sub></div>',   components: {     'sample-sub': SampleSub   }, } __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >samplesub\.js export default {   template:     `<div>       <div>サンプルサブコンポーネントです。</div>       <div>{{date}}はサーバーで{{weekday}}と認識されています。</div>      </div>`,   props: \['date', 'weekday'\],   created: function\(\) {     const self = this;     const today = new Date\(\);     self\.date = new Date\(\)\.toLocaleDateString\(\);     fetch\('\./api\.php\?date=' \+ today\.toISOString\(\)\)       \.then\(response => response\.json\(\)\)       \.then\(data => {self\.weekday = data\.day_in_japanese;}\);   } } __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >top\.js export default {   template: '<div>トップページです。</div>' } __END_OF_TERMINAL_CODE__
redux
redux

2020/08/12 08:45 編集

色々割愛しすぎていましたが、PHPのslim3フレームワークを使用していて、index\.htmlにアクセスした時点で、htmlファイルはDBから引っ張て来た連想配列を取得済の状態です。 Vue\.componentを使ったコンポーネント作成の場合、コンポーネント呼び出し時に以下のような記述をするだけでphpからvueコンポーネントへ値を渡すことができます。vue\.jsの教科書でprops(親から子への値引き渡し。)を使う時の記述はこれしか載っていませんでした。 <top post-data = <\?php echo \$response \?>></top> topコンポーネント内でpost-dataをpropsに登録することで、\$responseの値を使用可能になります。 なのでこれに乗っ取って記述しようとしたのですが、template等を変数に入れ込んで扱う場合、<top></top>のようなタグを使用しないので、値の受け渡し方がわからなくなってしまいました。 ajaxで叩くしかないなら仕方ないと思いますが、フレームワークを使っている以上、vue\.jsもslimも活用したいと思った次第です。
redux
redux

2020/08/12 09:12

この質問をした経緯として、vuerouterのcomponentの値に<top></top>といったタグを設定できないため、上記の方法でphpの値を受け渡せない事がそもそもの問題でした。 しかし、今ソースをいじっていて気づいたのですが、<top></top>といったタグはvue-routerに設定可能でした。 なぜ、いままで上手くいかなかったかというと、<top post-data = <\?php echo \$response \?>></top>のような形でphpの値を受け渡す記述をしていましたが、この記述がエラーになっているようです。 この値の受け渡しをrouter\.jsを通して実施できればすべてが解決します。
dameo
dameo

2020/08/12 09:13

う~ん、根本的にPHPを使ってHTMLを返そうとしている限り、繋ぎの部分はフレームが何だろうと、\*\.vueを使おう使うまいと、そこは全く関係ないのではないでしょうか? 初期化はともかくコンポーネント同士でやり取りするような処理は個人的に好ましくないと思うので、ややこしいのはお名前から類推されるアレと同じ分類のVuexなどで状態管理するのが望ましいようですよ。 いずれにせよ、要件の整理はあなたにとってもいいことでしょうし、質問は変えた方がいいかもですね。
redux
redux

2020/08/12 09:17

改めて質問してみます。 たくさんソースを記述していただいてありがとうございました。勉強になります。
dameo
dameo

2020/08/12 12:08

新しい質問見ました。 https://teratail\.com/questions/284250 私が何か書くと多分他の人が書かなくなっちゃうかもなので、私は引き続きこちらに記述しますね。 vue-router経由で渡すにしても、結局SPAという性質上HTMLでの取得は原則1回です。 つまり初期値であり、routingして遷移してるように見せてるだけで、ajaxを使わなければ初期値から変わることはありません。しかし、そのアプリはルーティングをした際に毎回HTML取得時の初期値を必要とするのでしょうか?設計上は遷移したときに結局必要な情報をajaxで取りに行くのが普通かと思います。 vue-router側も遷移と割り切ってrouter→component間でさほどデータを授受できるリッチなI/Fを持っていないようです。 という前置きを置いた上で、それでも初期値はなんか必要だよね、というところから考えた結果、結局phpの中でグローバルデータを置いてしまうのが一番ラクというのが私の見解です。コンポーネントのプロパティに設定する方法としては、routerのオプションで、routeの設定をする部分で、propsを定義し、そこにfunctionを設定してしまうのがいいようです。 sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >api\.php <\?php // https://www\.indetail\.co\.jp/blog/6053/ より拝借、変更 $daysInJapanese = \["日", "月", "火", "水", "木", "金", "土"\]; parse_str\($_SERVER\['QUERY_STRING'\], $queryString\); $targetDate = strtotime\($queryString\['date'\], 0\); $dayInJapanese = $daysInJapanese\[date\("w", $targetDate\)\] \. "曜日"; $response = array\(   'target_date' => $targetDate,   'day_in_japanese' => $dayInJapanese \); echo json_encode\($response\); \?> __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >index\.php <html lang='ja'> <head>  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <script src="https://cdn\.jsdelivr\.net/npm/vue/dist/vue\.js"></script> <script src="https://unpkg\.com/vue-router/dist/vue-router\.js"></script> <div id="router">  <div id="nav">   <router-link to="/top" >トップページ</router-link>|<router-link to="/sample">サンプル</router-link>  </div>  <router-view></router-view> </div> <script> const json = <\?php echo '{"data":\[{"id": "id1", "value": "value1"}, {"id": "id2", "value": "value2"}\]}'; \?>; const initialData = json\.data; </script> <script src="\./router\.js" type="module"></script> </html> __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >router\.js //router\.js import Top from '\./top\.js'; import Sample from '\./sample\.js'; var router = new VueRouter\({   routes: \[     {       path: '/top',       component: Top,       props: \(route\)=>\({dbdata: initialData}\),     },     {       path: '/sample',       component: Sample     },   \] }\) window\.vue=new Vue\({   router: router }\)\.$mount\('#router'\) __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >sample\.js import SampleSub from '\./samplesub\.js'; export default {   template: '<div>サンプルページです。<sample-sub></sample-sub></div>',   components: {     'sample-sub': SampleSub   }, } __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >samplesub\.js export default {   template:     `<div>       <div>サンプルサブコンポーネントです。</div>       <div>{{date}}はサーバーで{{weekday}}と認識されています。</div>      </div>`,   props: \['date', 'weekday'\],   created: function\(\) {     const self = this;     const today = new Date\(\);     self\.date = new Date\(\)\.toLocaleDateString\(\);     fetch\('\./api\.php\?date=' \+ today\.toISOString\(\)\)       \.then\(response => response\.json\(\)\)       \.then\(data => {self\.weekday = data\.day_in_japanese;}\);   } } __END_OF_TERMINAL_CODE__ sed 's/\^\\xc2\\xa0/ /;s/$/\$/g;s/`/`/g;s/ /\\x20\\x20/g' <<__END_OF_TERMINAL_CODE__ >top\.js export default {   template: `<div>トップページです。         <table>          <tr v-for="row, i in dbdata" :key="row\.id">           <td>{{row\.id}}</td><td>{{row\.value}}</td>          </tr>         </table>        </div>`,   props: \['dbdata'\], } __END_OF_TERMINAL_CODE__
redux
redux

2020/08/12 22:42

回答ありがとうございます。 Vue\.componentで同じことをしようとしたのですが、上手くいかず、 module構文で記述したら再現できました。 これで製作がはかどります。ありがとうございます。
dameo
dameo

2020/08/12 22:52

Vue\.componentはグローバルに登録する形になる気がしたので、考えたことなかったです。 余談ですがmodule構文使うと外から本当に見えないので、vueオブジェクト見えずにデバッグ時に泣きそうでした。上ではwindow\.vueとかに放り込んでます。

まだ回答がついていません

会員登録して回答してみよう

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Vue.js

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