vuejs-meetup

38bee248082f6071230de65e9d74a944?s=47 kazupon
January 29, 2015

 vuejs-meetup

Railsで作られたサービスにVue.jsを導入したというお話

38bee248082f6071230de65e9d74a944?s=128

kazupon

January 29, 2015
Tweet

Transcript

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

  2. About Me • @kazupon • ॴଐɿCUUSOO SYSTEM • ໾ׂɿϦʔυΤϯδχΞ •

    ࢓ࣄɿ
 ϑϩϯτΤϯυɺόοΫΤϯυɺΠϯϑϥɺͳͲɺγεςϜ શൠɺ΄΅ϑϧελοΫʂ • ࡞ͬͨVue.jsͷPluginɿ
 vue-i18n: https://github.com/kazupon/vue-i18n
 vue-validator: https://github.com/kazupon/vue-validator
  3. Vue.jsΛ࢖͍ͬͯΔฐࣾαʔϏε

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

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

    ͷ Sprockets ʹ͓·͔ͤ
  6. ͔͠͠ɺ໰୊͕ɻɻɻ

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

    Μɻɻɻ
  8. 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>
  9. 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); });
  10. ͜ͷ··Ͱ͸ϠόΠʂ Ϋιίʔυ͕૿͑Δ͹͔Γʂʂ

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

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

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

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

    ଞͷϓϩδΣΫτ΋ར༻ՄೳͰ͋Δ͜ͱ • ͙͢ʹ࢖͑Δ͜ͱ
  15. ͱ͍͏Θ͚ͰҎԼΛݕ౼

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

    • ֶशίετ͕௿͍
  17. Vue.jsΛಋೖͨ͠ݱঢ়

  18. 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) { ... } } });
  19. 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>
  20. ૄ݁߹ͳ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͠ ͯɺ਌ଆͰ࡟আͯ͠΋Β͏
  21. Template • View ʹ૬౰͢Δ Template(html) ΋ɺrequire Ͱ͖Δ Α͏ɺͳΔ΂͘ϑΝΠϧͱͯ͠؅ཧ # Tempalte

    <div class=“widget”> ... <div v-component="modal" v-ref="modal"></div> ... </div>
  22. 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; }, … } });
  23. 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); }
  24. 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
  25. Ϟδϡʔϧ؅ཧํ๏ • Vue.jsͰॻ͍ͨ΋ͷར ༻͢Δ΋ͷ͸ɺapp/ assets/javascriptsͱ͸ ผʹઐ༻σΟϨΫτϦ Λ࡞ͬͯͦ͜ͷதͰ؅ ཧ . !""

    Capfile !"" Gemfile !"" Gemfile.lock !"" README.md !"" Rakefile !"" app !"" config !"" config.ru !"" db !"" frontend !"" lib !"" log !"" public !"" script !"" spec #"" vendor ͜ͷσΟϨΫτϦ Ͱ؅ཧ
  26. Ϟδϡʔϧߏ଄ • ಠࣗن໿Ͱߏ଄Խ • ԼهͷΑ͏ʹɺVue.jsͰॻ͍ͨ Ϟδϡʔϧ͚ͩͰͳ͘ɺଞͷ Ϟδϡʔϧ΋Ұॹʹ؅ཧ
 - ڞ௨ϥΠϒϥϦ
 -

    UIؔ࿈
 - APIΫϥΠΞϯτ
 - ଟݴޠϦιʔε
 . !"" Makefile !"" gulpfile.js !"" index.js !"" lib $ !"" api $ ... $ !"" utils.js $ !"" validates.js $ #"" widgets !"" locales $ !"" en.json $ #"" ja.json #"" package.json
  27. ϞδϡʔϧͷϏϧυ • 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 ...
  28. ϨΨγʔίʔυ΁ͷ૊ΈࠐΈ • 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 }); })();
  29. Vue.jsΛಋೖͨ݁͠Ռ • ࣮૷ͨ͠ComponentΛɺ؆୯ʹ࢖ ͍·ΘΓͨ͠Γɺ֦ுͨ͠Γ͢Δ ͜ͱ͕Ͱ͖ΔΑ͏ʹͳͬͨ
 - ։ൃੜ࢈ੑ޲্
 - ϝϯςφϯεੑ޲্ Vue.jsͰ࣮૷ͨ͠

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

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

    • ͜Ε·ͰͲ͓Γ։ൃεϐʔυΛҡ࣋ͭͭ͠ɺΧΦεͩͬ ͨੈքΛվળ͢Δ͜ͱ͕Ͱ͖ͨ
  32. ͓·͚

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

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