├── LICENSE ├── README.md └── convert.vue /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Matej 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-cheat-sheet 2 | My cheat sheet for vue.js most basic stuff. The goal wasn't to make another [Vue documentation](https://vuejs.org/v2/guide/), because the official one is already badass. 3 | Big thank you to [boussadjra](https://github.com/boussadjra/) for making this cheat sheet available as a [website](https://boussadjra.github.io/vue-cheat-sheet/) 4 | 5 | Contributions and PRs are very welcome. 6 | 7 | _"You must type each of these exercises in, manually. If you copy and paste, you might as well not even do them. The point of these exercises is to train your hands, your brain, and your mind in how to read, write, and see code. If you copy-paste, you are cheating yourself out of the effectiveness of the lessons."_ - Zed A. 8 | 9 | Sources: 10 | * [iamshaunjp](https://github.com/iamshaunjp/vuejs-playlist) 11 | * [Vue.js official guide](https://vuejs.org/v2/guide/) 12 | 13 | Useful Chrome extensions: 14 | * [Vue Devtools](https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd?hl=en) 15 | * [JSON Formatter](https://chrome.google.com/webstore/detail/json-formatter/bcjindcccaagfpapjjmafapmmgkkhgoa?hl=en) 16 | 17 | Stuff that might get handy in almost every Vue.js project: 18 | * [Auth restrictions](http://www.eddyella.com/2017/04/24/vue-2-spa-restricting-components-for-logged-in-users-only/) 19 | * [Vue reactivity](https://vuejs.org/v2/guide/reactivity.html) 20 | * [Improve Vuex performance](https://medium.com/@jiihu/how-to-improve-performance-of-vuex-store-c9e3cfb01f72) 21 | 22 | --- 23 | ## Basic HTML and JS 24 | ```html 25 | 26 | 27 | 28 | VueJS example 29 | 30 | 31 | 32 | 33 | 34 |
35 |

{{ hello() }}

36 |

{{ name }}

37 |

{{ age + 1 }}

38 |

{{ age < 18 ? "Youngster" : "Adult"}}

