Home
Explore
Submit Search
Upload
Login
Signup
Advertisement
初めてのvue.js(2.x系)
Report
健人 井関
Follow
Sep. 28, 2020
•
0 likes
0 likes
×
Be the first to like this
Show More
•
587 views
views
×
Total views
0
On Slideshare
0
From embeds
0
Number of embeds
0
Check these out next
One night Vue.js
Masahiro Kyuden
Vue.js で XSS
tobaru_yuta
Vue.js 2.0を試してみた
Toshiro Shimizu
owasp_evening_okinawa_7_owasp_top_10-2017_injection
tobaru_yuta
Vue入門
Takeo Noda
Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁
Yutaro Miyazaki
Progressive Framework Vue.js 2.0
Toshiro Shimizu
Vue.jsの関連ツール・ライブラリ(Vuex, Vue-Router, Nuxt)
Kei Yagi
1
of
196
Top clipped slide
初めてのvue.js(2.x系)
Sep. 28, 2020
•
0 likes
0 likes
×
Be the first to like this
Show More
•
587 views
views
×
Total views
0
On Slideshare
0
From embeds
0
Number of embeds
0
Download Now
Download to read offline
Report
Technology
フロントエンドカンファレンス福岡2019で行ったVue.jsのワークショップ資料
健人 井関
Follow
Advertisement
Advertisement
Advertisement
Recommended
チュートリアルではじめるVue.js
小川 昌吾
11.9K views
•
71 slides
Vue Router + Vuex
Kei Yagi
2.5K views
•
49 slides
Vue.js入門
Takuya Sato
17.9K views
•
41 slides
はじめてのVue.js
Kei Yagi
2.3K views
•
48 slides
ライオンでも分かるVuejs
lion-man
8K views
•
26 slides
プロダクトに 1 から Vue.js を導入した話
Shohei Okada
22.7K views
•
69 slides
More Related Content
Slideshows for you
(20)
One night Vue.js
Masahiro Kyuden
•
3.4K views
Vue.js で XSS
tobaru_yuta
•
7.1K views
Vue.js 2.0を試してみた
Toshiro Shimizu
•
2.8K views
owasp_evening_okinawa_7_owasp_top_10-2017_injection
tobaru_yuta
•
814 views
Vue入門
Takeo Noda
•
5.7K views
Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁
Yutaro Miyazaki
•
66.1K views
Progressive Framework Vue.js 2.0
Toshiro Shimizu
•
2.2K views
Vue.jsの関連ツール・ライブラリ(Vuex, Vue-Router, Nuxt)
Kei Yagi
•
12.1K views
はじめてのSpring Boot
なべ
•
3.4K views
はじめてのVue.js
kamiyam .
•
5.1K views
Start React with Browserify
Muyuu Fujita
•
3.3K views
テストゼロからイチに進むための戦略と戦術
Y Watanabe
•
4.7K views
osc-nagoya
joeswebhosting
•
729 views
HTML5の前のJavaScript入門
Hiroki Toyokawa
•
3K views
Brush up your Coding! 2013 winter
Shogo Sensui
•
6.2K views
20200304 vuejs
yamamotomsc
•
29 views
iOS WebView App
hagino 3000
•
14.4K views
WordPressとjQuery
Seto Takahiro
•
3.3K views
Spring Bootでチャットツールを作りながらWebの仕組みを理解しよう!
Java女子部
•
13.3K views
サーバサイドで動的にhtml生成していたりjQueryをガッツし使っている既存プロジェクトにAngularJSを部分的につっこんでみた @jscafe21
佐藤 俊太郎
•
2.1K views
Similar to 初めてのvue.js(2.x系)
(20)
13016 n分で作るtype scriptでnodejs
Takayoshi Tanaka
•
2.3K views
ftechmeetup_データバインディングはどう実装されているのか
kanatsum
•
123 views
Appsody でnodejsのアプリを立ち上げよう!
Daisuke Hiraoka
•
273 views
【de:code 2020】 「あつまれ フロントエンドエンジニア」 Azure Static Web Apps がやってきた
日本マイクロソフト株式会社
•
286 views
Nuxt.js入門 2018/02/02 Vue.js入門勉強会@渋谷 発表資料
慎二 山田
•
1.1K views
[TL04] .NET 15 周年の今こそ考えるクラウドネイティブ アプリケーションと .NET の活用
de:code 2017
•
991 views
Using Windows Azure
Shinji Tanaka
•
2.2K views
Ma gician <Vue にはできないこと (1)> WeJS 37th
Eucen Stew
•
1.1K views
120512 metro styleapp_javascript
Takayoshi Tanaka
•
507 views
Hokuriku.net 2013 01-26 node.js
Tadahiro Ishisaka
•
1.1K views
Node.js Tutorial at Hiroshima
Yoshihiro Iwanaga
•
17.7K views
Ma_gician (世界中のフロントエンダーの残業時間を減らす、新しいフロントエンドフレームワーク)<詳細版>
Eucen Stew
•
902 views
Windows Azure PHP Tips
Microsoft Openness Japan
•
660 views
Netラボ2012年6月勉強会 マイクロソフトのオープンソース戦略を考える
david9142
•
2.2K views
T35 ASP.NET MVCを使ったTDD入門
normalian
•
1.4K views
ASP.NET WEB API 開発体験
miso- soup3
•
44.2K views
VSUGDAY2012 - ASP.NET MVC 4 Deveoper Preview による モバイルWEBアプリケーション開発
tomotoshi
•
885 views
CleanArchitecture with AssemblyDefinition in unity
NakanoYosuke1
•
689 views
Microsoft azure上にwebサイトやアプリケーションを構築する方法 アドバンスド
Kazumi Hirose
•
1.8K views
Visual Studio 2017 事はじめ
Hideaki Aoyagi
•
956 views
Advertisement
More from 健人 井関
(6)
勉強できてますか?
健人 井関
•
540 views
ThinkDESIGN ユニバーサルデザイン#1
健人 井関
•
399 views
ゆるっと IT勉強会
健人 井関
•
125 views
Atomic desing workshop
健人 井関
•
1.2K views
福岡のIT系勉強会情報
健人 井関
•
1.8K views
なぜ初心者は webpackが解らないのか?- Why can’t you understand the webpack? -
健人 井関
•
78.9K views
Recently uploaded
(20)
☀️【卡尔顿大学毕业证成绩单留学生首选】
15sad
•
2 views
留信网认证可查【拜欧拉大学文凭证书毕业证购买】
1lkjhg
•
3 views
Forguncy8 製品概要 202305.pptx
フォーガンシー
•
6 views
留信网认证可查【皇家霍洛威学院文凭证书毕业证购买】
32lkhng
•
2 views
☀️【中央兰开夏大学毕业证成绩单留学生首选】
25mjhd12
•
4 views
①【阳光海岸大学毕业证文凭学位证书|工艺完美复刻】
vgh215w
•
2 views
①【麦吉尔大学毕业证文凭学位证书|工艺完美复刻】
love445ds
•
2 views
Kubernetes超入門
Takashi Suzuki
•
0 views
論文紹介:Temporal Action Segmentation: An Analysis of Modern Techniques
Toru Tamaki
•
53 views
①【威斯康星大学麦迪逊分校毕业证文凭学位证书|工艺完美复刻】
C25lokh12
•
3 views
初学者のためのプロンプトエンジニアリング実践.pptx
Akifumi Niida
•
251 views
①【汤普森河大学毕业证文凭学位证书|工艺完美复刻】
love445ds
•
2 views
ペンタエリスリトール市場.pdf
HinaMiyazu
•
3 views
突如登場したAzure Developer CLIでなにができるのか?検証してみる
Kazumi IWANAGA
•
27 views
JSTQB_テストマネジメントとレビュープロセス.pdf
akipii Oga
•
15 views
20230523_IoTLT_vol99_kitazaki_v1.pdf
Ayachika Kitazaki
•
99 views
GitHub Copilotとともに次の開発体験へ
Kazumi IWANAGA
•
15 views
統計学の攻略_統計的仮説検定の9パターン.pdf
akipii Oga
•
27 views
シン3次元表示装置 ーその1ー
Takashi Yamanoue
•
126 views
Apache EventMesh を使ってみた
Yoshiyasu SAEKI
•
39 views
Advertisement
初めてのvue.js(2.x系)
初めてのVue.js(Vue.js 2.x 系) @フロントエンドカンファレンス福岡2019
自己紹介 - 井関 健人 - フリーランスのサーバーサイドエンジニア -
技術系講師してるということで駆り出される - 渋田 達也 - フリーランスのフロントが得意な、なんでもエンジニア - 前実行委員長ということで駆り出される
本資料について - 本資料を用いた営利活動はご遠慮ください
本日のスケジュール - Vue.js って
なーに? - Vue.js で商品一覧っぽのを作ってみる
進め方 - 基本的には解説しながら手を動かしてもらいます - 手を動かしてもらいたい部分スライドには マークを付けています -
ソースは全部手打ちする必要はなく、基本コピペでOKです 作業タイム
対象バージョン - Vue.js 2.x
系
Vue.js って、なーに?
Vue.js とは? - 読み方 -
びゅーじぇいえす - 公式 - https://jp.vuejs.org/index.html - 作者曰く - WebUIを構築するための「プログレッシブフレームワーク」
プログレッシブ? - プログレッシブ:漸進的な
フレームワーク? - フレームワーク framework -
① 骨組み。骨格。枠組み。 - ② 体制。組織。 - つまり、 「こういう便利な機能を用意した」から 「こういう方針で作ってね」が整備されたライブラリ
開発の方針があるといいことあるの? - 保守性が向上 - どのファイルに何を書くかが決まる -
ルールに則ってソースを書いていれば、 他の人が見てもどこで何をしているかが理解しやすい
- 特徴(プログレッシブフレームワーク) - 既存のサイトにも少しずつ使い始められる -
おすすめの利用箇所 - Webサイト内の小規模な機能 - 入力フォームとフォームの確認画面 - 小規模なSPA - 中大規模なSPAも可能だが、しっかりとした設計が必須 Vue.js とは?
ページ遷移のたびに HTML, js
を取得 SPA: Single Page Application 従来のWEB SPA index.html list.html detail1.html /index.html /app.js /items /items/1 初回のみ HTML, js を取得 ページ遷移は js による DOMの再構築で実現 描画に必要な情報は json などで都度取得 json json html html html html
- Web UI
を作るための - 既存のサイトにも、ちょっとずつ組み込める便利な機能 - イチから全部作り直さなくてOK - 何かを作るための骨組みと方針 - こういう風に作ったら良いよー - 本質的には「SPAフレームワーク」ではない(後述) つまり、Vue.jsは?
開発環境の準備 ~ローカル開発~
ローカル + ブラウザ 作業タイム 1.
自分のPCに任意の場所に、 vue_workshopという名前のディレクトリを作成 2. 作ったディレクトリをVsCodeやAtomなどのエディタで開く 3. vue_workshopの中に ファイル index.html と index.js を作成 - 内容は次のスライド参照
index.html の内容 作業タイム <!DOCTYPE html> <html> <head> <meta
http-equiv=”Pragma” content=”no-cache”> </head> <body> <div> SAMPLEコード </div> <script src="./index.js"></script> </body> </html>
index.js の内容 作業タイム alert("JavaScript is
working!!!")
- ファイルを作成できたら、index.html をブラウザで開く -
Visual Studio Codeであれば、 ファイル名を右クリックし、「パスのコピー」でコピーできる ローカル + ブラウザ 作業タイム
ブラウザで index.html を確認してみる 作業結果チェック -
アラートが出た後、こんな感じになればOK
Vue.js が提供する機能
Vueの作者が考えるフロントエンドのフレームワーク要素 引用:https://docs.google.com/presentation/d/1WnYsxRMiNEArT3xz7xXHdKeH1C-jT92VxmptghJb5Es/edit#slide=id.g5fc474681_041
- Declarative Rendering(宣言的レンダリング) -
Component System(コンポーネントシステム) - Client Side Routing(クライアントサイドでのルーティング) - Large Scale State Management(大規模状態管理) - Build System(ビルドシステム) Vueの作者が考えるフロントエンドのフレームワーク要素
- Declarative Rendering(宣言的レンダリング) -
Component System(コンポーネント システム) - Client Side Routing(クライアントサイドでのルーティング) - Large Scale State Management(大規模状態管理) - Build System(ビルドシステム) Vue.jsと周辺ライブラリの責任範囲の区分け 周辺ライブラリ 担当 Vue.js担当
- Declarative Rendering(宣言的レンダリング) -
Component System(コンポーネント システム) - Client Side Routing(クライアントサイドでのルーティング) - Large Scale State Management(大規模状態管理) - Build System(ビルドシステム) ここからは以下の2つを説明します 周辺ライブラリ 担当 Vue.js担当
- 単純なテンプレート構文で宣言的にデータを DOM
に描画する - 詳細はサンプルを見ながら確認 - Vue.jsの利用には下記のファイルをHTMLに読み込む必要がある - https://cdn.jsdelivr.net/npm/vue/dist/vue.js Declarative Rendering(宣言的レンダリング)
<!DOCTYPE html> <html> <head> <meta http-equiv=”Pragma”
content=”no-cache”> </head> <body> <div id="app"> {{ message }} </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="./index.js"></script> </body> </html> Declarative Rendering(宣言的レンダリング)の例 参考元:https://jp.vuejs.org/v2/guide/index.html
new Vue({ el: "#app", data:
{ message: "Hello Vue!" } }) Declarative Rendering(宣言的レンダリング)の例 参考元:https://jp.vuejs.org/v2/guide/index.html
Declarative Rendering(宣言的レンダリング)の例
Component System(コンポーネント システム) -
宣言的レンダリングはとても便利 - ただし画面内のいろいろな箇所で利用するとゴチャゴチャする - これってプログラミングの昔からの課題 - ちゃんと責務に分けて、見通しを良くするために必要なのが Component System(コンポーネントシステム)
Component System(コンポーネント システム) -
ほとんどのWEBアプリケーションはコンポーネントに分解できる - ヘッダ、フッタ - グローバルナビ - コンテンツの一覧 - コンテンツの詳細 - SNSのシェア - などなど
スタバの商品一覧をコンポーネントに分解
スタバの商品一覧をコンポーネントに分解 ナビ 絞り込みメニュー 見出し SNS 商品一覧 商品詳細
Component System(コンポーネント システム) -
すごく雑に言えば、開発者で独自のhtmlタグを定義して、 様々なページでそれを再利用するというもの - コンポーネントは「自己完結した小さく再利用しやすい」形にする - コンポーネントを組み合わせ、アプリケーションを構築する - WEB標準の「WEBコンポーネント」を参考にしている
コンポーネントシステムのイメージ <div id="app"> <global-nav></global-nav> <item-filter></item-filter>
<sns-button></sns-button> <head-title></head-title> <items></items> <footer></footer> </div> ナ ビ 絞り込みメニュー 見出し SNS 商品一覧 商品詳 細
コンポーネントで構成されたアプリは木構造になる ルート グロナビ 絞り込み メイン 見出し SNS 一覧 フッタ
ルート グロナビ 絞り込み メイン 見出し リンク リンク リンク SNS 一覧 詳細
詳細 詳細 フッタ リンク リンク コンポーネントは小さなコンポーネントが集まって作られる
ルート グロナビ 絞り込み メイン 見出し リンク リンク リンク SNS 一覧 詳細
詳細 詳細 フッタ リンク リンク つまり小さなコンポーネントは再利用が可能
コンポーネントはある程度の塊でまたコンポーネントになる ルート グロナビ 絞り込み メイン 見出し リンク リンク リンク SNS 一覧 詳細
詳細 詳細 フッタ リンク リンク
ルート グロナビ 絞り込み メイン 見出し リンク リンク リンク SNS 一覧 詳細
詳細 詳細 フッタ リンク リンク コンポーネントで構成されたアプリは全体も1つのコンポーネントと捉えられる
Vue.jsの宣言的レンダリングの基本
// index.html <!DOCTYPE html> <html> <head> <meta
http-equiv=”Pragma” content=”no-cache”> </head> <body> <div id="app"> {{ message }} </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="./index.js"></script> </body> </html> Declarative Rendering(宣言的レンダリング)の例 参考元:https://jp.vuejs.org/v2/guide/index.html 作業タイム - index.htmlを以下の内容で作成
- index.jsを以下の内容で作成 // index.js new
Vue({ el: "#app", data: { message: "Hello Vue!" } }) Declarative Rendering(宣言的レンダリング)の例 作業タイム 参考元:https://jp.vuejs.org/v2/guide/index.html
index.htmlを表示するとこんな感じになる 作業結果チェック
// index.js new Vue({ el:
"#app", data: { message: "Hello Vue!" } }) // index.html <!DOCTYPE html> <html> <head> <meta http-equiv=”Pragma” content=”no-cache”> </head> <body> <div id="app"> {{ message }} </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="./index.js"></script> </body> </html> サンプルコードの解説
解説するには先のソースでは見づらい…?
宣言的レンダリングの例の重要なところだけ抜粋 // index.js new Vue({ el:
"#app", data: { message: "Hello Vue!" } }) // index.html <div id="app"> {{ message }} </div>
これからすること - index.js の内容を解説 -
index.html の内容を解説
先程のソースで何が起きてるのか(1) // index.js new Vue({ el:
'#app', data: { message: 'Hello Vue!' } }) - Vue.jsを使うための下準備 - new Vue() は Vue.js の定番パターン - Vueインスタンスを作る = Vueのコンポーネントを作る = '#app' 配下がコンポーネントになる(後述) - Vueの定義は「vue.js」ファイルに存在
- Vueインスタンスを作る時に設定をObject 型で渡せる -
どんなオブジェクトを作りたいかを指定 - 具体的な説明は次のスライドで 先程のソースで何が起きてるのか(2) // index.js new Vue({ el: '#app', data: { message: 'Hello Vue!' } })
- el プロパティ -
宣言的レンダリングが適用される要素を指定 - HTML と Vueインスタンス を紐付ける - 例では「id属性がappの要素」に 「Vueインスタンス」が紐付く // index.js new Vue({ el: '#app', data: { message: 'Hello Vue!' } }) 先程のソースで何が起きてるのか(3)
先程のソースで何が起きてるのか(4) - data プロパティ -
テンプレート構文(HTML)で利用できる変数を宣言 - 例では変数 message を宣言的レンダリングの 過程で利用できる - つまり、テンプレート構文上にある message という 記述は Hello Vue! になる // index.js new Vue({ el: '#app', data: { message: 'Hello Vue!' } })
- id属性 が
app の中で宣言的レンダリングしたい - テンプレートの中では - 変数 message は "Hello Vue !" - 上記内容で描画をしてください index.js の内容まとめ // index.js new Vue({ el: '#app', data: { message: 'Hello Vue!' } })
これからすること - index.js の内容を解説 -
画面を描画するために必要な情報を宣言 - index.html の内容を解説
- id属性 が
app のタグを用意 - index.jsの記述により、 この中が宣言的レンダリングの対象となる index.html では何を書いているのか(1) // index.html <div id="app"> {{ message }} </div>
- {{ message
}} - テンプレート構文 - {{ }} で囲まれた内容が評価され 文字列として埋め込まれる - 「data要素で指定した値」や「式の戻り値」 などを指定できる - 例ではindex.js で宣言した、要素dataのmessageが埋め 込まれる index.html では何を書いているのか(2) // index.html <div id="app"> {{ message }} </div>
- 宣言的レンダリングの対象範囲の指定 - index.jsと合わせて、 <div
id="app"> の中はテンプレートになる - index.jsで用意した変数の利用 - message には index.jsで指定した値を埋め込む index.html の内容まとめ // index.html <div id="app"> {{ message }} </div>
- html上に描画したい内容や適用範囲を テンプレート構文、HTMLタグを利用し宣言 - js上で描画に必要となる内容を宣言 -
テンプレートとして扱うHTML要素 - テンプレート上で使う変数、関数など テンプレートとその中で利用する値(など)を宣言し、描画してもらう 宣言的レンダリング って何なの? ポイント
宣言的レンダリング のうまみ - ビュー
と 値 の 記述を明確に分離できる - 変数化し抽象度を上げることで、テンプレート全体の見通しが良い - 「表示のON/OFF」や「繰り返し」のようなロジックを宣言的に書ける - DOMのappend、remove地獄から抜け出せる ポイント
- 画面の再レンダリングコストが低い - 仮想DOMという仕組みで、 純粋なJavaScriptのappendChildなどよりも低コスト(らしい) -
Reactでも仮想DOMを利用しているので、Vue.js の専売特許じゃない Vue.jsを利用した宣言的レンダリングのうまみ
商品一覧っぽいものを作りながら学ぶ Vue.jsの宣言的レンダリング
- index.html と
index.js を書き換えてください - 内容は以降のスライドに掲載 - index.cssを作成してください - 場所は index.htmlと同じフォルダ - 内容は以降のスライドに掲載 これから商品一覧っぽいものを作ります
- かなり長いので以下のURLにある内容をコピペしてください - https://gist.github.com/take2webservice/1e32992c49fa7eb9988210a1ef0 cd72c index.html
の内容 作業タイム
- Raw を押すと、index.htmlだけを表示してくれます [補足]index.html
の内容 作業タイム
index.js の内容 作業タイム // index.js new
Vue({ el: '#app', data: { } })
index.css の内容 作業タイム - 長いので以下のURLにある内容をコピペしてください -
https://gist.github.com/take2webservice/fc83bab849c0e32103edeb087c4 73947
編集した index.html をブラウザで開くとこんな感じ 作業結果チェック
- 商品一覧部分の<li>タグの部分が繰り返しで見通しが 悪いのでなんとかする - 追加読み込みボタンを押したら動くようにする(未実装) -
価格で並べ替えできるようにする(未実装) これからすること
Vue.jsには繰り返し表示の仕組みがあるらしい
配列を用いたタグ繰り返し(1) - v-for を
v-for ディレクティブという - 配列の要素数分タグを描画 - v-for をつけたタグを複数回描画する - 取り出した要素はタグの中で利用できる <タグ v-for="取り出した値を格納する変数名 in 配列" v-bind:key="一意な値"> ... </タグ> ポイント
- v-bind:key を
v-bind:key ディレクティブという - v-for ディレクティブを使うときは基本セットで使う - 配列の中の各要素を特定する一意な値を渡す必要がある 配列を用いたタグ繰り返し(2) <タグ v-for="取り出した値を格納する変数名 in 配列" v-bind:key="一意な値"> ... </タグ> ポイント
- まずは思い切って、liタグを最初の1つだけにする まずは繰り返すタグを選ぶ 実演のみ <ul class="items"> <li
class="item"> <img src="https://dummyimage.com/200.png/09f/fff" alt="dummy"> <div class="title">title1</div> <div class="price">1000円</div> </li> </ul>
- v-forディレクティブを使ってみる - ディレクティブの
" " の中は式として評価される v-forディレクティブで要素を繰り返してみる <ul class="items"> <li class="item" v-for="i in [1,2,3,4,5,6,7,8,9]" v-bind:key="i"> <img src="https://dummyimage.com/200.png/09f/fff" alt="dummy"> <div class="title">title1</div> <div class="price">1000円</div> </li> </ul> 実演のみ
編集した index.html をブラウザで開くとこんな感じ -
タイトルがすべて title1 になっている 実演のみ
でもこのままじゃ全部の商品名が同じ‥
{{ 変数 or
式 }} <div> {{ 変数 or 式 }} </div> ポイント - 「テンプレート構文」 と呼ばれる - new Vue 実行時の引数内のdataプロパティの値や、 その他のv-for ディレクティブで取り出した変数、 JavaScriptの式の結果などを埋め込める
- v-forディレクティブで配列から取り出した値を使ってみる - title
の後ろに、 {{ }} で i を出力してみる タイトルをv-forディレクティブの値を元に表示 <ul class="items"> <li class="item" v-for="i in [1,2,3,4,5,6,7,8,9]" v-bind:key="i"> <img src="https://dummyimage.com/200.png/09f/fff" alt="dummy"> <div class="title">title{{ i }}</div> <div class="price">1000円</div> </li> </ul> 実演のみ
編集した index.html をブラウザで開くとこんな感じ -
タイトルがすべて異なるようになっている 実演のみ
いやいや、値段とかも変えたいよね…?
v-for ディレクティブに dataプロパティ
の値を渡せる?
ならば商品情報をdataプロパティに持たせよう!
- `new Vue`
するときの引数の dataプロパティを書き換える index.js の書き換え 作業タイム new Vue({ el: '#app', data: { items: [ {title: 'title1', price: 1000, id: 1}, {title: 'title2', price: 1500, id: 2}, {title: 'title3', price: 1300, id: 3}, {title: 'title4', price: 1100, id: 4}, {title: 'title5', price: 2000, id: 5}, {title: 'title6', price: 1800, id: 6}, {title: 'title7', price: 1000, id: 7}, {title: 'title8', price: 400, id: 8}, {title: 'title9', price: 600, id: 9} ] } })
- まずは思い切って、liタグを最初の1つだけにする index.html の書き換え(1) 作業タイム <ul
class="items"> <li class="item"> <img src="https://dummyimage.com/200.png/09f/fff" alt="dummy"> <div class="title">title1</div> <div class="price">1000円</div> </li> </ul>
- 今まで配列を v-for
ディレクティブの中で配列を宣言していたが、 そこを data プロパティの中にある items に置き換える index.html の書き換え(2) 作業タイム <li class="item" v-for="item in items" v-bind:key="item.id"> <img src="https://dummyimage.com/200.png/09f/fff" alt="dummy"> <div class="title">title1</div> <div class="price">1000円</div> </li>
- タイトル と
価格 を itemsから取り出した変数 item を利用して表示 - itemはオブジェクトなのでドットでtitleとpriceを指定 index.html の書き換え(2) 作業タイム <li class="item" v-for="item in items" v-bind:key="item.id"> <img src="https://dummyimage.com/200.png/09f/fff" alt="dummy"> <div class="title">{{ item.title }}</div> <div class="price">{{ item.price }}円</div> </li>
編集した index.html をブラウザで開くとこんな感じ -
タイトルと価格が JavaScriptから取得できた - html の内容がスッキリした 作業結果チェック
- 商品一覧部分の<li>タグの部分が繰り返しで見通しが 悪いのでなんとかする - 追加読み込みボタンを押したら動くようにする(未実装) -
価格で並べ替えできるようにする(未実装) これからすること
ボタンクリックしたら動く仕組みが必要だな
- DOM要素にイベントを配置する際は、v-on ディレクティブを利用 -
clickの場合は、v-on:clickとなる - 他にもkeyup, mouseover, blur のような馴染みのイベントも有る - その場合、v-on:keyup や v-on:mouseoverとイベント名の 部分を書き換える必要がある イベントの配置のディレクティブ <タグ v-on:イベント名="実行する処理" ></タグ> ポイント
- ボタンを押したらアラートを出してみる - alert
ではなく this.window.alert なのは変数スコープが 通常のHTML上のJavaScriptとは異なるため index.html の書き換え 作業タイム <div class="btn_wrap"> <button class="more" v-on:click="this.window.alert('ボタン押した')">さらに読み込む</button> </div>
- さらに読み込むボタンを押すとアラートが表示される 編集した index.html
をブラウザで開くとこんな感じ 作業結果チェック
次は追加読み込みの関数が必要だな
- メソッドの宣言はVueインスタンス生成時 に渡すObjectの中にmethodsプロパティに 用意 - methodsはelやdataと同列 -
メソッド内でdataプロパティの値にアクセス する場合はthis.変数名と書く Vue.jsでのメソッドの定義 new Vue({ el: '#app', data: { }, methods: { 関数名(){ 関数の処理 } } }) ポイント
... 省略 {title: 'title9',
price: 600} ] }, methods: { loadItems() { alert('ボタン押した in メソッド') } } ... 省略 - 関数名は loadItems 、中の処理は先程のアラートを出すもの - methodsの中ではスコープが異なり、今度はthis.windowが不要 index.js の書き換え 作業タイム
index.html の書き換え - methodsで定義した関数は、dataプロパティに定義した値と同様に テンプレート上で参照できる 作業タイム <div
class="btn_wrap"> <button class="more" v-on:click="loadItems">さらに読み込む</button> </div>
- 読み込むボタンを押すとアラートが表示される 編集した index.html
をブラウザで開くとこんな感じ 作業結果チェック
methods: { loadItems() { const
items = [ {title: 'title10', price: 1000, id: 10}, {title: 'title11', price: 1500, id: 11}, {title: 'title12', price: 1300, id: 12}, {title: 'title13', price: 1100, id: 13} ] this.items.push(...items) } } - ボタンを押したら商品が増えるように関数を書き換えます - dataプロパティのitemsにアクセスするには this が必要になります index.js の書き換え 作業タイム
- さらに読み込むボタンを押すとアイテムがどんどん追加されます 編集した index.html
をブラウザで開くとこんな感じ 作業結果チェック
おや?itemsへの変更が画面に即時反映されるぞ?
リアクティブデータバインディング - Vue.jsは dataプロパティへの変更を自動 検知 -
変更があった場合などはwatcherという監 視人に通知が行われる - watcherへの通知がトリガーとなり、DOM の再描画が行う 引用: https://jp.vuejs.org/v2/guide/reactivity.html ポイント
毎回ランダムなアイテム名と価格にしたいな
index.js の書き換え methods: { loadItems()
{ this.addItems(5) }, createItem() { return { id: Math.random(), title: 'title' + Math.round(Math.random() * 100), price: Math.round(Math.random() * 100) * 100 } }, addItems(count) { const newItems = [...Array(count)].map(() => this.createItem()) this.items.push(...newItems) }, } 作業タイム - メソッドの中でメソッドを呼ぶ場合も this が必要になる
- 追加読み込み分がランダムになった 編集した index.html
をブラウザで開くとこんな感じ 作業結果チェック
最初に読み込む部分もランダム生成にできる??
`created`フック - new Vue()
が呼ばれたあと、 データの変更検知の準備が終わった状態で呼び 出される処理を記述 - まだテンプレートに変数などがマウントされる前 に処理が実行される - 描画する初期データの取得が実行されることが 多い ポイント new Vue({ el: '#app', data: { }, created(){ データマウント前の処理 }, ... })
data: { items: [] }, created
() { this.addItems(9) }, index.js の書き換え 作業タイム - data プロパティ にある items を「空の配列」にしておく - createdフックの中で items を初期化 - 関数の中では this をつけて data と methods の中を参照
- 最初の読み込み分もランダムになった 編集した index.html
をブラウザで開くとこんな感じ 作業結果チェック
- 商品一覧部分の<li>タグの部分が繰り返しで見通しが 悪いのでなんとかする - 追加読み込みボタンを押したら動くようにする(未実装) -
価格で並べ替えできるようにする(未実装) これからすること
並べ替えなら、dataを毎回書き換える感じかな?
もっといい方法があるらしい
- 自動的に値の再計算してくれる機能 - 内部で利用する値の変更を検知し 自動で再計算してくれる -
リアクティブ - 関数と似ているが、引数をとれない 算出プロパティ new Vue({ el: '#app', data: { }, computed: { 算出プロパティ名(){ return 値 } } }) ポイント
- sortedItemsという名前で算出プロパティ定義 - 内容は、itemsを価格の安い順に並べ替えるというもの data:
{ items: [] }, computed: { sortedItems(){ return this.items.sort((a, b) => a.price - b.price) } }, index.js の書き換え 作業タイム
- 並び順が安い順になるよう、v-for ディレクティブでは
items ではなく、sortedItems を使うように変更 index.html の書き換え 作業タイム <li class="item" v-for="item in sortedItems" v-bind:key="item.id"> <img src="https://dummyimage.com/200.png/09f/fff" alt="dummy"> <div class="title">{{ item.title }}</div> <div class="price">{{ item.price }}円</div> </li>
- 価格が安い順になった 編集した index.html
をブラウザで開くとこんな感じ 作業結果チェック
高い順、安い順、読み込み順で切り替えたいな
フォームの値の変更を検知 → computedで並べ替え
- 「入力フォームの値」と「dataプロパティの変数」の紐付けには input タグ
や select タグ と v-model ディレクティブを利用 - フォームの変更に対応し、v-modelで指定した値が書き換わる - 値の型については注意が必要 入力フォームの値 と dataプロパティの変数 の紐付け <input v-model="変数名" ></input> <select v-model="変数名" ></select> ポイント
- フォームと紐付けるための値 order
を定義 data: { items: [], order: 'normal' }, index.js の書き換え 作業タイム
- v-model ディレクティブ
で フォームと値 order を紐付け - 値の変更を目視で確認できるように テンプレート構文で orderの内容を表示する <div> <select class="order" name="order" v-model="order"> <option value="normal">読み込み順</option> <option value="low">価格が安い順</option> <option value="high">価格が高い順</option> </select> {{ order }} </div> index.html の書き換え 作業タイム
- selectの切り替えに応じて、normal, low,
highと表示が切り替わる 編集した index.html をブラウザで開くとこんな感じ 作業結果チェック
optionタグも v-for で書き換えられそう
- HTMLタグの属性にコンポーネントのプロパティを埋め込む - v-bind:~
のことは v-bind ディレクティブ と呼ぶ - 固定の値であれば、普通のHTMLのように指定してOK HTMLタグの属性の付与 <タグ v-bind:属性名="コンポーネントのプロパティ" ></タグ> ex. <タグ v-bind:value="dataプロパティに定義した変数 " ></タグ> ポイント
- 並べ替え用のselectのオプションも値として定義 v-forディレクティブで書き出すようにする data: { items:
[], order: 'normal', orderOptions: [ { text: '読み込み順', value: 'normal' }, { text: '価格が安い順', value: 'low' }, { text: '価格が高い順', value: 'high' } ] }, index.js の書き換え 作業タイム
index.html の書き換え <div> <select class="order"
name="order" v-model="order"> <option v-for="option in orderOptions" v-bind:key="option.value" v-bind:value="option.value"> {{ option.text }} </option> </select> {{ order }} </div> 作業タイム - v-bind:value で optionタグ の value属性 を設定 - v-for で取り出した値は、v-forを適用したタグ上でも利用できる
- 外見上は変わらないが、 selectの切り替えに応じて、normal, low,
high と表示が切り替わる 編集した index.html をブラウザで開くとこんな感じ 作業結果チェック
orderの値に応じて算出プロパティで並べ替える
- order を
参照し並べ替えのロジックを分岐 - sortは破壊的メソッドなので、[...this.items]で別オブジェクトを生成 sortedItems() { switch (this.order) { case 'low': return [...this.items].sort((a, b) => a.price - b.price) case 'high': return [...this.items].sort((a, b) => b.price - a.price) default: return this.items } } index.js の書き換え 作業タイム
- selectの変更に応じて並べ替えが行われるようになった - 追加読込しても並び替えした状態になる 編集した
index.html をブラウザで開くとこんな感じ 作業結果チェック
- 宣言的レンダリングのいいところ - Viewの構成の見通しがいい -
テンプレートにロジックが入りづらい まとめ
Vue.jsでコンポーネントシステム
Component System(コンポーネント システム) -
宣言的レンダリングはとても便利ですが、 画面内のいろいろな箇所で利用するとゴチャゴチャする - 変数や関数宣言が増えすぎる - これってプログラミングの昔からの課題 - ちゃんと責務に分けて、見通しを良くするために必要なのが Component System(コンポーネントシステム)
さっきまで作った一覧っぽいページなら
さっきまで作った一覧っぽいページなら 絞り込みメニュー 商品一覧 商品詳細 追加読み込み
Component System(コンポーネント システム) -
すごく雑に言えば、開発者で独自のhtmlタグを定義して、 様々なページでそれを再利用するというもの - コンポーネントは「自己完結した小さく再利用しやすい」形にする - コンポーネントを組み合わせ、アプリケーションを構築する - WEB標準の「WEBコンポーネント」を参考にしている
コンポーネントシステムのイメージ <div id="app"> <order-select></order-select> <item-list></item-list>
<show-more-button></show-more-button> </div> 絞り込みメニュー 商品一覧 追加読み込み
少しずつ「一覧」をコンポーネント化してみよう
- コンポーネントの定義 - 定義したコンポーネントを使う旨の宣言 -
コンポーネントをテンプレート上で使う コンポーネント化と利用のステップ
- 最低限templateプロパティに描画したいhtmlの記述があればOK - dataプロパティは「オブジェクトを返す関数」でなければならない コンポーネント定義
(Object型の変数) の用意 ポイント { template: `コンポーネントが描画するHTML(テンプレート)`, data(){ return {} } }
const ItemList =
{ template: `<div>{{message}}</div>`, data(){ return { message: "ここがコンポーネント" } } } 以下の内容で item_list.js を index.js と同じ階層に作る 作業タイム
- コンポーネントの定義 - 定義したコンポーネントを使う旨の宣言 -
コンポーネントをテンプレート上で使う コンポーネント化と利用のステップ
親コンポーネントで、子コンポーネントに名前を付け、使えるようにする - Vueインスタンス生成時の引数にcomponentsプロパティを定義 - componentsプロパティは
Object型の値 - プロパティ名 :「テンプレートで利用するタグ名」 - 値 :先程作った「コンポーネント定義」 ポイント components: { テンプレート上でのタグ名: コンポーネント定義 },
index.js を書き換える 作業タイム data: { items:
[], order: 'normal', orderOptions: [ { text: '読み込み順', value: 'normal' }, { text: '価格が安い順', value: 'low' }, { text: '価格が高い順', value: 'high' } ] }, components: { 'item-list': ItemList }, - dataプロパティの後ろに、componentsプロパティを定義 - Object中のプロパティは item-list という名前に対して、ItemList を定義
- コンポーネントの定義 - 定義したコンポーネントを使う旨の宣言 -
コンポーネントをテンプレート上で使う コンポーネント化と利用のステップ
</div> <item-list></item-list> <ul class="items"> <li class="item"
v-for="item in sortedItems" v-bind:key="item.id"> <img src="https://dummyimage.com/200.png/09f/fff" alt="dummy"> <div class="title">{{ item.title }}</div> <div class="price">{{ item.price }}円</div> </li> </ul> index.html を書き換える(1) 作業タイム - 既存の <ul> タグ の上に <item-list>というタグを用意
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="./item_list.js"></script> <script
src="./index.js"></script> index.html を書き換える(2) 作業タイム - index.js の読み込みの上に、item_list.jsの読み込みを追加
- item-list コンポーネント
が表示できている 編集した index.html をブラウザで開くとこんな感じ 作業結果チェック
ここまでの作業内容のまとめ - ItemList 変数にコンポーネントの定義をつくる -
Vue インスタンスを作る時に、 <item-list> タグを使えるように、先程の ItemList を渡す - index.html 上で <item-list>タグを記述 - index.html 上で、item_list.jsを読み込む
- タグ名の定義はケバブケース - 例)my-component-name -
理由)HTML の属性名は大文字小文字を区別しないから - タグ名は2単語以上で構成することが推奨される コンポーネント定義の注意点
コンポーネントの内容が固定ならここまでの方法でOK
でも、今のままじゃ一覧の機能としてはデグレ - 初回表示時に一覧が動的に描画されない - 追加読み込みが動かない -
ソートが効かない
これからやること - 初回表示時に一覧が動的に描画させる - 追加読み込みが動くようにする -
ソートを有効にする
商品情報は index.js、item_list.js どっちに持つ?
- コンポーネント内でのみ完結 - コンポーネント内の
data プロパティで保持 - 初回読み込み時に生成 or ajax で読み込むだけ - 値が定数で変更されない - コンポーネント外から影響を受ける - 影響範囲が最小となる親コンポーネントのdata プロパティで保持 - 後述の方法で親コンポーネントから値を受け取る コンポーネントで利用する変数の所在 ポイント
- 商品情報には以下のような制約がある - 追加読み込みの際に値が更新される必要がある -
並び替えの際に、order 変数を参照する必要がある - つまり - 商品情報 は item-list コンポーネント内で完結しない - よって - 商品情報は item_list.js ではなく index.js で管理する 商品情報 はどこにあるべき?
- 親コンポーネントから子コンポーネントに渡す値を Prop
と呼ぶ - テンプレート上で v-bindディレクティブを利用し、 Prop として「変数や式」を渡す <コンポーネント v-bind:Prop名="変数名 や 式"></コンポーネント> 子コンポーネントへの値の渡し方 ポイント
<div> <select class="order" name="order"
v-model="order"> <option v-for="option in orderOptions" v-bind:value="option.value" v-bind:key="option.value"> {{ option.text }} </option> </select> {{ order }} </div> <!-- ここにあった ul タグを削除 --> <item-list v-bind:items="sortedItems"></item-list> index.html を書き換える 作業タイム - 既存の商品一覧の ul タグを削除する - item-list コンポーネントに items という名前でsotedItems を渡す
- 親コンポーネントから子コンポーネントが受け取る値を Prop
と呼ぶ - 子コンポーネントの定義ではtemplateプロパティなどと並列に、 propsプロパティを用意する - 「受け取るProp名」と「受け取るPropのデータ型」のペアを与える 親コンポーネントからの値の受け取り方 props: { 受け取るProp名: 受け取るPropのデータ型 } ポイント
...(省略)... }, data(){ return { } }, props: { items:
Array } - dataプロパティは空のObjectを返させる - props プロパティで 「items Prop」を受け取る item_list.js を書き換える(1) 作業タイム
template: ` <ul class="items"> <li
class="item" v-for="item in items" v-bind:key="item.id"> <img src="https://dummyimage.com/200.png/09f/fff" alt="dummy"> <div class="title">{{ item.title }}</div> <div class="price">{{ item.price }}円</div> </li> </ul> `, ...(省略)... - templateプロパティの内容を、index.htmlのulタグに置き換える - v-for ディレクティブで扱う値が items になっている点に注意 item_list.js を書き換える(2) 作業タイム
- 要素が動的にだせるようになった - 追加読み込みも、ソートもできるようになってる 編集した
index.html をブラウザで開くとこんな感じ 作業結果チェック
v-bind:component-prop="items" props: { componenProp: String } -
v-bindディレクティブ で渡す時の Prop名 は「ハイフンつなぎ」 - propsプロパティ で受け取る時の Prop名 は「キャメルケース」 Prop 名の注意点 ポイント
他の要素もコンポーネント化してみよう 絞り込みメニュー 追加読み込み
これからやること - 追加読み込みコンポーネントを作る - (絞り込みメニューコンポーネントは尺の都合で省略)
show_more_button.js を index.js
と同じ階層に作る const ShowMoreButton = { template: ` <div class="btn_wrap"> <button class="more" v-on:click="onClick">さらに読み込む(c)</button> </div> `, methods: { onClick() { } } } 作業タイム - onClick メソッドは後で実装する
index.js を書き換える 作業タイム - 用意した
ShowMoreButton をテンプレート上で <show-more-button> タグで、利用できるようにする data: { order: 'normal', orderOptions: [ { text: '読み込み順', value: 'normal' }, { text: '価格が安い順', value: 'low' }, { text: '価格が高い順', value: 'high' } ] }, components: { 'items-component': ItemList, 'show-more-button': ShowMoreButton }
index.html を書き換える </div> <items-component ref="items"
v-bind:component-order="order"></items-component> <show-more-button></show-more-button> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="./item_list.js"></script> <script src="./show_more_button.js"></script> <script src="./index.js"></script> 作業タイム - 既存の <div class="btn_wrap"> を <show-more-button> に置き換える - show_more_button.js を index.js の前に読み込むようにする
- 無事コンポーネント化できたら、 ラベルが「さらに読み込む(c)」となっている 編集した index.html
をブラウザで開くとこんな感じ 作業結果チェック
コンポーネント間の指示ってどうするんだ?
- メソッドなどでイベントを発行することで、 親コンポーネントでイベントを取得することができる カスタムイベントの発行 ポイント this.$emit(カスタムイベント名)
show_more_button.js を 書き換える const
ShowMoreButton = { template: ` <div class="btn_wrap"> <button class="more" v-on:click="onClick">さらに読み込む(c)</button> </div> `, methods: { onClick(){ this.$emit('click') } } } 作業タイム - onClick メソッドで click イベントを発行する
- カスタムイベントを発行する子コンポーネントのタグには、 v-onディレクティブで親コンポーネントが実行するメソッドを指定可能 親コンポーネントでのイベントの取得 ポイント <タグ v-on:カスタムイベント名="実行するメソッド名"></タグ>
- click イベントを発行する
show-more-button に v-onディレクティブでイベント発行時に実行するメソッド名を指定 index.html を書き換える 作業タイム </div> <items-component ref="items" v-bind:component-order="order"></items-component> <show-more-button v-on:click="loadItems"></show-more-button> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="./item_list.js"></script> <script src="./show_more_button.js"></script> <script src="./index.js"></script>
- さらに読み込むボタンで追加読み込みができたらOK 編集した index.html
をブラウザで開くとこんな感じ 作業結果チェック
- コンポーネントのポイント - 今回はやらなかったが、 コンポーネントをページごとに使い回せる -
ただし、上手にコンポーネントを分けないと 不要なイベントの発行などが増えて読みづらくなる Vue.jsのコンポーネントまとめ
Vue CLI の紹介
- Vue.js での開発を高速に行うためのシステム -
様々な既存のエコシステムを - 最近は Vue.js をフル活用した開発で、主に使って行われる(はず) - 手軽に Vue CLI の機能の一部を体験できる資料はこちら - https://docs.google.com/presentation/d/1TkUZ9xYM8-9qvDmEeePcRE_DO1kZuxlPzg Lr8_eceAo/edit?usp=sharing Vue CLIとは?
- 時間の関係でこちらに置き換えたものをおいています - https://github.com/take2webservice/ItemList -
帰宅後に今日ご自身で書いたソースコードと見比べてみてください 一覧画面をVue CLI用に置き換えるとどうなるか
- Vue.js の
ミニマムな使い方を足早に行いました - 今回のワークショップはVue.js の 「触り」の部分になります - ぜひ家に帰ってからも手を動かしてみてください Vueワークショップまとめ
書籍の紹介(1) - https://www.amazon.co.jp/dp/4863542453/ - Vue.js
の 基本的な話が載っている
書籍の紹介(2) - https://www.amazon.co.jp/dp/B07TB87P7M - コンポーネントの分け方に関するいい本
ひきつづき フロントエンドカンファレンスを お楽しみください おわり
尺調整用おまけ
商品がない場合にメッセージを出したい
- v-if ディレクティブ
をつけた、タグ自体の表示の出し分け - 値がfalseの場合の処理を書きたい場合、続くタグに v-elseタグをつける - falseの処理が不要なら省略可 表示の出し分けをする方法 ポイント <タグ v-if="真偽値を返す値">trueの場合に表示</タグ> <タグ v-else>falseの場合に表示</タグ>
item_list.js を書き換える(1) 作業タイム - itemsに商品があるかを判断する算出プロパティhasItem
を用意 props: { items: Array }, computed: { hasItem() { return this.items.length > 0 } },
- template プロパティを書き換え、 v-if
ディレクティブとv-else ディレクティブで出し分ける item_list.js を書き換える(2) 作業タイム template: ` <ul class="items" v-if="hasItem"> <li class="item" v-for="item in items" v-bind:key="item.id"> <img src="https://dummyimage.com/200.png/09f/fff" alt="dummy"> <div class="title">{{ item.title }}</div> <div class="price">{{ item.price }}円</div> </li> </ul> <div v-else>商品がありません</div> `,
- crated フックでの初期処理を削除し、 最初の表示時に商品がない状態にする index.js
を書き換える 作業タイム created () { },
- 最初には「商品がありません」と表示されればOK 編集した index.html
をブラウザで開くとこんな感じ 作業結果チェック
- 「さらに読み込む」ボタンをおして、 「商品がありません」が消え、一覧が表示されればOK 編集した index.html
をブラウザで開くとこんな感じ 作業結果チェック
v-if に似たディレクティブで v-show
ディレクティブがある - v-if - false の場合DOM上からタグを消す - v-show - false の場合DOM上には残る - スタイルでdisplay:none; を付与し見た目から消す v-if と v-show ポイント
最初に一瞬表示されるテンプレート構文は嫌だな
- v-cloak ディレクティブ -
Vue インスタンスのコンパイルが終了するまでの間残存し、 コンパイルが終わるとDOM上から消える - CSS と組み合わせて、Vue インスタンスのコンパイルが終わるまで 表示を隠せる 初期表示を隠すテクニック <タグ v-cloak></タグ> ポイント
index.html を書き換える 作業タイム <body> <div id="app"> <div> <select
class="order" name="order" v-model="order" v-cloak> <option v-for=" option in orderOptions" v-bind:key="option.value" v-bind:value="option.value"> {{ option.text }} </option> </select> </div> - v-cloakディレクティブ を 「テンプレート構文の表示を隠したい要素」に付与する
- v-cloak 属性があるタグを表示しないスタイルを追記する index.css
を書き換える 作業タイム .order { font-size: 1.3em; } [v-cloak] { display: none; }
- 最初に一瞬、{{ option.text
}} が表示しなくなればOK 編集した index.html をブラウザで開くとこんな感じ 作業結果チェック
ひきつづき フロントエンドカンファレンスを お楽しみください 今度こそ おわり
Advertisement