Slide 1

Slide 1 text

RailsͰ࡞ΒΕͨαʔϏεʹ Vue.jsΛಋೖͨ͠ͱ͍͏͓࿩
 Vue.js Meetup 2015-01-28 @kazupon

Slide 2

Slide 2 text

About Me • @kazupon • ॴଐɿCUUSOO SYSTEM • ໾ׂɿϦʔυΤϯδχΞ • ࢓ࣄɿ
 ϑϩϯτΤϯυɺόοΫΤϯυɺΠϯϑϥɺͳͲɺγεςϜ શൠɺ΄΅ϑϧελοΫʂ • ࡞ͬͨVue.jsͷPluginɿ
 vue-i18n: https://github.com/kazupon/vue-i18n
 vue-validator: https://github.com/kazupon/vue-validator

Slide 3

Slide 3 text

Vue.jsΛ࢖͍ͬͯΔฐࣾαʔϏε

Slide 4

Slide 4 text

Vue.jsಋೖલͷΞʔΩςΫνϟ αʔό ΫϥΠΞϯτ

Slide 5

Slide 5 text

• αʔόαΠυͰHTMLΛϨϯμϦϯά͢Δయܕతͳ ϖʔδભҠͷΞϓϦέγϣϯ • UX͕ٻΊΒΕΔ෦෼͸ɺjQueryͷϓϥάΠϯɺAjax ͳͲͰରԠ • JavascriptɺCSS ͸ Rails ͷ Sprockets ʹ͓·͔ͤ

Slide 6

Slide 6 text

͔͠͠ɺ໰୊͕ɻɻɻ

Slide 7

Slide 7 text

Կ͕໰୊ͳͷ͔ • ΫϥΠΞϯταΠυ͸ಛʹ MVC ͳͲͷΞϓϦέʔ γϣϯΞʔΩςΫνϟ͕ͳ͘ɺยखؒΦϨΦϨΞʔ ΩςΫνϟͰΧΦεʹͳ͍ͬͯΔ • ഭΓདྷΔϏδωεཁ݅ͰɺUI/UXվળʹΑΔߴ౓ͳ UIΛཁٻ͢Δ࣮૷͕૿͖͑ͯͯɺϝϯς͕ͭΒͨ Μɻɻɻ

Slide 8

Slide 8 text

Rails & data-*Λ࢖ͬͨ ΦϨΦϨController # Javascript $(document).ready(function () { var module = constantnize($(‘body’).data(‘controller-name’)); if (module) { module.init(); } }); # HTML template ... ”>... ...

Slide 9

Slide 9 text

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); });

Slide 10

Slide 10 text

͜ͷ··Ͱ͸ϠόΠʂ Ϋιίʔυ͕૿͑Δ͹͔Γʂʂ

Slide 11

Slide 11 text

͜ΕҎ্ϠόΫͳΒͳ͍Α͏Α͏ Կͱ͔ͤͶ͹ʂ

Slide 12

Slide 12 text

ͱ͏͍͏Θ͚ͰVue.jsΛಋೖ http://vuejs.org

Slide 13

Slide 13 text

ͳͥɺVue.jsΛಋೖͨ͠ͷ͔ʁ

Slide 14

Slide 14 text

લఏ৚݅ • طଘͷjQueryͰॻ͔Εͨίʔυࢿ࢈Λ׆༻Ͱ͖Δ͜ͱ • ݱঢ়ͷΞϓϦέʔγϣϯʹରͯ͠૊ΈࠐΈ༰қͰɺط ଘ࣮૷ʹରͯ͠෭࡞༻͕΄ͱΜͲͳ͍͜ͱ • ίϩίϩUI࢓༷͕มΘΔϏδωεཁ݅ʹରͯ͠ɺ͜Ε ·ͰͲ͓Γɺ։ൃεϐʔυΛҡ࣋Ͱ͖Δ͜ͱ • ଞͷϓϩδΣΫτ΋ར༻ՄೳͰ͋Δ͜ͱ • ͙͢ʹ࢖͑Δ͜ͱ

Slide 15

Slide 15 text

ͱ͍͏Θ͚ͰҎԼΛݕ౼

Slide 16

Slide 16 text

Vue.jsΛಋೖͨ͠ཧ༝ • ଞͷϥΠϒϥϦͱׯব͕΄ͱΜͲͳ͍ • σʔλόΠϯσΟϯάͰɺੜDOMૢ࡞ͷ࣮૷Λͦ ΜͳʹΨϦΨϦॻ͔ͣͱ΋ɺUIͷදࣔɾৼ෣͍Λָ ʹ࣮૷Ͱ͖Δ • CommonJS ϕʔεͰϞδϡʔϧԽͰ͖Δ • ֶशίετ͕௿͍

Slide 17

Slide 17 text

Vue.jsΛಋೖͨ͠ݱঢ়

Slide 18

Slide 18 text

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) { ... } } });

Slide 19

Slide 19 text

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
...
...

Slide 20

Slide 20 text

ૄ݁߹ͳ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͠ ͯɺ਌ଆͰ࡟আͯ͠΋Β͏

Slide 21

Slide 21 text

