Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Enjoy The Vue

Enjoy The Vue

My Presentation at ITKonekt in Belgrade 2019 as an introduction to Vue with a few deep dives and tricks, to see what can be done with it in real projects.

Roman Kuba

March 21, 2019
Tweet

More Decks by Roman Kuba

Other Decks in Technology

Transcript

  1. Mastery Necessary 0 25 50 75 100 Progress First Results

    Use Components Use Webpack Vue Ecosystem Mastery
  2. Mastery Necessary 0 25 50 75 100 Progress First Results

    Use Components Use Webpack Vue Ecosystem Mastery
  3. <body> <div id="app"> <h1>{{ message }}!</h1> !</div> <script src="https:!//unpkg.com/vue">!</script> <script>

    new Vue({ el: '#app', data() { return { message: 'Hello World' } } }) !</script> !</body>
  4. <button data-action="greet">Say Hello!</button> <script> const actions = { greet() {

    console.log('Hello Belgrade') } } $('[data-action]').on('click', (e) !=> { e.preventDefault() const method = $(this).data('action') !// greet actions[method]() }) !</script>
  5. <ul> <li v-for="user in users">{{ user }}!</li> !</ul> <script> const

    users = ['Jane', 'Simone', 'Sarah'] new Vue({ data() { return users } }) !</script>
  6. <ul> <user v-for="user in users">{{ user }}!</user> !</ul> <script> const

    users = ['Jane', 'Simone', 'Sarah'] Vue.component('user', { template: '<li><slot !/>!</li>' }) new Vue({ data() { return users }, }) !</script>
  7. <ul> <user v-for="user in users">{{ user }}!</user> !</ul> <script> const

    users = ['Jane', 'Simone', 'Sarah'] Vue.component('user', { template: '<li><slot !/>!</li>' }) new Vue({ data() { return users }, }) !</script> Slots?
  8. <script> Vue.component('Passenger', { props: { name: String, id: String },

    mounted() { console.log(this.name, this.id) } }) !</script>
  9. <Passenger name="Bruce Wayne" v-bind:id="randomID" !/> <script> Vue.component('Passenger', { props: {

    name: String, id: String }, mounted() { console.log(this.name, this.id) } }) !</script>
  10. <Passenger name="Bruce Wayne" v-bind:id="randomID" !/> <script> Vue.component('Passenger', { props: {

    name: String, id: String }, mounted() { console.log(this.name, this.id) } }) !</script> <script> new Vue({ data() { return { randomID: uuid() } } }) !</script>
  11. <Passenger name="Bruce Wayne" v-bind:id="randomID" !/> <script> Vue.component('Passenger', { props: {

    name: String, id: String }, mounted() { console.log(this.name, this.id) } }) !</script>
  12. <Passenger name="Bruce Wayne" :id="randomID" !/> <script> Vue.component('Passenger', { props: {

    name: String, id: String }, mounted() { console.log(this.name, this.id) } }) !</script>
  13. <script> Vue.component('Modal', { props: { id: { type: [String, Number],

    default: () !=> uuid() }, action: Function } }) !</script>
  14. const state = { count: 1 } const vm =

    new Vue({ data() { return state } })
  15. const state = { count: 1 } const vm =

    new Vue({ data() { return state } }) vm.count !// 1
  16. const state = { count: 1 } const vm =

    new Vue({ data() { return state } }) vm.count !// 1 state.count!++
  17. const state = { count: 1 } const vm =

    new Vue({ data() { return state } }) vm.count !// 1 state.count!++ vm.count !// 2
  18. new Vue({ data() { return { numbers: [1, 2, 3,

    4] }; }, computed: { evens() { return this.numbers.filter(n !=> n % 2 !== 0); }, } });
  19. new Vue({ data() { return { numbers: [1, 2, 3,

    4] }; }, computed: { evens() { return this.numbers.filter(n !=> n % 2 !== 0); }, now() { return Date.now(); } } });
  20. new Vue({ data() { return { counter: 0 } },

    created() { setInterval(() !=> { this.counter!++ }, 1000) } })
  21. new Vue({ data() { return { counter: 0 } },

    created() { setInterval(() !=> { this.counter!++ }, 1000) } }) Lifecycle Method
  22. new Vue({ data() { return { counter: 0 } },

    computed: { secondsPassed() { const msg = `${this.counter} seconds have passed` console.log(msg) return msg } }, created() { setInterval(() !=> { this.counter!++ }, 1000) } })
  23. const userMixin = { data() { return { !// return

    User from an API user: Service.getCurrentUser() }; }, components: { UserStatus }, updated() { this.user.storeLatestUpdate(Date.now()); } }; new Vue({ mixins: [userMixin] });
  24. const userMixin = { data() { return { !// return

    User from an API user: Service.getCurrentUser() }; }, components: { UserStatus }, updated() { this.user.storeLatestUpdate(Date.now()); } }; Vue.mixin(userMixin);
  25. import userMixin from '@/mixins' const User = { install(Vue, options)

    { !// Global functions Vue.logout = function() {!!...} Vue.mixin(userMixin) Vue.$prototype.$logout = Vue.logout } }
  26. import userMixin from '@/mixins' const User = { install(Vue, options)

    { !// Global functions Vue.logout = function() {!!...} Vue.mixin(userMixin) Vue.$prototype.$logout = Vue.logout } } !// Install a Plugin Vue.use(User)
  27. <template> <div> <h1>{{ message }}!</h1> !</div> !</template> <script> export default

    { data() { return { message: "Hello Belgrade” }; } }; !</script>
  28. <template> <div> <h1>{{ message }}!</h1> !</div> !</template> <script> export default

    { data() { return { message: "Hello Belgrade” }; } }; !</script> <style scoped> h1 { color: #bada55; } !</style>
  29. <template> <div> <List :data="collection" !/> !</div> !</template> <script> import List

    from "@/components"; export default { components: { List }, computed: { collection() { return Service.getImportantData(); } } }; !</script>
  30. <body> <div id="app"> <h1>{{ message }}!</h1> !</div> <script src="https:!//unpkg.com/vue">!</script> <script>

    new Vue({ el: '#app', data() { return { message: 'Hello World' } } }) !</script> !</body>
  31. <body> <header> !!!<!-- Navigation Header from Backend !!--> !</header> <div

    id="app"> !!!<!-- Content From Server !!--> <UserList :users="!#{@users.to_json}"> !!!<!-- Vue Land !!--> !</UserList> !</div> <script src="foo/app-1234.min.js">!</script> !</body>
  32. <body> <header> !!!<!-- Navigation Header from Backend !!--> !</header> <div

    id="app"> !!!<!-- Content From Server !!--> <UserList :users="!#{@users.to_json}"> !!!<!-- Vue Land !!--> !</UserList> !</div> <script src="foo/app-1234.min.js">!</script> !</body>
  33. <body> <header> !!!<!-- Navigation Header from Backend !!--> !</header> <div

    id="app"> !!!<!-- Content From Server !!--> <UserList :users="!#{@users.to_json}"> !!!<!-- Vue Land !!--> !</UserList> !</div> <script src="foo/app-1234.min.js">!</script> !</body>
  34. <div> <header> <h1>I'm a template!!</h1> !</header> <p v-if="message">{{ message }}!</p>

    <p v-else>No message.!</p> !</div> render(h) { const message = this.message return h('div', [ h('header', [ h('h1', "I'm a template!") ]), message ? h('p', message) : h('p', 'No message.') ]) }
  35. <div> <header> <h1>I'm a template!!</h1> !</header> <p v-if="message">{{ message }}!</p>

    <p v-else>No message.!</p> !</div> function anonymous() { with (this) { return _c('div', [_m(0), (message) ? _c('p', [_v(_s(message))]) : _c('p', [_v("No message.")])]) } } _m(0): function anonymous() { with (this) { return _c('header', [_c('h1', [_v("I'm a template!")])]) } }
  36. <heading>My h1 Title!</heading> <heading level="2">My h2 Title!</heading> Vue.component('heading', { props:

    { level: { type: Number, default: 1 } }, render(h) { const tag = `h${this.level}` return h(tag, this.$slots.default) } })
  37. <heading>My h1 Title!</heading> <heading level="2">My h2 Title!</heading> Vue.component('heading', { props:

    { level: { type: Number, default: 1 } }, render(h) { const tag = `h${this.level}` return h(tag, this.$slots.default) } })
  38. <template> <div class="modal"> <header> <slot name="header">!</slot> !</header> <slot>!</slot> <footer> <slot

    name="footer">!</slot> !</footer> !</div> !</template> <Modal> <template v-slot:header> <h1>Signup Form!</h1> !</template> <p>This is the modal content!!</p> <template v-slot:footer> <button>Sign me up!</button> !</template> !</Modal>
  39. <script> export default { name: "Randomizer", data() { return {

    number: Date.now() }; }, render() { return this.$scopedSlots.default({ number: this.number }); } }; !</script>
  40. <script> export default { name: "Randomizer", data() { return {

    number: Date.now() }; }, render() { return this.$scopedSlots.default({ number: this.number }); } }; !</script> <Randomizer v-slot:default="{ number }"> <span>{{ number }}!</span> !</Randomizer>
  41. <script> export default { name: "Randomizer", data() { return {

    number: Date.now() }; }, render() { return this.$scopedSlots.default({ number: this.number }); } }; !</script> <Randomizer #default=“{ number }"> <span>{{ number }}!</span> !</Randomizer>
  42. <script> import axios from 'axios' const CODESHIP_STATUSPAGE_URL = ‘…’ export

    default { data () { return { status: 'loading', description: '' } }, render () { return this.$scopedSlots.default({ description: this.description, statusClass: this.statusClass }) }, computed: { statusClass () { return `header-item-status-${this.status}` } }, methods: { success (response) { this.status = response.data.status.indicator this.description = response.data.status.description } }, created () { axios.get(CODESHIP_STATUSPAGE_URL).then(this.success) } }
  43. Page-Status li.header-item.header-item-primary[slot-scope="{ description, statusClass }" :class="statusClass"] a.header-link.header-link-support[href="#" data-dropdown-trigger] span Support

    span.header-arrow-btn.hidden[class="md:block"] !== icon :arrow_down, prefix: :header ul.header-item-dropdown-list / Navigation links !!... !== header_dropdown_item status_url, target: '_blank', class: 'header-item-dropdown-link-status' span.header-item-dropdown-link-title Codeship Status span.header-item-dropdown-link-description {{ description }}
  44. =

  45. <script> const csslink = "https:!//cdnjs.cloudflare.com/ajax/libs/simplebar/3.1.5/simplebar.min.css"; const jslink = "https:!//cdnjs.cloudflare.com/ajax/libs/simplebar/3.1.5/simplebar.min.js"; export

    default { mounted() { let link = document.createElement("link"); link.href = csslink; link.type = "text/css"; link.rel = "stylesheet"; document.head.appendChild(link); let simplebarScript = document.createElement("script"); simplebarScript.async = true; simplebarScript.setAttribute("src", jslink); document.head.appendChild(simplebarScript); const waitForSimplebar = () !=> { if (window["SimpleBar"]) { this.setup(); } else { setTimeout(() !=> waitForSimplebar(), 100); } }; waitForSimplebar(); } }; !</script>
  46. <script> const csslink = "https:!//cdnjs.cloudflare.com/ajax/libs/simplebar/3.1.5/simplebar.min.css"; const jslink = "https:!//cdnjs.cloudflare.com/ajax/libs/simplebar/3.1.5/simplebar.min.js"; export

    default { mounted() { let link = document.createElement("link"); link.href = csslink; link.type = "text/css"; link.rel = "stylesheet"; document.head.appendChild(link); let simplebarScript = document.createElement("script"); simplebarScript.async = true; simplebarScript.setAttribute("src", jslink); document.head.appendChild(simplebarScript); const waitForSimplebar = () !=> { if (window["SimpleBar"]) { this.setup(); } else { setTimeout(() !=> waitForSimplebar(), 100); } }; waitForSimplebar(); } }; !</script>
  47. <script> const csslink = "https:!//cdnjs.cloudflare.com/ajax/libs/simplebar/3.1.5/simplebar.min.css"; const jslink = "https:!//cdnjs.cloudflare.com/ajax/libs/simplebar/3.1.5/simplebar.min.js"; export

    default { mounted() { let link = document.createElement("link"); link.href = csslink; link.type = "text/css"; link.rel = "stylesheet"; document.head.appendChild(link); let simplebarScript = document.createElement("script"); simplebarScript.async = true; simplebarScript.setAttribute("src", jslink); document.head.appendChild(simplebarScript); const waitForSimplebar = () !=> { if (window["SimpleBar"]) { this.setup(); } else { setTimeout(() !=> waitForSimplebar(), 100); } }; waitForSimplebar(); } }; !</script>
  48. <script> const csslink = "https:!//cdnjs.cloudflare.com/ajax/libs/simplebar/3.1.5/simplebar.min.css"; const jslink = "https:!//cdnjs.cloudflare.com/ajax/libs/simplebar/3.1.5/simplebar.min.js"; export

    default { mounted() { let link = document.createElement("link"); link.href = csslink; link.type = "text/css"; link.rel = "stylesheet"; document.head.appendChild(link); let simplebarScript = document.createElement("script"); simplebarScript.async = true; simplebarScript.setAttribute("src", jslink); document.head.appendChild(simplebarScript); const waitForSimplebar = () !=> { if (window["SimpleBar"]) { this.setup(); } else { setTimeout(() !=> waitForSimplebar(), 100); } }; waitForSimplebar(); } }; !</script>
  49. <script> const csslink = "https:!//cdnjs.cloudflare.com/ajax/libs/simplebar/3.1.5/simplebar.min.css"; const jslink = "https:!//cdnjs.cloudflare.com/ajax/libs/simplebar/3.1.5/simplebar.min.js"; export

    default { data() { return { instance: undefined, config: { autohide: false } }; }, methods: { setup() { this.instance = new window.SimpleBar(this.$refs.wrapper, this.config); } }, mounted() { … } }; !</script>
  50. import Vue from "vue"; import Vuex from "vuex"; Vue.use(Vuex); export

    default Vuex.Store({ state: { count: 1 }, mutations: { add(state) { state.count!++; } }, actions: { add({ commit }) { commit("add"); } }, getters: { counter: s !=> s.count } });
  51. import Vue from "vue"; import Vuex from "vuex"; Vue.use(Vuex); export

    default Vuex.Store({ state: { count: 1 }, mutations: { add(state) { state.count!++; } }, actions: { add({ commit }) { commit("add"); } }, getters: { counter: s !=> s.count } }); import store from "./store"; import { mapGetters, mapActions } from "vuex"; new Vue({ store, computed: { !!...mapGetters(["counter"]) }, methods: { !!...mapActions(["add"]) } });
  52. !!!<!-- REACT !!--> <div> <h1>Hello!!</h1> {unreadMessages.length > 0 !&& <h2>

    You have {unreadMessages.length} unread messages. !</h2> } !</div> !!!<!-- Vue !!--> <div> <h1>Hello!!</h1> <h2 v-if="unreadMessages.length > 0"> You have {{ unreadMessages.length }} unread messages. !</h2> !</div>