Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
vuejs-meetup
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
kazupon
January 29, 2015
Programming
8.5k
16
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
vuejs-meetup
Railsで作られたサービスにVue.jsを導入したというお話
kazupon
January 29, 2015
More Decks by kazupon
See All by kazupon
プラグインで拡張される Context をtype-safe にする難しさと設計判断
kazupon
2
1.9k
Oxlint JS plugins
kazupon
1
1.4k
gunshi
kazupon
1
260
Nitro v3
kazupon
2
600
わたしのOSS活動
kazupon
3
650
Vapor Revolution
kazupon
3
4.3k
Vue.js最新動向
kazupon
3
1.7k
Vue 3.4
kazupon
13
4.9k
Vue & Vite Rustify
kazupon
4
2.5k
Other Decks in Programming
See All in Programming
AWS DevOps Agentで インシデント対応をAIに任せたい
honmarkhunt
7
3.3k
モバイル交通系ICへのチャージ実例から考える、クロスプラットフォーム開発におけるiOS実機テスト設計とCI運用
yusuga
1
550
App Intentsのビルドプロセスを支える技術
kntkymt
0
460
パズルゲームの作り方 / how to make puzzle games
kaityo256
PRO
2
240
技術的負債を組織課題として解く-増えすぎたマイクロサービスとの戦い-
reimaru
1
2.5k
IBM Bob Dojo #1 仕様駆動開発入門
oniak3ibm
PRO
0
290
そのリトライ、死んだコネクションを使い回していませんか ── GoのHTTPクライアントとHTTP/2を実プロダクト障害から学び直す
myus4a
0
300
速く作れる。その次は、速く確かめられる開発へ 〜AIネイティブ開発を支える、Shift Down〜 / Can build fast. Next, moving to development where we can verify fast.
rkaga
7
5k
標準パッケージに uuid が追加された 背景から見る Go らしい意思決定 / go_127_uuid_decision
convto
5
8.8k
JAWS-UG 東京支部が始める、JAWS-UG支部コラボ / JAWS-UG lunchtime LT Collaboration
y0hgi
0
160
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
1
350
thread_parallel_with_free-threaded_Python_and_NumPy.pdf
riku_sakamoto
0
360
Featured
See All Featured
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
410
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
540
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.6k
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
74
42k
Paper Plane (Part 1)
katiecoart
PRO
2
11k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
470
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
460
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
620
Mobile First: as difficult as doing things right
swwweet
225
10k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
520
Transcript
RailsͰ࡞ΒΕͨαʔϏεʹ Vue.jsΛಋೖͨ͠ͱ͍͏͓ Vue.js Meetup 2015-01-28 @kazupon
About Me • @kazupon • ॴଐɿCUUSOO SYSTEM • ׂɿϦʔυΤϯδχΞ •
ࣄɿ ϑϩϯτΤϯυɺόοΫΤϯυɺΠϯϑϥɺͳͲɺγεςϜ શൠɺ΄΅ϑϧελοΫʂ • ࡞ͬͨVue.jsͷPluginɿ vue-i18n: https://github.com/kazupon/vue-i18n vue-validator: https://github.com/kazupon/vue-validator
Vue.jsΛ͍ͬͯΔฐࣾαʔϏε
Vue.jsಋೖલͷΞʔΩςΫνϟ αʔό ΫϥΠΞϯτ
• αʔόαΠυͰHTMLΛϨϯμϦϯά͢Δయܕతͳ ϖʔδભҠͷΞϓϦέγϣϯ • UX͕ٻΊΒΕΔ෦ɺjQueryͷϓϥάΠϯɺAjax ͳͲͰରԠ • JavascriptɺCSS Rails
ͷ Sprockets ʹ͓·͔ͤ
͔͠͠ɺ͕ɻɻɻ
Կ͕ͳͷ͔ • ΫϥΠΞϯταΠυಛʹ MVC ͳͲͷΞϓϦέʔ γϣϯΞʔΩςΫνϟ͕ͳ͘ɺยखؒΦϨΦϨΞʔ ΩςΫνϟͰΧΦεʹͳ͍ͬͯΔ • ഭΓདྷΔϏδωεཁ݅ͰɺUI/UXվળʹΑΔߴͳ UIΛཁٻ͢Δ࣮͕૿͖͑ͯͯɺϝϯς͕ͭΒͨ
Μɻɻɻ
Rails & data-*Λͬͨ ΦϨΦϨController # Javascript $(document).ready(function () { var
module = constantnize($(‘body’).data(‘controller-name’)); if (module) { module.init(); } }); # HTML template <html> ... <body data-controller-name=“<%= contoller.controller_name %>”>...</doby> ... </html>
jQueryΠϕϯτϋϯυϥ & DOMૢ࡞ͷཛྷ $('body .projects').on('focus', 'textarea', function () { var
value = $(this).val().split(‘\n’); var value_row = 0; $.each(value, function(i, val) { value_row += Math.max(Math.ceil(val.length / self.cols), 1); }); var input_row = $(this).attr('rows'); var original_row = $(this).data('default_row'); var next_row = (input_row <= value_row) ? value_row + 0 : Math.max(value_row + 1, original_row); $(this).attr('rows', next_row); });
͜ͷ··ͰϠόΠʂ Ϋιίʔυ͕૿͑Δ͔Γʂʂ
͜ΕҎ্ϠόΫͳΒͳ͍Α͏Α͏ Կͱ͔ͤͶʂ
ͱ͏͍͏Θ͚ͰVue.jsΛಋೖ http://vuejs.org
ͳͥɺVue.jsΛಋೖͨ͠ͷ͔ʁ
લఏ݅ • طଘͷjQueryͰॻ͔Εͨίʔυࢿ࢈Λ׆༻Ͱ͖Δ͜ͱ • ݱঢ়ͷΞϓϦέʔγϣϯʹରͯ͠ΈࠐΈ༰қͰɺط ଘ࣮ʹରͯ͠෭࡞༻͕΄ͱΜͲͳ͍͜ͱ • ίϩίϩUI༷͕มΘΔϏδωεཁ݅ʹରͯ͠ɺ͜Ε ·ͰͲ͓Γɺ։ൃεϐʔυΛҡ࣋Ͱ͖Δ͜ͱ •
ଞͷϓϩδΣΫτར༻ՄೳͰ͋Δ͜ͱ • ͙͢ʹ͑Δ͜ͱ
ͱ͍͏Θ͚ͰҎԼΛݕ౼
Vue.jsΛಋೖͨ͠ཧ༝ • ଞͷϥΠϒϥϦͱׯব͕΄ͱΜͲͳ͍ • σʔλόΠϯσΟϯάͰɺੜDOMૢ࡞ͷ࣮Λͦ ΜͳʹΨϦΨϦॻ͔ͣͱɺUIͷදࣔɾৼ͍Λָ ʹ࣮Ͱ͖Δ • CommonJS ϕʔεͰϞδϡʔϧԽͰ͖Δ
• ֶशίετ͕͍
Vue.jsΛಋೖͨ͠ݱঢ়
ViewModel • Vue.jsͷWebαΠτʹॻ͍ͯ͋ Δͱ͓ΓɺVue.jsͷϞδϡʔϧ ͱͯ͠ར༻Ͱ͖ΔΑ͏ɺ Vue.extendͰαϒΫϥεԽ͠ ͯɺmodule.exports ͢Δ component system:
http://vuejs.org/guide/components.html var Modal = module.exports = Vue.extend({ template: require('./modal.html'), components: { ... }, data: function () { return { title: '', ... } }, methods: { show: function () { ... }, hide: function () { ... }, onClickClose: function (e) { ... } } });
ViewModelͷొ • Vue.extendͰϞδϡʔϧԽ͠ ͨͷɺVue.component Ͱ άϩʔόϧొͤͣɺɺ ඞཁͳͱ͖ʹ require ͯ͠ componentsΦϓγϣϯͰࢦఆ
• ޙ v-component ɺv-ref Ͱ ΨγΨγ͏ # ViewModel var Widget = module.exports = Vue.extend({ template: require('./widget.html'), ... components: { modal: require('../modal') }, ... methods: { onClickOpenModal: function () { this.$.modal.show(); }, ... } }); # View <div class=“widget”> ... <div v-component="modal" v-ref="modal"></div> ... </div>
ૄ݁߹ͳViewModel • TODOϦετͷΑ͏ͳɺࢠؔ ͕͋ΔViewModelΛ࡞͢ Δ߹ɺΠϕϯτAPIΛۦ • Πϕϯτ໊conflict͕ى͖ͳ ͍Α͏namespaceΛར༻ • v0.11.4Ͱɺv-eventsΛ͑
ɺࢠଆͰ$emitͰൃՐͨ͠Π ϕϯτर͑·͢ … events: { ‘ChildWidget:remove’: function (vm, index) { // remove the item from the item collection // … }) } … onClickRemoveItem: function (event, index) { this.$dispatch( ‘ChildWidget:remove’, event.targetVM, index ); }) onClickRemoveItem: function (event, index) { this.$dispatch( ‘ChildWidget:remove’, event.targetVM, index ); }) ࢠ1 ࢠx ϢʔβʔͷΠϯλ ϥΫγϣϯʹΑͬͯ আཁٻ͕དྷͨΒɺΠϕϯτΛdispatch͠ ͯɺଆͰআͯ͠Β͏
Template • View ʹ૬͢Δ Template(html) ɺrequire Ͱ͖Δ Α͏ɺͳΔ͘ϑΝΠϧͱͯ͠ཧ # Tempalte
<div class=“widget”> ... <div v-component="modal" v-ref="modal"></div> ... </div>
Filter • FilterViewModelͷ࣌ͱಉ ༷ɺmodule.exportsͯ͠ɺ requireͰ͖ΔΑ͏ʹ͍ͯ͠Δ • FilterΛొ͢Δͱ͖ɺ ComponentԽͨ͠ViewModel ͷͱ͖ͱಉ༷ɺVue.filterͰά ϩʔόϧొͤͣɺඞཁͳͱ
͖ʹrequireͯ͠ɺfiltersΦϓ γϣϯʹࢦఆ͍ͯ͠Δ # Filter module module.exports = { required: function required (val) { return !val ? false : true; }, ... }; # ViewModel var filters = require(‘./filters’); var Invitation = module.exports = Vue.extend({ template: require('./invitaion'), ... filters: { validateRequired: function (val) { this.validation.email = filters.required(val); return val; }, … } });
Resource • ಛʹpluginతͳͷΛ͏͜ͱ ͳ͘ɺϥΠϒϥϦ(superagent) ΛͬͯɺWebAPIͷend-point ʹϦΫΤετ͢Δ͜ͱͰ resourceʹΞΫηε superagent: http://visionmedia.github.io/superagent/ var
request = require('superagent-browserify'); module.exports = list; function list (params, fn) { params = params || {}; var endPoint = ‘/api/v1/xxx’; // ... request .get(endPoint) .query(params) .withCredentials() .end(fn); }
Plugin • vue-i18n: ࠃࡍԽରԠ • αʔόଆͰ cookie ʹઃఆͨ͠ locale ใΛऔಘͯ͠ɺදࣔॲཧ
͢Δݴޠͷઃఆ • v-t ·ͨ Vue.t Ͱ Rails ͷ i18n like ʹ key Λࢦఆͯ͠ར༻ # Entrypoint var cookie = require('cookie-cutter'); var Vue = require('vue'); var i18n = require('vue-i18n'); // locale setting var locale = cookie.get('locale') || ‘en’; Vue.use(i18n, { lang: locale, locales: { en: require('./locales/en.json'), ja: require('./locales/ja.json') } }); # Tempalte <div> <p v-t=“foo.bar"></p> </div> vue-i18n: https://github.com/kazupon/vue-i18n
Ϟδϡʔϧཧํ๏ • Vue.jsͰॻ͍ͨͷར ༻͢Δͷɺapp/ assets/javascriptsͱ ผʹઐ༻σΟϨΫτϦ Λ࡞ͬͯͦ͜ͷதͰ ཧ . !""
Capfile !"" Gemfile !"" Gemfile.lock !"" README.md !"" Rakefile !"" app !"" config !"" config.ru !"" db !"" frontend !"" lib !"" log !"" public !"" script !"" spec #"" vendor ͜ͷσΟϨΫτϦ Ͱཧ
Ϟδϡʔϧߏ • ಠࣗنͰߏԽ • ԼهͷΑ͏ʹɺVue.jsͰॻ͍ͨ Ϟδϡʔϧ͚ͩͰͳ͘ɺଞͷ ϞδϡʔϧҰॹʹཧ - ڞ௨ϥΠϒϥϦ -
UIؔ࿈ - APIΫϥΠΞϯτ - ଟݴޠϦιʔε . !"" Makefile !"" gulpfile.js !"" index.js !"" lib $ !"" api $ ... $ !"" utils.js $ !"" validates.js $ #"" widgets !"" locales $ !"" en.json $ #"" ja.json #"" package.json
ϞδϡʔϧͷϏϧυ • Gulp + BrowserifyͰϞδϡʔ ϧԽͨ͠JSίʔυ܊ͨͪΛɺ ·ΔͬͱϏϧυͯ͠όϯυϧ • ϏϧυʹΑΓόϯυϧͨ͠JS ϑΝΠϧΛɺapp/assets/
javascripts ʹஔͤͯ͞ɺ application.jsͰrequireͤ͞Δ • ࠷ऴతʹSprocketsͰ·͔ͤΔ . !"" app $ !"" assets $ $ !"" images $ $ !"" javascripts $ $ $ !"" application.js $ $ $ !"" bundle.js $ $ $ ... $ $ $ #"" zzz.js $ $ #"" stylesheets !"" frontend $ !"" Makefile $ !"" gulpfile.js $ !"" index.js $ !"" lib $ $ !"" api $ $ ... $ $ !"" utils.js $ $ !"" validates.js $ $ #"" widgets $ !"" locales $ $ !"" en.json $ $ #"" ja.json $ #"" package.json ...
ϨΨγʔίʔυͷΈࠐΈ • RailsͷControllerͰϨϯμϦ ϯά͞ΕΔςϯϓϨʔτϑΝ ΠϧʹscriptλάͰɺrequire Ͱ·Δͬͱ࣮ͨ͠ ViewModelΛҾ͖ࠐΜͰɺ ΠϯελϯεԽ͢Δ͚ͩ • ॳظσʔλ͕ඞཁͳΒɺ
JSONΛϨϯμϦϯάͯ͠ dataʹηοτ # erb template ... <div id="widgets" v-cloak v-repeat="item: items" v-component="widget-item"></div> ... <script> (function () { var Widget = require('bundle').Widget; var data = JSON.parse('<%= j(object.to_json).html_safe %>'); new Widget({ el: '#widgets', data: data }); })();
Vue.jsΛಋೖͨ݁͠Ռ • ࣮ͨ͠ComponentΛɺ؆୯ʹ ͍·ΘΓͨ͠Γɺ֦ுͨ͠Γ͢Δ ͜ͱ͕Ͱ͖ΔΑ͏ʹͳͬͨ - ։ൃੜ࢈ੑ্ - ϝϯςφϯεੑ্ Vue.jsͰ࣮ͨ͠
Component
Vue.jsΛಋೖͨ݁͠Ռ • ଞͷϓϩδΣΫτͰɺϥΠϒϥϦײ֮Ͱɺ ComponentΛҾ͖ࠐΜͰར༻Ͱ͖ΔΑ͏ͳͬͨ - Ϟδϡʔϧੑ্ Vue.jsͰ࣮ͨ͠ ComponentΛ֦ு
·ͱΊ • jQueryͷΫιίʔυ͕૿৩͢ΔΧΦεͳΫϥΠΞϯτ αΠυ • զʑͷχʔζʹ͋ͬͨVue.jsΛ࠾༻͢Δ͜ͱͰɺΫϥ ΠΞϯταΠυΛߏԽ • ϨΨγʔίʔυΛ͋·Γमਖ਼͢Δ͜ͱͳ͘ΈࠐΊΔ ͜ͱ͕Ͱ͖ɺ͔ͭଞͷϓϩδΣΫτͰར༻Մೳ
• ͜Ε·ͰͲ͓Γ։ൃεϐʔυΛҡ࣋ͭͭ͠ɺΧΦεͩͬ ͨੈքΛվળ͢Δ͜ͱ͕Ͱ͖ͨ
͓·͚
Vue.jsʹର͢Δෆຬ • UIͷঢ়ଶͱModelͷ͕ͬͪ͝Όʹͳ͍ͬͯΔɺ $data Λ͍ͨ͠ • αʔόαΠυͰ Vue.render Έ͍ͨͷͰɺಈ͔ ͯ͠ϨϯμϦϯά͍ͨ͠
͝੩ௌ ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