Template • View ʹ૬౰͢Δ Template(html) ΋ɺrequire Ͱ͖Δ Α͏ɺͳΔ΂͘ϑΝΠϧͱͯ͠؅ཧ # Tempalte
...
...

Slide 22

Slide 22 text

Filter • Filter΋ViewModelͷ࣌ͱಉ ༷ɺ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; }, … } });

Slide 23

Slide 23 text

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); }

Slide 24

Slide 24 text

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

vue-i18n: https://github.com/kazupon/vue-i18n

Slide 25

Slide 25 text

Ϟδϡʔϧ؅ཧํ๏ • Vue.jsͰॻ͍ͨ΋ͷར ༻͢Δ΋ͷ͸ɺapp/ assets/javascriptsͱ͸ ผʹઐ༻σΟϨΫτϦ Λ࡞ͬͯͦ͜ͷதͰ؅ ཧ . !"" Capfile !"" Gemfile !"" Gemfile.lock !"" README.md !"" Rakefile !"" app !"" config !"" config.ru !"" db !"" frontend !"" lib !"" log !"" public !"" script !"" spec #"" vendor ͜ͷσΟϨΫτϦ Ͱ؅ཧ

Slide 26

Slide 26 text

Ϟδϡʔϧߏ଄ • ಠࣗن໿Ͱߏ଄Խ • ԼهͷΑ͏ʹɺVue.jsͰॻ͍ͨ Ϟδϡʔϧ͚ͩͰͳ͘ɺଞͷ Ϟδϡʔϧ΋Ұॹʹ؅ཧ
 - ڞ௨ϥΠϒϥϦ
 - UIؔ࿈
 - APIΫϥΠΞϯτ
 - ଟݴޠϦιʔε
 . !"" Makefile !"" gulpfile.js !"" index.js !"" lib $ !"" api $ ... $ !"" utils.js $ !"" validates.js $ #"" widgets !"" locales $ !"" en.json $ #"" ja.json #"" package.json

Slide 27

Slide 27 text

ϞδϡʔϧͷϏϧυ • 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 ...

Slide 28

Slide 28 text

ϨΨγʔίʔυ΁ͷ૊ΈࠐΈ • RailsͷControllerͰϨϯμϦ ϯά͞ΕΔςϯϓϨʔτϑΝ ΠϧʹscriptλάͰɺrequire Ͱ·Δͬͱ࣮૷ͨ͠ ViewModelΛҾ͖ࠐΜͰɺ ΠϯελϯεԽ͢Δ͚ͩ • ॳظσʔλ͕ඞཁͳΒɺ JSONΛϨϯμϦϯάͯ͠ dataʹηοτ # erb template ... 


 ... (function () { var Widget = require('bundle').Widget; var data = JSON.parse('<%= j(object.to_json).html_safe %>'); new Widget({ el: '#widgets', data: data }); })();

Slide 29

Slide 29 text

Vue.jsΛಋೖͨ݁͠Ռ • ࣮૷ͨ͠ComponentΛɺ؆୯ʹ࢖ ͍·ΘΓͨ͠Γɺ֦ுͨ͠Γ͢Δ ͜ͱ͕Ͱ͖ΔΑ͏ʹͳͬͨ
 - ։ൃੜ࢈ੑ޲্
 - ϝϯςφϯεੑ޲্ Vue.jsͰ࣮૷ͨ͠ Component

Slide 30

Slide 30 text

Vue.jsΛಋೖͨ݁͠Ռ • ଞͷϓϩδΣΫτͰ΋ɺϥΠϒϥϦײ֮Ͱɺ ComponentΛҾ͖ࠐΜͰར༻Ͱ͖ΔΑ͏ͳͬͨ
 - Ϟδϡʔϧੑ޲্ Vue.jsͰ࣮૷ͨ͠ ComponentΛ֦ு

Slide 31

Slide 31 text

·ͱΊ • jQueryͷΫιίʔυ͕૿৩͢ΔΧΦεͳΫϥΠΞϯτ αΠυ • զʑͷχʔζʹ͋ͬͨVue.jsΛ࠾༻͢Δ͜ͱͰɺΫϥ ΠΞϯταΠυΛߏ଄Խ • ϨΨγʔίʔυΛ͋·Γमਖ਼͢Δ͜ͱͳ͘૊ΈࠐΊΔ ͜ͱ͕Ͱ͖ɺ͔ͭଞͷϓϩδΣΫτͰ΋ར༻Մೳ • ͜Ε·ͰͲ͓Γ։ൃεϐʔυΛҡ࣋ͭͭ͠ɺΧΦεͩͬ ͨੈքΛվળ͢Δ͜ͱ͕Ͱ͖ͨ

Slide 32

Slide 32 text

͓·͚

Slide 33

Slide 33 text

Vue.jsʹର͢Δෆຬ • UIͷঢ়ଶ஋ͱModelͷ஋͕ͬͪ͝Όʹͳ͍ͬͯΔɺ $data Λ෼཭͍ͨ͠ • αʔόαΠυͰ΋ Vue.render Έ͍ͨ΋ͷͰɺಈ͔ ͯ͠ϨϯμϦϯά͍ͨ͠

Slide 34

Slide 34 text

͝੩ௌ ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