39 |
40 | 41 | 42 | 43 | 44 | ``` 45 | ```javascript 46 | new Vue({ 47 | el: '#vue-app', // contoled element 48 | 49 | data: { 50 | name: "Matej", 51 | age: 27, 52 | sleepy: true 53 | }, 54 | 55 | methods: { 56 | hello: function () { 57 | return "Hello"; 58 | }, 59 | computed:{} 60 | } 61 | }); 62 | ``` 63 | ![](https://cdn-images-1.medium.com/max/2000/1*C4A0g1KYpa_olbSJcxAEBA.png) 64 | 65 | ## HTML directives 66 | ##### Show / hide div 67 | ##### Hides the element (display none), doesn't delete it 68 | where _available_ is a boolean variable in the js 69 | ```html 70 |
Stuff
71 | ``` 72 | ##### Toggle show / hide div 73 | where _available_ is a boolean variable in the js 74 | ```html 75 |
Stuff
76 | ``` 77 | 78 | ##### Render div 79 | ##### Deletes the element, doesn't hide it 80 | where _available_ is a boolean variable in the js 81 | ```html 82 |
Stuff
83 |
Smth else
84 | ``` 85 | 86 | ##### Looping 87 | ##### array of strings 88 | Remember to check if the element exists with v-if before looping over it 89 | ```html 90 | 93 | ``` 94 | ##### array of objects 95 | ```html 96 | 99 | ``` 100 | 101 | ##### nested arrays 102 | ```html 103 | 104 | 105 | 106 | 107 | 108 | 109 | 116 |
AmountAssetCreated
117 | ``` 118 | 119 | ##### variables in v-for 120 | ```html 121 |
  • 122 |
    123 | {{ item.name }}
    124 | {{ item.homepage }} 125 |
  • 126 | ``` 127 | 128 | ##### Set text for element from a variable _name_ 129 | ```html 130 | 131 | ``` 132 | ##### Set html for element from a variable _name_ 133 | ```html 134 | 135 | ``` 136 | 137 | ## Two way data binding 138 | ```html 139 | 140 |

    My name is: {{name}}

    141 | ``` 142 | ```javascript 143 | ... 144 | data:{ 145 | name: "" 146 | } 147 | ... 148 | ``` 149 | 150 | ## Computed properties 151 | > Computed properties are cached, and only re-computed on reactive dependency changes. Note that if a certain dependency is out of the instance’s scope (i.e. not reactive), the computed property will not be updated. In other words, imagine a computed property as a method (but it's not really a method) in the ```data()``` that always returns a value. That "method" will be called whenever a property (variable from ```data()```) used in that method is changed. 152 | 153 | ```html 154 | 155 | 156 | 157 | VueJS example 158 | 159 | 160 | 161 | 162 |
    163 | 164 | 165 | 166 |

    Counter 1: {{ a }}

    167 |

    Counter 2: {{ b }}

    168 | 169 | 170 |

    Result: {{ result() }} | {{ output }}

    171 | 172 |
    173 | 174 | 175 | 176 | 177 | ``` 178 | 179 | ```javascript 180 | new Vue({ 181 | el: '#vue-app', 182 | data: { 183 | a: 0, 184 | b: 0 185 | }, 186 | methods: { 187 | result: function () { 188 | // this function is not interested in the "b" variable, yet it runs every time when the result needs to be changed 189 | console.log("methods"); 190 | return this.a < 0 ? "Negative" : "Positive"; 191 | } 192 | }, 193 | computed: { 194 | // these methods are invoked like attributes, without () 195 | // this method runs only when the "a" variable is changed 196 | output: function () { 197 | console.log("computed"); 198 | return this.a < 0 ? "Negative" : "Positive"; 199 | } 200 | } 201 | }); 202 | ``` 203 | ##### Computed property methods can also have getters and setters 204 | ```javascript 205 | var vm = new Vue({ 206 | data: { a: 1 }, 207 | computed: { 208 | // get only 209 | aDouble: function () { 210 | return this.a * 2 211 | }, 212 | // both get and set 213 | aPlus: { 214 | get: function () { 215 | return this.a + 1 216 | }, 217 | set: function (v) { 218 | this.a = v - 1 219 | } 220 | } 221 | } 222 | }) 223 | vm.aPlus // => 2 224 | vm.aPlus = 3 225 | vm.a // => 2 226 | vm.aDouble // => 4 227 | ``` 228 | 229 | ## HTML properties and classes 230 | ```html 231 |

    ...

    232 | ``` 233 | this div will have the _red_ class if the _userFound_ variable is set to _true_ 234 | ```html 235 |
    ...
    236 | ``` 237 | this div will have the _red_ class if the _isAdmin_ variable is set to _true_ 238 | ```html 239 |
    ...
    240 | ``` 241 | 242 | ## Events 243 | ##### Call _method_ on click event 244 | where _method_ is a custom method in the js 245 | ```html 246 | 247 | ``` 248 | ##### or shorthand 249 | where _method_ is a custom method in the js 250 | ```html 251 | 252 | ``` 253 | _method_ is called when ALT+ENTER is pressed 254 | ```html 255 | 256 | ``` 257 | ##### Conditional event binding (as of Vue 2.6) 258 | The method ```sendModey``` will be called only if the condition ``` amount > 0 ``` has been met. 259 | ```vue 260 | 261 | ``` 262 | 263 | ## Custom events 264 | ```javascript 265 | // fire custom event 266 | this.$emit("eventName", data); 267 | ``` 268 | ```html 269 | 273 |

    274 | ``` 275 | 276 | ## Event bus 277 | ##### communicate between child components without the parent component 278 | ##### consider using Vuex instead 279 | ```javascript 280 | // main.js 281 | // create new event bus 282 | export const bus = new Vue(); 283 | ``` 284 | ```html 285 | // Header.vue 286 | import {bus} from "../main"; 287 | ``` 288 | ```html 289 | // Footer.vue 290 | import {bus} from "../main"; 291 | ``` 292 | ```javascript 293 | // listen to bus event in first component 294 | // usually in .created() function 295 | bus.$on("eventName", (data) => { 296 | // callback 297 | // use data 298 | }) 299 | 300 | // fire bus event in second component 301 | bus.$emit("eventName", data); 302 | ``` 303 | 304 | ## Components 305 | ##### reusable inside the html 306 | ```html 307 |
    308 | 309 | 310 | 311 |
    312 | ``` 313 | ```javascript 314 | // global registration 315 | Vue.component('signature', { 316 | template: '

    Regards. Matej.

    ' 317 | }); 318 | ``` 319 | 320 | ## .vue components and props 321 | ##### Props - passing data from parent component to child component 322 | ```vue 323 | 324 | 333 | 334 | 365 | ``` 366 | ```vue 367 | 368 | 379 | 380 | 395 | ``` 396 | ```vue 397 | 398 | 404 | 405 | 418 | ``` 419 | ```vue 420 | 421 | 427 | 428 | 442 | ``` 443 | 444 | ## Validate props 445 | ```vue 446 | export default { 447 | props:{ 448 | ninjas:{ 449 | type: Array, 450 | required: true 451 | } 452 | } 453 | } 454 | ``` 455 | 456 | ## Filters 457 | ##### Change the output data to the browser. They do not change the data directly. 458 | ```html 459 |

    {{title | to-uppercase}}

    460 | ``` 461 | ```javascript 462 | // main.js 463 | Vue.filter("to-uppercase", function ( value ) { 464 | return value.toUpperCase(); 465 | }); 466 | ``` 467 | 468 | ## Mixins 469 | ##### Reuse some piece if code (or function) so that it doesn't need to be written in more separate files. 470 | 471 | 472 | ## References 473 | ##### An object of DOM elements and component instances 474 | ```html 475 | 476 | ``` 477 | ```javascript 478 | var name = this.$refs.name; 479 | 480 | ``` 481 | 482 | ## Dynamic components 483 | dynamically change component based on variable _component_ value 484 | rememberto use _keep-alive_ tag to remember data from the destroyed component 485 | ```vue 486 | 493 | 494 | import formOne from "./components/formOne.vue"; 495 | import formTwo from "./components/formTwo.vue"; 496 | 497 | ... 498 | data: function() { 499 | return { 500 | component: "form-two" 501 | } 502 | } 503 | ``` 504 | 505 | ## Vue CLI 506 | ##### make new project 507 | ``` 508 | $ vue init webpack-simple my-project 509 | $ cd project-name 510 | ``` 511 | ##### install dependencies and start local server 512 | ``` 513 | $ npm install 514 | $ npm run dev 515 | ``` 516 | ##### build app for production 517 | this will make a dist folder with minified js 518 | ``` 519 | $ npm run build 520 | ``` 521 | 522 | ## Vue lifecycle 523 | * new Vue(); 524 | * .beforeCreate(); 525 | * .created(); 526 | * .beforeMount(); 527 | * .updated(); 528 | * .beforeUpdate(); 529 | * .beforeDestroy(); 530 | * .destroyed(); 531 | ![](https://vuejs.org/images/lifecycle.png) 532 | 533 | ## Checkboxes 534 | ##### with v-model, the _categories_ array will be appended with the values 535 | ```html 536 |
    537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 |
    546 | ``` 547 | ```javascript 548 | data: function () { 549 | categories: [] 550 | } 551 | ``` 552 | 553 | ## Select box binding 554 | ##### hardcoded and looped select 555 | ```html 556 |
    557 | 562 | 563 | 566 |
    567 | ``` 568 | ```javascript 569 | data: function () { 570 | town: "", 571 | towns: ["Zagreb", "Osijek", "Varazdin", "Split", "Rijeka", "Dubrovnik"] 572 | } 573 | ``` 574 | ## POST requests with vue-resource 575 | __Important: if sending nested objects, be sure to JSON.stringify first!__ 576 | ##### Register it in main.js 577 | ```javascript 578 | import VueResource from 'vue-resource' 579 | 580 | Vue.use(VueResource); 581 | ``` 582 | ##### Usage in custom function 583 | ```javascript 584 | post: function () { 585 | this.$http.post("http://localhost:3000/users", { 586 | title: this.blog.title, 587 | body: this.blog.body, 588 | userId: 1 589 | }).then( res => { 590 | // promise 591 | console.log("Response: ", res); 592 | }, error => { 593 | console.log("Error: ", error); 594 | }); 595 | } 596 | ``` 597 | 598 | ## GET requests 599 | ##### Usage in custom function 600 | ```javascript 601 | post: function () { 602 | this.$http.get("http://localhost:3000/users").then( function ( res ){ 603 | // promise 604 | console.log("Response: ", res) 605 | }); 606 | } 607 | ``` 608 | 609 | ## Routes with vue-router 610 | ```javascript 611 | // router.js 612 | import login from "./components/login.vue"; 613 | import registration from "./components/Registration.vue"; 614 | import user from "./components/user.vue"; 615 | ``` 616 | ```javascript 617 | // main.js 618 | import VueRouter from 'vue-router'; 619 | import { routes } from "./routes"; 620 | Vue.use(VueRouter); 621 | 622 | const router = new VueRouter({ 623 | routes 624 | }); 625 | 626 | new Vue({ 627 | el: '#app', 628 | router: router, 629 | render: h => h(App) 630 | }) 631 | ``` 632 | ```javascript 633 | // routes.js 634 | import Login from "./components/Login.vue"; 635 | import Registration from "./components/Registration.vue"; 636 | import User from "./components/User.vue"; 637 | 638 | export const routes = [ 639 | { path: "", component: Login }, 640 | { path: "/registration", component: Registration }, 641 | { path: "/users/", component: Users, children: [ 642 | { path: "", component: UserStart }, 643 | { path: ":id", component: UserDetail }, 644 | { path: ":id/edit", component: UserEdit } 645 | ] }, 646 | {path: "*", redirect: "/"} // handle all uncovered routes 647 | 648 | ] 649 | ``` 650 | ##### mark the place with router-view where the component of the currently active route will be loaded 651 | ```html 652 | 655 | ``` 656 | ##### handling route parameters 657 | ```vue 658 | 659 | 665 | 683 | ``` 684 | ##### navigating around 685 | ```html 686 | 690 | ``` 691 | ##### dynamically route over user details 692 | ```vue 693 | {{ user.username }} 694 | ``` 695 | ##### navigate home 696 | ```javascript 697 | this.$router.push({ path: "/home"}); 698 | ``` 699 | 700 | ##### watch for route changes 701 | ```javascript 702 | watch: { 703 | "$route": function (to, form){ 704 | this.id = to.params.id 705 | } 706 | } 707 | ``` 708 | 709 | ##### watch if object is changed 710 | ```javascript 711 | watch: { 712 | picked: { 713 | handler(val, oldVal) { 714 | console.log('changed: ', oldVal); 715 | console.log('new: ', val); 716 | }, 717 | deep: true, 718 | immediate: true 719 | } 720 | } 721 | ``` 722 | ## auth restrictions 723 | To not let someone access e.g. /dashboard if the user is not logged in. 724 | ```javascript 725 | // add requiresAuth to certain components 726 | export const routes = [ 727 | { path: "", component: Login }, 728 | { path: "/dashboard", component: Dashboard, meta: {requiresAuth: true} } 729 | ]; 730 | ``` 731 | 732 | ```javascript 733 | // configure vue-router 734 | // important: do not turn on history mode 735 | const router = new VueRouter({ 736 | routes, 737 | // mode: "history" 738 | }) 739 | 740 | router.beforeEach((to, from, next) => { 741 | if (to.matched.some(record => record.meta.requiresAuth)) { 742 | if ( CHECK_FOR_USER_IN_LOCALSTORAGE_ETC ) { 743 | // handle restricted access 744 | next({ 745 | path: '/login', 746 | }); 747 | } else { 748 | next(); 749 | } 750 | } else { 751 | // do nothing with components without meta: {requiresAuth: true} 752 | next(); 753 | } 754 | }) 755 | ``` 756 | 757 | ## table search + sort 758 | #### multiple column search 759 | ```html 760 | 761 | 762 | 763 | 764 | ``` 765 | ```javascript 766 | // users array and search query variable 767 | data: function () { 768 | return { 769 | searchQuery: "", 770 | users: [] 771 | }; 772 | }, 773 | 774 | ... 775 | // computed method for filtering users by 776 | // email, last name and first name 777 | computed: { 778 | filterUsers () { 779 | return this.users.filter(user => { 780 | return (user.email.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1 || 781 | user.lastName.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1 || 782 | user.firstName.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1) 783 | }) 784 | } 785 | } 786 | ``` 787 | 788 | #### sort columns asc and desc 789 | ```javascript 790 | // add needed variables 791 | data: function () { 792 | return { 793 | ascending: false, 794 | sortColumn: '', 795 | users: [], 796 | }; 797 | }, 798 | methods: { 799 | // sort method 800 | "sortTable": function sortTable ( col ) { 801 | if ( this.sortColumn === col ) { 802 | this.ascending = !this.ascending; 803 | } else { 804 | this.ascending = true; 805 | this.sortColumn = col; 806 | } 807 | 808 | let ascending = this.ascending; 809 | 810 | this.users.sort(function ( a, b ) { 811 | if ( a[col] >= b[col] ) { 812 | return ascending ? 1 : -1 813 | } else if ( a[col] < b[col] ) { 814 | return ascending ? -1 : 1 815 | } 816 | return 0; 817 | }) 818 | } 819 | } 820 | ``` 821 | ```html 822 | 823 | 824 | Username 825 | First Name 826 | Last Name 827 | Address 828 | Phone number 829 | 830 | ``` 831 | ## Search + filters + sort 832 | ```javascript 833 | searchVideos() { 834 | let filtered = this.videos; 835 | // search by keyword 836 | if (this.filters.searchQuery) { 837 | filtered = this.videos.filter( 838 | v => v.title.toLowerCase().indexOf(this.filters.searchQuery) > -1 839 | ); 840 | } 841 | // filter by date range 842 | if (this.filters.startDate && this.filters.endDate) { 843 | filtered = filtered.filter(v => { 844 | var time = new Date(v.created_at).getTime(); 845 | return (new Date(this.filters.startDate).getTime() < time && time < new Date(this.filters.endDate).getTime()); 846 | }); 847 | } 848 | // filter by property value 849 | if (this.filters.filterVal) { 850 | if (this.filters.filterVal === 'female') { 851 | filtered = filtered.filter( 852 | v => v.gender === this.filters.filterVal 853 | ); 854 | } 855 | // sort by property 856 | if (this.filters.sortValue === 'most_popular') { 857 | filtered.sort(function(a, b) { return a.views - b.views; }); 858 | } 859 | } 860 | return filtered; 861 | } 862 | ``` 863 | ## async await 864 | An ```async``` function returns a promise. When you want to call this function you prepend ```await```, and the calling code will stop until the promise is resolved or rejected. 865 | ```javascript 866 | // example 867 | const doSomethingAsync = () => { 868 | return new Promise((resolve) => { 869 | setTimeout(() => resolve('I did something'), 3000) 870 | }) 871 | } 872 | 873 | const doSomething = async () => { 874 | console.log(await doSomethingAsync()) 875 | console.log('I did something again!') 876 | } 877 | 878 | doSomething() 879 | // result: 880 | // I did something! 881 | // I did something again! 882 | ``` 883 | 884 | ## async await with fetch in vuex 885 | ```javascript 886 | // example 887 | import Vue from 'vue' 888 | import Vuex from 'vuex' 889 | 890 | Vue.use(Vuex) 891 | 892 | export default new Vuex.Store({ 893 | state: { 894 | data: null 895 | }, 896 | mutations: { 897 | setData: (state, payload) => { 898 | state.resource = payload 899 | } 900 | }, 901 | actions: { 902 | async getData({ commit }) { 903 | let res = null 904 | try { 905 | res = await fetch( 906 | 'https://api.coindesk.com/v1/bpi/currentprice.json' 907 | ) 908 | } catch (err) { 909 | console.log('err: ', err) 910 | return 911 | } 912 | 913 | // Handle success 914 | console.log('waiting for data...'); 915 | const data = await res.json() 916 | console.log('data: ', data) 917 | commit('setData', data) 918 | } 919 | } 920 | }) 921 | 922 | ``` 923 | ## import config file 924 | ```javascript 925 | // config.js 926 | // example config file 927 | var apiPort = 5566; 928 | var currHost = window.location.protocol + '//' + window.location.hostname + ':' + apiPort + '/api/v1'; 929 | var url = window.location.host !== 'localhost:8080' ? 'http://PROD-URL/' : currHost; 930 | 931 | export var cfg = { 932 | version: "0.1.0", 933 | api: { 934 | endpoint: url 935 | } 936 | }; 937 | ``` 938 | ```javascript 939 | // main.js 940 | import * as config from './config' 941 | window._cfg = config.cfg 942 | ``` 943 | ## Focus on a field 944 | ```javascript 945 | mounted() { 946 | this.$refs.myInput.focus(); 947 | } 948 | ``` 949 | 950 | 951 | ## Stuff that might get handy 952 | * _v-once_ - render the element and component only once 953 | * _v-if_ - conditionally render the element 954 | * [Difference between computed and methods](https://github.com/dekadentno/vue-cheat-sheet/blob/master/computed-properties.md) 955 | * watch - specify what property to listen for changes and then execute some code without returning values 956 | * v-model modifiers 957 | * .lazy - fire event when user lefts the field 958 | * .number - force the value to be converted to a integer 959 | * .trim - delete whitespace 960 | -------------------------------------------------------------------------------- /convert.vue: -------------------------------------------------------------------------------- 1 | console.log("ha!"); 2 | --------------------------------------------------------------------------------