├── .editorconfig ├── .github └── workflows │ └── deploy.yml ├── .gitignore ├── .vscode ├── extensions.json └── settings.json ├── content ├── .vitepress │ ├── config.mts │ └── theme │ │ ├── components │ │ ├── ActionButtons.vue │ │ ├── DocFooter.vue │ │ ├── Footer.vue │ │ ├── GithubCounterBtn.vue │ │ ├── SocialLinks.vue │ │ ├── SubscribeAlert.vue │ │ ├── SubscribeForm.vue │ │ └── VueThemesCallOut.vue │ │ ├── custom.scss │ │ ├── index.ts │ │ └── tailwind.css ├── changelog.md ├── contributing.md ├── index.md ├── pinia │ └── basic.md ├── public │ ├── brand-logo-small-dark.png │ ├── brand-logo-small-light.png │ ├── google6f658ffc1e5996cb.html │ ├── hero-image.png │ ├── hero.png │ ├── logos │ │ ├── android-icon-192x192.png │ │ ├── apple-icon-114x114.png │ │ ├── apple-icon-120x120.png │ │ ├── apple-icon-144x144.png │ │ ├── apple-icon-152x152.png │ │ ├── apple-icon-180x180.png │ │ ├── apple-icon-57x57.png │ │ ├── apple-icon-60x60.png │ │ ├── apple-icon-72x72.png │ │ ├── apple-icon-76x76.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon-96x96.png │ │ ├── favicon.ico │ │ └── manifest.json │ ├── pinia-logo.png │ ├── robots.txt │ ├── vue-cheatsheet-logo.png │ ├── vue-logo.png │ └── vue-router-logo.png ├── vue-router │ ├── advanced.md │ └── basic.md └── vue │ ├── basic.md │ ├── built-in-components.md │ ├── component.md │ ├── composable.md │ ├── forms.md │ └── reactivity.md ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── readme.md ├── shims.d.ts ├── tailwind.config.js └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # Matches multiple files with brace expansion notation 12 | # Set default charset 13 | [*.{js,py}] 14 | charset = utf-8 15 | 16 | # 4 space indentation 17 | [*.py] 18 | indent_style = space 19 | indent_size = 4 20 | 21 | # Tab indentation (no size specified) 22 | [Makefile] 23 | indent_style = tab 24 | 25 | # Indentation override for all JS under lib directory 26 | [lib/**.js] 27 | indent_style = space 28 | indent_size = 2 29 | 30 | # Matches the exact files either package.json or .travis.yml 31 | [{package.json,.travis.yml}] 32 | indent_style = space 33 | indent_size = 2 -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy - Documentation 2 | run-name: 🚀 Deploy 3 | 4 | on: 5 | workflow_dispatch: 6 | push: 7 | branches: 8 | - main 9 | 10 | jobs: 11 | deployment: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: ⚙️ Setup pnpm 15 | uses: pnpm/action-setup@v2 16 | with: 17 | version: 8 18 | 19 | - name: ⬇️ Checkout repo 20 | uses: actions/checkout@v3 21 | 22 | - name: 📦 Build 23 | run: | 24 | pnpm i 25 | pnpm build 26 | mv content/.vitepress/dist content/.vitepress/html 27 | 28 | - name: 🚀 Upload 29 | uses: appleboy/scp-action@master 30 | with: 31 | HOST: ${{ secrets.HOST }} 32 | USERNAME: ${{ secrets.USERNAME }} 33 | PORT: ${{ secrets.PORT }} 34 | KEY: ${{ secrets.SSHKEY }} 35 | source: content/.vitepress/html 36 | target: ${{ secrets.TARGET_DIR }} 37 | strip_components: 3 38 | rm: true 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* 131 | 132 | # 👉 Custom 133 | 134 | **/.vitepress/cache -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "davidanson.vscode-markdownlint", 4 | "editorconfig.editorconfig", 5 | "streetsidesoftware.code-spell-checker", 6 | "xabikos.javascriptsnippets", 7 | "dbaeumer.vscode-eslint", 8 | "matijao.vue-nuxt-snippets", 9 | "vue.volar" 10 | ] 11 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // JSON 3 | "[json]": { 4 | "editor.defaultFormatter": "vscode.json-language-features" 5 | }, 6 | "[jsonc]": { 7 | "editor.defaultFormatter": "vscode.json-language-features" 8 | }, 9 | // Markdown 10 | "[markdown]": { 11 | "editor.defaultFormatter": "DavidAnson.vscode-markdownlint", 12 | "markdown.validate.enabled": true, 13 | "markdown.occurrencesHighlight.enabled": true, 14 | }, 15 | "markdown.styles": [ 16 | "https://cdn.jsdelivr.net/gh/sindresorhus/github-markdown-css/github-markdown-dark.css", 17 | "https://cdn.jsdelivr.net/gh/elegantech/github-markdown-css@transparent/github-markdown-with-transparent-background.min.css" 18 | ], 19 | "markdown.editor.pasteUrlAsFormattedLink.enabled": "smart", 20 | "emmet.includeLanguages": { 21 | "markdown": "html", 22 | }, 23 | "commentAnchors.tagHighlights.enabled": false, 24 | } -------------------------------------------------------------------------------- /content/.vitepress/config.mts: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url' 2 | import { defineConfig } from 'vitepress' 3 | 4 | const isDev = process.env.NODE_ENV !== 'production' 5 | 6 | const gtmConfig = { 7 | headScript: ` 8 | 13 | `, 14 | bodyNoScript: ` 15 | 17 | `, 18 | } 19 | 20 | // https://vitepress.dev/reference/site-config 21 | export default defineConfig({ 22 | lang: 'en-US', 23 | title: 'Vue Cheatsheet By ThemeSelection', 24 | lastUpdated: true, 25 | description: "The one and only Vue cheatsheet you need for VueJS by ThemeSelection", 26 | head: [ 27 | ['link', { rel: 'icon', href: '/logos/favicon.ico' }], 28 | ['link', { rel: 'apple-touch-icon', href: '/logos/apple-icon-57x57.png' }], 29 | ['link', { rel: 'apple-touch-icon', href: '/logos/apple-icon-60x60.png' }], 30 | ['link', { rel: 'apple-touch-icon', href: '/logos/apple-icon-72x72.png' }], 31 | ['link', { rel: 'apple-touch-icon', href: '/logos/apple-icon-76x76.png' }], 32 | ['link', { rel: 'apple-touch-icon', href: '/logos/apple-icon-114x114.png' }], 33 | ['link', { rel: 'apple-touch-icon', href: '/logos/apple-icon-120x120.png' }], 34 | ['link', { rel: 'apple-touch-icon', href: '/logos/apple-icon-144x144.png' }], 35 | ['link', { rel: 'apple-touch-icon', href: '/logos/apple-icon-152x152.png' }], 36 | ['link', { rel: 'apple-touch-icon', href: '/logos/apple-icon-180x180.png' }], 37 | ['link', { rel: 'icon', href: '/logos/android-icon-192x192.png' }], 38 | ['link', { rel: 'icon', href: '/logos/favicon-32x32.png' }], 39 | ['link', { rel: 'icon', href: '/logos/favicon-96x96.png' }], 40 | ['link', { rel: 'icon', href: '/logos/favicon-16x16.png' }], 41 | ['link', { rel: 'manifest', href: '/logos/manifest.json' }], 42 | ['meta', { property: 'og:title', content: 'Vue Cheatsheet' }], 43 | ['meta', { property: 'og:description', content: 'The only VueJS cheatsheet you will ever need' }], 44 | ['meta', { property: 'og:image', content: 'https://ts-assets.b-cdn.net/ts-assets/vue-cheatsheet/github-banner-smm.png' }], 45 | ['meta', { property: 'twitter:image', content: 'https://ts-assets.b-cdn.net/ts-assets/vue-cheatsheet/github-banner-smm.png' }], 46 | ['meta', { property: 'twitter:title', content: 'Vue.js CheatSheet By ThemeSelection' }], 47 | ['meta', { property: 'twitter:description', content: 'Accelerate your vue learning & improve your skills with our comprehensive Vue 3 cheatsheet.' }], 48 | ['meta', { property: 'twitter:card', content: 'summary_large_image' }], 49 | ['meta', { property: 'twitter:site', content: '@Theme_Selection' }], 50 | ['meta', { property: 'twitter:creator', content: '@Theme_Selection' }], 51 | ['meta', { property: 'keywords', content: 'Vue 3 Cheatsheet, VueJS Cheatsheet, Vue JS Cheatsheet' }], 52 | ['meta', { property: 'google-site-verification', content: 'Eb4Y887SF6gMOy33YpMZEZLJuVfQHW9E3b8QjoSTDhw' }], 53 | ['script', { src: 'https://buttons.github.io/buttons.js' }] 54 | ], 55 | themeConfig: { 56 | logo: { src: '/vue-cheatsheet-logo.png', alt: 'Vue Cheatsheet' }, 57 | 58 | siteTitle: 'Vue Cheatsheet', 59 | search: { 60 | provider: 'local', 61 | options: { 62 | detailedView: true, 63 | }, 64 | }, 65 | // https://vitepress.dev/reference/default-theme-config 66 | nav: [ 67 | { text: 'Home', link: '/' }, 68 | { text: 'Freebies', link: 'https://themeselection.com/item/category/freebies/' }, 69 | { text: 'Templates', link: 'https://themeselection.com/item/category/admin-templates/' }, 70 | { text: 'UI Kits', link: 'https://themeselection.com/item/category/ui-kits/' }, 71 | ], 72 | 73 | sidebar: [ 74 | { 75 | text: 'Introduction', 76 | items: [ 77 | { text: 'Contributing', link: '/contributing' }, 78 | { text: 'Changelog', link: '/changelog' }, 79 | ], 80 | }, 81 | { 82 | text: 'Vue', 83 | items: [ 84 | { text: 'Basic', link: '/vue/basic.md' }, 85 | { text: 'Reactivity', link: '/vue/reactivity' }, 86 | { text: 'Forms', link: '/vue/forms' }, 87 | { text: 'Component', link: '/vue/component' }, 88 | { text: 'Composable', link: '/vue/composable' }, 89 | { text: 'Built-in Components', link: '/vue/built-in-components' }, 90 | ] 91 | }, 92 | { 93 | text: 'Vue Router', 94 | items: [ 95 | { text: 'Basic', link: '/vue-router/basic.md' }, 96 | { text: 'Advanced', link: '/vue-router/advanced.md' }, 97 | ] 98 | }, 99 | { 100 | text: 'Pinia', 101 | items: [ 102 | { text: 'Basic', link: '/pinia/basic.md' }, 103 | ] 104 | } 105 | ], 106 | 107 | socialLinks: [ 108 | { icon: 'twitter', link: 'https://twitter.com/Theme_Selection' } 109 | ], 110 | 111 | editLink: { 112 | pattern: 'https://github.com/themeselection/vue-cheatsheet/edit/main/content/:path' 113 | } 114 | }, 115 | vite: { 116 | resolve: { 117 | alias: [ 118 | { 119 | find: /^.*\/VPFooter\.vue$/, 120 | replacement: fileURLToPath( 121 | new URL('./theme/components/Footer.vue', import.meta.url) 122 | ) 123 | } 124 | ] 125 | } 126 | }, 127 | markdown: { 128 | // ℹ️ We only enabled this in development so that we can highlight code lines by seeing line number without calculating it in our editor. 129 | lineNumbers: false, 130 | toc: { level: [1, 2,] }, 131 | 132 | theme: { 133 | light: 'github-light', 134 | dark: 'dracula' 135 | }, 136 | math: true, 137 | }, 138 | transformHtml: async (code, id, ctx) => { 139 | return code 140 | .replace('', `\n${gtmConfig.headScript}`) 141 | .replace('', `\n${gtmConfig.bodyNoScript}`) 142 | } 143 | }) 144 | -------------------------------------------------------------------------------- /content/.vitepress/theme/components/ActionButtons.vue: -------------------------------------------------------------------------------- 1 | 6 | 18 | 19 | 30 | -------------------------------------------------------------------------------- /content/.vitepress/theme/components/DocFooter.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /content/.vitepress/theme/components/Footer.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 62 | 63 | 85 | -------------------------------------------------------------------------------- /content/.vitepress/theme/components/GithubCounterBtn.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 19 | 20 | 31 | -------------------------------------------------------------------------------- /content/.vitepress/theme/components/SocialLinks.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 44 | -------------------------------------------------------------------------------- /content/.vitepress/theme/components/SubscribeAlert.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | -------------------------------------------------------------------------------- /content/.vitepress/theme/components/SubscribeForm.vue: -------------------------------------------------------------------------------- 1 | 3 | 4 | 22 | -------------------------------------------------------------------------------- /content/.vitepress/theme/components/VueThemesCallOut.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /content/.vitepress/theme/custom.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --vp-c-brand-1: #42b883; 3 | --vp-c-brand-2: #42d392; 4 | --vp-c-brand-3: #35eb9a; 5 | 6 | // Hero title 7 | --vp-home-hero-name-color: transparent; 8 | --vp-home-hero-name-background: var(--vp-c-brand-2); 9 | 10 | --vp-layout-max-width: 1344px; 11 | --vp-nav-logo-height: 2.5rem; 12 | } 13 | 14 | .VPHero { 15 | &.VPHomeHero { 16 | margin-top: 1.25rem; 17 | margin-bottom: 2.25rem; 18 | } 19 | } 20 | 21 | .VPButton.brand { 22 | background-color: var(--vp-c-brand-2) !important 23 | } 24 | 25 | .VPButton { 26 | border-radius: 0.5rem !important; 27 | } 28 | 29 | @media (min-width: 960px) { 30 | .tagline { 31 | font-size: 22px !important; 32 | opacity: 80%; 33 | } 34 | } 35 | 36 | .VPFeature { 37 | background: transparent !important; 38 | border-color: var(--vp-c-gray-3) !important; 39 | 40 | &:hover { 41 | .title { 42 | color: var(--vp-c-brand-2) !important; 43 | } 44 | 45 | border-color: var(--vp-c-brand-2) !important; 46 | } 47 | } 48 | 49 | /* Style home logo */ 50 | .VPContent.is-home .VPHomeHero .VPImage { 51 | width: 100%; 52 | height: auto; 53 | } 54 | 55 | .VPContent { 56 | .container { 57 | max-width: 1280px !important; 58 | } 59 | } 60 | 61 | // Restore search bg 62 | @media (min-width: 768px) { 63 | button.DocSearch-Button { 64 | background-color: var(--vp-c-bg-alt); 65 | } 66 | 67 | .VPHero { 68 | &.VPHomeHero { 69 | margin-top: 3.5rem; 70 | margin-bottom: 2.25rem; 71 | } 72 | } 73 | } 74 | 75 | // Enable below after: https://github.com/vuejs/vitepress/pull/3522 76 | .VPNav:has(~ .is-home) .title > span { 77 | display: none; 78 | } 79 | -------------------------------------------------------------------------------- /content/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import DefaultTheme from 'vitepress/theme'; 2 | import { h } from 'vue'; 3 | import ActionButtons from './components/ActionButtons.vue'; 4 | import DocFooter from './components/DocFooter.vue'; 5 | import GithubCounterBtn from './components/GithubCounterBtn.vue'; 6 | import SubscribeAlert from './components/SubscribeAlert.vue'; 7 | import HomeVueThemesCallOut from './components/VueThemesCallOut.vue'; 8 | import './custom.scss'; 9 | import './tailwind.css'; 10 | 11 | export default { 12 | extends: DefaultTheme, 13 | Layout() { 14 | return h(DefaultTheme.Layout, null, { 15 | 'home-features-before': h(HomeVueThemesCallOut), 16 | 'doc-after': h(DocFooter), 17 | 'home-hero-before': h(SubscribeAlert), 18 | 'home-hero-actions-after': h(ActionButtons), 19 | 'nav-bar-content-after': h(GithubCounterBtn), 20 | }) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /content/.vitepress/theme/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /content/changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 2024-01-31 4 | 5 | - Initial Release 6 | -------------------------------------------------------------------------------- /content/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Great! We appreciate your willingness to contribute! 4 | 5 | The following are some guidelines for contributing to the Vue cheatsheet. These guidelines are meant to provide direction, but they are not strict rules. Please use your own judgment, and feel free to suggest changes to [this document](https://github.com/themeselection/vue-cheatsheet/blob/master/src/pages/contributing.md). 6 | 7 | ## Running the project locally 8 | 9 | 1. We recommend [pnpm](https://pnpm.io/installation) package manager. You can download it from [here](https://pnpm.io/installation). If you don't want to use `pnpm`, you can use `npm` or `yarn` instead. 10 | 11 | 2. Clone the project, and install the dependencies: 12 | 13 | ```shell 14 | git clone https://github.com/themeselection/vue-cheatsheet.git 15 | cd vue-cheatsheet 16 | pnpm install 17 | ``` 18 | 19 | 3. Create a new branch: 20 | 21 | ```shell 22 | git branch new_content 23 | git checkout new_content 24 | ``` 25 | 26 | 4. Change/upgrade/add the changes you want 27 | 5. Update the `README` if needed 28 | 6. `Add`, `commit` and `push` your changes to GitHub: 29 | 30 | ```shell 31 | git add . 32 | git commit -m 'Your commit message' 33 | git push origin new_content 34 | ``` 35 | 36 | 7. Open a [pull request](https://github.com/themeselection/vue-cheatsheet/pulls) 37 | 38 | ## You can 39 | 40 | - Submit changes to the cheatsheet 41 | - Improve existing topics and examples 42 | - Add new topics or resources 43 | - Ask for new topics by creating an [Issue](https://github.com/themeselection/vue-cheatsheet/issues) 44 | - Read the issues, fork the project and do a [Pull Request](https://github.com/themeselection/vue-cheatsheet/pulls) 45 | - Report any kind of error or typo by creating an [Issue](https://github.com/themeselection/vue-cheatsheet/issues) or fix it with a [Pull Request](https://github.com/themeselection/vue-cheatsheet/pulls) 46 | 47 | ## What you need to know 48 | 49 | If you don't know where to start: 50 | 51 | - [Mastering Markdown](https://guides.github.com/features/mastering-markdown/) 52 | - [Mastering Issues](https://guides.github.com/features/issues/) 53 | - [Forking Projects](https://guides.github.com/activities/forking/) 54 | - And read the rest of the [GitHub Guides](https://guides.github.com/) 55 | -------------------------------------------------------------------------------- /content/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | hero: 6 | name: "Vue Cheatsheet" 7 | tagline: The only VueJS cheatsheet you will ever need 8 | image: 9 | src: /hero-image.png 10 | alt: Vue Cheatsheet 11 | 12 | features: 13 | - title: Vue 14 | icon: 15 | src: /vue-logo.png 16 | alt: 'Vue' 17 | details: Accelerate your vue learning & improve your skills with our comprehensive Vue 3 cheatsheet. 18 | link: /vue/basic 19 | - title: Vue Router 20 | icon: 21 | src: /vue-router-logo.png 22 | alt: 'Vue Router' 23 | details: Your Simple Guide to Vue Router, Making Routes as Easy as Following a Map. 24 | link: /vue-router/basic 25 | - title: Pinia 26 | icon: 27 | src: /pinia-logo.png 28 | alt: 'Pinia' 29 | details: Your vue js cheatsheet for Pina, perfect for vue beginners and beyond. 30 | link: /pinia/basic 31 | --- 32 | -------------------------------------------------------------------------------- /content/pinia/basic.md: -------------------------------------------------------------------------------- 1 | # Pinia 2 | 3 | Pinia is a store library for Vue which allows you to share a state across components. 4 | 5 | ::: tip Note 6 | We have used Composition API in this cheatsheet as it is recommended. 7 | ::: 8 | 9 | ::: info In Setup Stores 10 | 11 | `ref()`s become state properties. 12 | 13 | `computed()`s become getters. 14 | 15 | `function()`s become actions. 16 | ::: 17 | 18 | ## Define Store 19 | 20 | ```js 21 | export const useCounterStore = defineStore('counter', () => { 22 | 23 | // States 24 | const count = ref(0) 25 | const name = ref('Eduardo') 26 | 27 | // Getters 28 | const doubleCount = computed(() => count.value * 2) 29 | 30 | // Actions 31 | function increment() { 32 | count.value++ 33 | } 34 | 35 | return { count, name, doubleCount, increment } 36 | }) 37 | ``` 38 | 39 | ## Use store 40 | 41 | ```vue 42 | 59 | ``` 60 | 61 | ## States 62 | 63 | ### Define a state 64 | 65 | ```js 66 | export const useCounterStore = defineStore('counter', () => { 67 | // States 68 | const count = ref(0) // [!code hl] 69 | 70 | return { count } 71 | }) 72 | ``` 73 | 74 | ### Accessing the States 75 | 76 | ```vue 77 | 81 | ``` 82 | 83 | ### Resetting the States 84 | 85 | In Setup Stores, you need to create your own `$reset()` method 86 | 87 | ```js 88 | export const useCounterStore = defineStore('counter', () => { 89 | const count = ref(0) 90 | 91 | function $reset() { 92 | count.value = 0 93 | } 94 | }) 95 | ``` 96 | 97 | ### Mutating the state 98 | 99 | We use `$patch` method for mutating the state. 100 | 101 | ```vue 102 | 105 | ``` 106 | 107 | ### Replacing the state 108 | 109 | ```vue 110 | 113 | ``` 114 | 115 | ### Subscribing to the state 116 | 117 | You can watch the state and its changes through the `$subscribe()` method of a store. 118 | 119 | ```js 120 | store.$subscribe((mutation, state) => { 121 | // import { MutationType } from 'pinia' 122 | mutation.type // 'direct' | 'patch object' | 'patch function' 123 | // same as cartStore.$id 124 | mutation.storeId // 'cart' 125 | // only available with mutation.type === 'patch object' 126 | mutation.payload // patch object passed to cartStore.$patch() 127 | 128 | // persist the whole state to the local storage whenever it changes 129 | localStorage.setItem('counter', JSON.stringify(state)) 130 | }) 131 | ``` 132 | 133 | ## Store computed Properties aka Getters 134 | 135 | Getters are exactly the equivalent of computed values for the state of a Store. 136 | 137 | ### Define a Getter 138 | 139 | ```js 140 | export const useCounterStore = defineStore('counter', () => { 141 | 142 | const count = ref(0) 143 | 144 | const doubleCount = computed(() => count.value * 2) // [!code hl] 145 | 146 | return { count, doubleCount } 147 | }) 148 | ``` 149 | 150 | ### Accessing Getters 151 | 152 | ```js 153 | 158 | 159 | 162 | ``` 163 | 164 | ### Accessing Other Getters 165 | 166 | ```js 167 | export const useCounterStore = defineStore('counter', () => { 168 | 169 | const count = ref(0) 170 | const doubleCount = computed(() => count.value * 2) 171 | 172 | const doubleCountPlusOne = computed(() => doubleCount.value + 1) // [!code hl] 173 | 174 | return { count, doubleCount, doubleCountPlusOne} 175 | }) 176 | ``` 177 | 178 | ### Accessing Other Store Getters 179 | 180 | ```js 181 | import { useOtherStore } from './other-store' 182 | 183 | export const useStore = defineStore('main', { 184 | 185 | const otherGetter = computed(() => { 186 | const otherStore = useOtherStore() 187 | return state.localData + otherStore.data 188 | }) 189 | }) 190 | ``` 191 | 192 | ## Store methods aka Actions 193 | 194 | Actions are the equivalent of methods in components. 195 | 196 | ### Defining an action 197 | 198 | ```js 199 | export const useCounterStore = defineStore('counter', () => { 200 | 201 | const count = ref(0) 202 | 203 | function increment() { // [!code hl] 204 | count.value++ // [!code hl] 205 | } // [!code hl] 206 | 207 | return { count, increment } 208 | }) 209 | ``` 210 | 211 | ### Accessing Actions 212 | 213 | ```vue 214 | 219 | 220 | 223 | ``` 224 | 225 | ### Accessing other store actions 226 | 227 | ```js 228 | import { useAuthStore } from './auth-store' 229 | 230 | export const useSettingsStore = defineStore('settings', { 231 | 232 | const preferences = ref([]) 233 | 234 | const fetchPreferences = () => { 235 | const auth = useAuthStore() 236 | 237 | if(auth.isAuthenticated) 238 | preferences = await fetchPreferences() 239 | else 240 | throw new Error('User must be authenticated') 241 | } 242 | 243 | }) 244 | ``` 245 | 246 | ## Plugin 247 | 248 | A Pinia plugin is a function that optionally returns properties to be added to a store. It takes one optional argument, a context: 249 | 250 | ```js 251 | export function myPiniaPlugin(context) { 252 | context.pinia // the pinia created with `createPinia()` 253 | context.app // the current app created with `createApp()` (Vue 3 only) 254 | context.store // the store the plugin is augmenting 255 | context.options // the options object defining the store passed to `defineStore()` 256 | // ... 257 | } 258 | 259 | pinia.use(myPiniaPlugin) 260 | ``` 261 | 262 | ```js 263 | import { markRaw } from 'vue' 264 | // adapt this based on where your router is 265 | import { router } from './router' 266 | 267 | pinia.use(() => ({ hello: 'world' })) 268 | 269 | pinia.use(({ store }) => { 270 | store.router = markRaw(router) 271 | }) 272 | 273 | pinia.use(({ store }) => { 274 | store.$subscribe(() => { 275 | // react to store changes 276 | }) 277 | store.$onAction(() => { 278 | // react to store actions 279 | }) 280 | }) 281 | ``` 282 | -------------------------------------------------------------------------------- /content/public/brand-logo-small-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/brand-logo-small-dark.png -------------------------------------------------------------------------------- /content/public/brand-logo-small-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/brand-logo-small-light.png -------------------------------------------------------------------------------- /content/public/google6f658ffc1e5996cb.html: -------------------------------------------------------------------------------- 1 | google-site-verification: google6f658ffc1e5996cb.html -------------------------------------------------------------------------------- /content/public/hero-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/hero-image.png -------------------------------------------------------------------------------- /content/public/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/hero.png -------------------------------------------------------------------------------- /content/public/logos/android-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/logos/android-icon-192x192.png -------------------------------------------------------------------------------- /content/public/logos/apple-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/logos/apple-icon-114x114.png -------------------------------------------------------------------------------- /content/public/logos/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/logos/apple-icon-120x120.png -------------------------------------------------------------------------------- /content/public/logos/apple-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/logos/apple-icon-144x144.png -------------------------------------------------------------------------------- /content/public/logos/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/logos/apple-icon-152x152.png -------------------------------------------------------------------------------- /content/public/logos/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/logos/apple-icon-180x180.png -------------------------------------------------------------------------------- /content/public/logos/apple-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/logos/apple-icon-57x57.png -------------------------------------------------------------------------------- /content/public/logos/apple-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/logos/apple-icon-60x60.png -------------------------------------------------------------------------------- /content/public/logos/apple-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/logos/apple-icon-72x72.png -------------------------------------------------------------------------------- /content/public/logos/apple-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/logos/apple-icon-76x76.png -------------------------------------------------------------------------------- /content/public/logos/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/logos/favicon-16x16.png -------------------------------------------------------------------------------- /content/public/logos/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/logos/favicon-32x32.png -------------------------------------------------------------------------------- /content/public/logos/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/logos/favicon-96x96.png -------------------------------------------------------------------------------- /content/public/logos/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/logos/favicon.ico -------------------------------------------------------------------------------- /content/public/logos/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "App", 3 | "icons": [ 4 | { 5 | "src": "\/android-icon-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image\/png", 8 | "density": "0.75" 9 | }, 10 | { 11 | "src": "\/android-icon-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image\/png", 14 | "density": "1.0" 15 | }, 16 | { 17 | "src": "\/android-icon-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image\/png", 20 | "density": "1.5" 21 | }, 22 | { 23 | "src": "\/android-icon-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image\/png", 26 | "density": "2.0" 27 | }, 28 | { 29 | "src": "\/android-icon-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image\/png", 32 | "density": "3.0" 33 | }, 34 | { 35 | "src": "\/android-icon-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image\/png", 38 | "density": "4.0" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /content/public/pinia-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/pinia-logo.png -------------------------------------------------------------------------------- /content/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /content/public/vue-cheatsheet-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/vue-cheatsheet-logo.png -------------------------------------------------------------------------------- /content/public/vue-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/vue-logo.png -------------------------------------------------------------------------------- /content/public/vue-router-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themeselection/vue-cheatsheet/d36c2dc747aeabfe7cd9e462a9e2ef20f53d61c9/content/public/vue-router-logo.png -------------------------------------------------------------------------------- /content/vue-router/advanced.md: -------------------------------------------------------------------------------- 1 | # Advanced 2 | 3 | ## Scroll Behavior 4 | 5 | With client-side routing, we might want to scroll to the top on a new route, or keep the scroll position like a real page reload. 6 | 7 | ```ts 8 | const router = createRouter({ 9 | history: createWebHashHistory(), 10 | routes: [...], 11 | scrollBehavior (to, from, savedPosition) { 12 | // return desired position 13 | return { top : 0 } 14 | 15 | // always scroll 10px above the element #main 16 | return { el: '#main', top: 10 } 17 | 18 | // Returning the savedPosition 19 | return (savePosition ? savedPosition : { top : 0 }) 20 | 21 | // "scroll to anchor" behavior & "scroll behavior to smooth" 22 | if (to.hash) 23 | return { el: to.hash, behavior: 'smooth' } 24 | 25 | // Delaying the scroll 26 | return new Promise((resolve, reject) => { 27 | setTimeout(() => { 28 | resolve({ left: 0, top: 0 }) 29 | }, 500) 30 | }) 31 | } 32 | }) 33 | ``` 34 | 35 | ## Navigation Guards & Navigation Flow 36 | 37 | They are primarily used to guard navigations either by redirecting it or canceling it. 38 | 39 | 1. Navigation triggered. 40 | 2. Call `beforeRouteLeave` guards in deactivated components. 41 | 3. Call global `beforeEach` guards. 42 | 4. Call `beforeRouteUpdate` guards in reused components. 43 | 5. Call `beforeEnter` in route configs. 44 | 6. Resolve async route components. 45 | 7. Call `beforeRouteEnter` in activated components. 46 | 8. Call global `beforeResolve` guards. 47 | 9. Navigation is confirmed. 48 | 10. Call global `afterEach` hooks. 49 | 11. DOM updates triggered. 50 | 12. Call callbacks passed to `next` in `beforeRouteEnter` guards with instantiated instances. 51 | 52 | Every guard function receives two arguments: 53 | 54 | `to`: the target route location in a normalized format being navigated to. 55 | 56 | `from`: the current route location in a normalized format being navigated away from. 57 | 58 | ## RouterView slot 59 | 60 | The RouterView component exposes a slot that can be used to render the route component 61 | 62 | ```vue 63 | 72 | ``` 73 | 74 | ## Transitions 75 | 76 | ```vue 77 | 84 | ``` 85 | 86 | ### Per-Route Transition 87 | 88 | ```ts 89 | // Apply different transitions on each route's. 90 | 91 | const routes = [ 92 | { 93 | path: '/custom-transition', 94 | component: PanelLeft, 95 | meta: { transition: 'slide-left' }, 96 | }, 97 | { 98 | path: '/other-transition', 99 | component: PanelRight, 100 | meta: { transition: 'slide-right' }, 101 | }, 102 | ] 103 | ``` 104 | 105 | ```vue 106 | 114 | ``` 115 | 116 | ## Route Meta fields 117 | 118 | Attach arbitrary information to routes like: transition names, or roles to control who can access the route, etc. 119 | 120 | ```js 121 | const routes = [ 122 | { 123 | path: '/posts', 124 | component: PostsLayout, 125 | children: [ 126 | { 127 | path: 'new', 128 | component: PostsNew, 129 | // only authenticated users can create posts 130 | meta: { requiresAuth: true }, 131 | }, 132 | { 133 | path: ':id', 134 | component: PostsDetail, 135 | // anybody can read a post 136 | meta: { requiresAuth: false }, 137 | }, 138 | ], 139 | }, 140 | ] 141 | ``` 142 | -------------------------------------------------------------------------------- /content/vue-router/basic.md: -------------------------------------------------------------------------------- 1 | # Vue Router 2 | 3 | ## Basic Route Setup 4 | 5 | ```ts 6 | // src/route/index.ts 7 | 8 | const router = createRouter({ 9 | ... 10 | routes: [ 11 | { 12 | path: '/', 13 | name: 'home', // "home" will be route name 14 | component: () => import('./views/HomeView.vue') // Always lazy load route components 15 | }, 16 | { 17 | path: '/about', 18 | name: 'about', 19 | component: () => import('./views/About.vue') 20 | } 21 | ] 22 | }) 23 | ``` 24 | 25 | Use `RouterView` to render the matched component for the current route, and use `RouterLink` component to create links to navigate between routes. 26 | 27 | ```vue 28 | 37 | ``` 38 | 39 | ## Programmatic Navigation 40 | 41 | Aside from using `` to create anchor tags for declarative navigation, we can do this programmatically using the router's instance methods. 42 | 43 | | Declarative | Programmatic | 44 | | ------------- | :-----------: | 45 | | `` | `router.push(...)` | 46 | | `` | `router.replace(...)` | 47 | | `window.history.go(n)` | `router.go(1)` | 48 | 49 | The argument can be a string path, or a location descriptor object. 50 | 51 | ```ts 52 | // literal string path 53 | router.push('/users/eduardo') 54 | 55 | // object with path 56 | router.push({ path: '/users/eduardo' }) 57 | 58 | // named route with params to let the router build the url 59 | router.push({ name: 'user', params: { username: 'eduardo' } }) 60 | 61 | // with query, resulting in /register?plan=private 62 | router.replace({ path: '/register', query: { plan: 'private' } }) 63 | 64 | // with hash, resulting in /about#team 65 | router.replace({ path: '/about', hash: '#team' }) 66 | 67 | // go forward by one record, the same as router.forward() 68 | router.go(1) 69 | 70 | // go back by one record, the same as router.back() 71 | router.go(-1) 72 | ``` 73 | 74 | ## Dynamic Routing 75 | 76 | Dynamic routes are used to match a series of routes with some params to be acquired. (Denoted by **colon** `:` ) 77 | 78 | ```ts 79 | // src/router/index.ts 80 | 81 | const router = createRouter({ 82 | ... 83 | routes: [ 84 | { 85 | path: '/product/:id', // [!code highlight] 86 | name: 'product', 87 | component: () => import('./views/ProductView.vue') 88 | } 89 | ] 90 | }) 91 | ``` 92 | 93 | ``` vue 94 | 95 | 96 | 107 | 108 | 113 | ``` 114 | 115 | ## Catch all / 404 Not found Route 116 | 117 | ```ts {6,12} 118 | const router = createRouter({ 119 | ... 120 | routes: [ 121 | // will match everything and put it under `$route.params.pathMatch` 122 | { 123 | path: '/:pathMatch(.*)*', 124 | name: 'NotFound', 125 | component: () => import('./views/NotFound.vue') // Component 126 | }, 127 | // will match anything starting with `/user-` and put it under `$route.params.afterUser` 128 | { 129 | path: '/user-:afterUser(.*)', 130 | component: () => import('./views/UserGeneric.vue') // Component 131 | } 132 | ] 133 | }) 134 | ``` 135 | 136 | ## Routes' Matching Syntax 137 | 138 | ```ts 139 | const routes = [ 140 | // matches /o/3549 or /o/books 141 | { path: '/o/:orderId' }, 142 | 143 | // /:orderId -> matches only numbers 144 | { path: '/:orderId(\\d+)' }, 145 | 146 | // /:productName -> matches anything else 147 | { path: '/:productName' }, 148 | 149 | // /:chapters -> matches /one, /one/two, /one/two/three, etc 150 | { path: '/:chapters+' }, 151 | 152 | // /:chapters -> matches /, /one, /one/two, /one/two/three, etc 153 | { path: '/:chapters*' }, 154 | 155 | // Sensitive and strict route options: match /users/posva but not: 156 | // - /Users/posva because of sensitive: true 157 | { path: '/users/:id', sensitive: true }, 158 | 159 | // - /users/posva/ because of strict: true 160 | { path: '/users/:id?', strict: true }, 161 | 162 | // Optional parameters: match /users and /users/posva 163 | { path: '/users/:userId?' }, 164 | ] 165 | ``` 166 | 167 | ## Nested Routes 168 | 169 | It is used when components that are nested with **multiple levels deep**. 170 | 171 | ``` 172 | /user/johnny/profile /user/johnny/posts 173 | +------------------+ +-----------------+ 174 | | User | | User | 175 | | +--------------+ | | +-------------+ | 176 | | | Profile | | +------------> | | Posts | | 177 | | | | | | | | | 178 | | +--------------+ | | +-------------+ | 179 | +------------------+ +-----------------+ 180 | ``` 181 | 182 | ```ts 183 | // src/router/index.ts 184 | 185 | const router = createRouter({ 186 | ... 187 | routes: [ 188 | { 189 | path: '/product/:id', 190 | name: 'product', 191 | component: () => import('./views/ProductView.vue'), 192 | children: [ 193 | { 194 | path: 'reviews', 195 | component: () => import('./views/ProductReviews.vue') 196 | }, 197 | { 198 | path: 'variations', 199 | component: () => import('./views/ProductVariations.vue') 200 | }, 201 | ] 202 | } 203 | ] 204 | }) 205 | ``` 206 | 207 | ```vue 208 | 209 | 210 | 215 | ``` 216 | 217 | ## Named Views 218 | 219 | ```ts 220 | // display multiple views at the same time 221 | const router = createRouter({ 222 | history: createWebHashHistory(), 223 | routes: [ 224 | { 225 | path: '/', 226 | components: { 227 | default: Home, 228 | // short for LeftSidebar: LeftSidebar 229 | LeftSidebar, 230 | // they match the `name` attribute on `` 231 | RightSidebar, 232 | }, 233 | }, 234 | ], 235 | }) 236 | ``` 237 | 238 | ```vue 239 | 244 | ``` 245 | 246 | [Working Demo](https://codesandbox.io/p/sandbox/named-views-vue-router-4-examples-rd20l?file=%2Fsrc%2Frouter.js%3A25%2C9) 247 | 248 | ## Redirect 249 | 250 | Redirecting is also done in the routes configuration. To redirect from /home to /: 251 | 252 | ```ts 253 | const router = createRouter({ 254 | ... 255 | routes: [ 256 | { 257 | path: '/home', 258 | redirect: '/', 259 | }, 260 | // targeting a named route 261 | { 262 | path: '/home', 263 | redirect: { name: 'homepage' }, 264 | } 265 | ] 266 | }) 267 | ``` 268 | 269 | ## Alias 270 | 271 | ```ts 272 | const routes = [ 273 | { 274 | path: '/users/:id', 275 | component: UsersByIdLayout, 276 | children: [ 277 | /* 278 | this will render the UserDetails for these 3 URLs 279 | - /users/24 280 | - /users/24/profile 281 | - /24 282 | */ 283 | { path: 'profile', component: UserDetails, alias: ['/:id', ''] }, 284 | ], 285 | }, 286 | ] 287 | ``` 288 | 289 | ::: info `Redirect` vs. `Alias` 290 | 291 | A redirect means when the user visits `/home`, the URL will be replaced by `/`, and then matched as `/`. 292 | 293 | An alias of `/` as `/home` means when the user visits `/home`, the URL remains `/home`, but it will be matched as if the user is visiting `/`. 294 | 295 | ::: 296 | 297 | ## Passing Props to Route Components 298 | 299 | ```vue 300 | 330 | 331 | 332 | 340 | ``` 341 | -------------------------------------------------------------------------------- /content/vue/basic.md: -------------------------------------------------------------------------------- 1 | # Vue Basic 2 | 3 | ## Data binding 4 | 5 | ```vue 6 | 12 | 13 | 20 | ``` 21 | 22 | ## Attribute Bindings 23 | 24 | ```vue 25 | 26 |
27 | 28 | 29 |
30 | 31 | 32 |
33 | 34 | 35 |
36 | ``` 37 | 38 | ### Event Bindings 39 | 40 | ```vue 41 | 42 | 43 | 44 | 45 | 46 | ``` 47 | 48 | ::: info 49 | Furthermore, we'll exclusively use shorthand notation 50 | ::: 51 | 52 | ### Boolean Attributes 53 | 54 | ```vue 55 | 60 | 61 | 64 | ``` 65 | 66 | ### Dynamically Binding Multiple Attributes 67 | 68 | ```vue 69 | 75 | 76 | 80 | ``` 81 | 82 | ## Using JavaScript Expressions 83 | 84 | ```vue 85 | 94 | 95 | 105 | ``` 106 | 107 | ## Directives 108 | 109 | ![Directive-Structure](https://vuejs.org/assets/directive.7WSr6AKH.png) 110 | 111 | ::: details Vue all Directives with their API 112 | 113 | ::: 114 | 115 | ```vue 116 | 117 |
118 | 119 | 120 | 121 | 122 | 123 |

Hello!

124 | 125 | 126 |
A
127 |
B
128 |
C
129 |
Not A/B/C
130 | 131 | 132 |
{{ item }}
133 | 134 | 135 | This will never change: {{msg}} 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | ... 145 | 146 | 147 |
...
148 | 149 | 150 | {{ this will not be compiled }} 151 | 152 | 153 |
...
154 | 155 | 156 |
{{ message }}
157 | ``` 158 | 159 | ::: info `v-if` vs. `v-show` 160 | `v-if`: Use when the condition is unlikely to change often. 161 | 162 | `v-show`: Use when you need to toggle frequently. 163 | ::: 164 | 165 | ### Example: Quick review of using 'v-for' with arrays and objects 166 | 167 | ```vue 168 | 179 | 180 | 204 | ``` 205 | 206 | ## Template Refs 207 | 208 | Give access to DOM elements. 209 | 210 | ```vue 211 | 220 | 221 | 224 | ``` 225 | 226 | ## Lifecycle Hooks 227 | 228 | | Hooks | Descpriton | 229 | | :-------------: | :-------------------------------------: | 230 | | beforeCreate | After the instance has been initialized | 231 | | created | After the instance is created | 232 | | onBeforeMount | Before mounting DOM | 233 | | onMounted | DOM can be accessed | 234 | | onBeforeUpdate | Reactive data changes | 235 | | onUpdated | DOM has been updated | 236 | | onBeforeUnmount | Component still complete | 237 | | onUnmounted | Teardown complete | 238 | 239 | ## Event Handling 240 | 241 | ```vue 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 261 | 262 | 263 | 266 | 267 | 268 | 269 | 270 | 271 | 272 |
273 | 274 | 275 | 276 | 277 | 278 |
279 | 280 | 281 | 282 |
...
283 | 284 | 285 | 286 | 287 |
...
288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 |
...
296 | ``` 297 | 298 | ### Key Modifiers 299 | 300 | | Key Modifier | Example Usage | 301 | | ------------ | ------------- | 302 | | keyup.enter | Triggers Enter key up event | 303 | | keyup.tab | Triggers Tab key up event | 304 | | keyup.delete | Triggers Delete or Backspace key up event | 305 | | keyup.esc | Triggers Escape key up event | 306 | | keyup.space | Triggers Space key up event | 307 | | keyup.arrow-up | Triggers arrow up key up event | 308 | | keyup.arrow-down | Triggers arrow down key up event | 309 | | keyup.arrow-left | Triggers arrow left key up event | 310 | | keyup.arrow-right | Triggers arrow right key up event | 311 | 312 | ### Mouse modifiers 313 | 314 | | Mouse Modifier | Example Usage | 315 | | ------------ | ------------- | 316 | | mousedown.left | Triggers Mouse left click event | 317 | | mousedown.right | Triggers Mouse right click event | 318 | | mousedown.middle | Triggers Mouse middle click event | 319 | -------------------------------------------------------------------------------- /content/vue/built-in-components.md: -------------------------------------------------------------------------------- 1 | # Built-in Components 2 | 3 | ## Transition 4 | 5 | `` : It can be used to apply enter and leave animations on elements or components passed to it via its default slot. 6 | 7 | ![Transition Image](https://vuejs.org/assets/transition-classes.2BufuvZR.png) 8 | 9 | ```vue{9-11} 10 | 15 | 16 | 22 | 23 | 34 | ``` 35 | 36 | [Try it in the Playground](https://play.vuejs.org/#eNp9UstOwzAQ/BXjCyDRBKniUtKKh3qAAyDo0ZfgblO3jm3Zm7RV1X9nHUelSKineGdnxrMb7/mjc1nbAB/xIkivHLIA2LiJMKp21iPbMw8LdmALb2t2SdRLYYSR1gSiLu2GjSPhCn0D18IUeXIhPRUItdMlAlWMFd8NojXsQWol12PBe/VF/Ao+mdmq0lDkiZYkM1+aoFD1NSGOtQO16NWkWoLWtshjYOrmfwRFfhKAyoA7HY9ZOwCD4AelRNXCTYdoKFvoEbaPbnj0GjHrSqlwx26zu8CgDHAvzCGaHr3ifk6d0CaXXjlit0lCG+pi8BuOgda4UFW2CtbQH+j4gktbO6XBv7t4dxB8lJxir6RpN68dFjdOFyZcLkGu/8FXYRsxwT88BPAtCH7sYekrwNSefr3Bls7HZm3njSb2meYnBKubmDHRnhozp9gnvC7tS/eOlKlmYbpFoJX2Q8WgkXno+ILT23o+M/pv3GE27HS0T374AbBs70k=) 37 | 38 | ### Using Javascript Hooks 39 | 40 | ```vue 41 | 51 | 52 | 53 | ``` 54 | 55 | ## TransitionGroup 56 | 57 | ``: It is designed for animating the insertion, removal, and order change of elements or components that are rendered in a list. 58 | 59 | ```vue{5-9} 60 | 70 | 71 | 82 | ``` 83 | 84 | [Try it in the Playground](https://play.vuejs.org/#eNp9VMFu2zAM/RXCwJBkdZ10WS9eGmzriqEDthVbDwPqHjSbjtXKkmHRaYog/z5KStIka3syST0+PtKiltGnpknmHUZpNLF5KxsCi9Q100zLujEtwRJaLGEFZWtq6DG0l+lM50ZbghnSpZYkhbokrC2cQX8AZ1O4OYnhXQzjGN7HcHq7gcs1iAn7B6n9wSDTChlTMMADk7lQHSYK9YwqOIITV7fsdE7SaJDaYktcbplpgDU/p34XVCWt6XTRD6bQhakZ9/YZVq4Je2HbKJljX8YwilnK0REjVnt1W+T5bMrupHLp/1rykNf68dSTYRg8j5wdRjZKELIHMPnbEXHRjznLuj/LotB1Fk2DAYIgNMjzKHAxGYaE55O9dM713x2oB18zj2XxRn/l6TVAYsYpncoi0KJGtpW0nA25EtayyyMnITW2zOgYmENJmB+XpnVCuQ/WFDrfyXI+u+k9Pm69dTrAcunxsOK5eMKhkqGV4YE8jk6GO6Ni19KjcmbiKfzveZAFVSmcjEZvPji/QjmrKIXxqFlwwE8/cW0doyZsjwX/4jnGm6BCMcd1MBDSVkUKQikYJacWUFgMbLtcbl0OmMgEFtOIXNJjCiOvypPy1Oo0mK6lP32ncRBo+YL43qI4IstjL+UsubNG8856Pvcv6kYqbH82ThvPOw2V3BnrNA/ffIzaznUX4nmF+f0z8Tu7cLEsunL3pJ1jFm3PSLR8ycPxxe8fuGB7e1ibolOMfuXwF1qjOqcxwD7zmrLsHZxXe+lfHqln1/ZiQcgjXzflhDrkyuOziF+j81daf5I7TsY+j+fJUzyvpCpeePXCS9K0pnEvVYElX/Er5/VveiRJYe+W9/rFnZ0Ucv7CikwqFAW2zrLK0GatQpQRzMlhf7OfkDXnbzKmX7AUnSL32vFUeIW3CRtYaQxfvsMSIbpf4gk5ZMn7+xSt/gH4Zxci) 85 | 86 | ## KeepAlive 87 | 88 | ``: It allows us to conditionally cache component instances when dynamically switching between multiple components. 89 | 90 | ::: code-group 91 | 92 | ```vue{13-15} [App.vue] 93 | 100 | 101 | 110 | ``` 111 | 112 | ```vue [CompA.vue] 113 | 118 | 119 | 124 | ``` 125 | 126 | ```vue [CompB.vue] 127 | 132 | 133 | 138 | ``` 139 | 140 | ::: 141 | 142 | [Try it in the Playground](https://play.vuejs.org/#eNqtU01vnDAQ/SuWL5sq6VIpN0RQlyiHtOqH0h65EJglToxt+YNuhfjvHdssYbf5kKLc8Jvn8XvzhoFulFr3DmhKM1NrpiwxYJ3KS0EI65TUlgzE3FWcyz83sCUj2WrZkRXeWS04l7JTm6m0TsLJtz2mFAeUYqJ4Ui2FsaR2WoOw5GLx5EmgfihFlkSFqA0PFjrFKwtBadawntS8MuaipA10sqQBxwqvboHnGRPKWWL/KkCGrhqGFNJ/7GQDHJHpYcTSvuLOk4IJBJKcbLIktnmPnkXsWRz1/AqgNpz10VCAamRL4eeRMm9sbphnyVzb308OG2QJjgS/smQxKHoWXb2euP4v6kVI0oWIkHPy6ZVcVH45RToLTv0443OZUZXIQ7+UDMPUeRxRfagEzq2zVgryueasfvBT8KTTU5zCtag1VAZwtRDKksh8xnRYtreb7kw7WV6t3uIZ4156/gbGVC0QZtIDs3GlHncInw2rfOzIGpS1Ze363kiBrgZ/28+mU4yD/qEsQ9klxbHG/Shp+J++BMxqB2d7vL6D+uEJ/N7sPFbSnxoM6B5KOtdspVvARfTlq1/fYYffcxG1O47sF4o3YCR3XmOkFU40KHvBC2qvQzJMtL/N1c6CMHtTXqhnjoFfUkzLZ/yc9Ue55+vzcK8UIx3/AY/eq8Q=) 143 | 144 | ## Teleport 145 | 146 | The `` component in Vue.js allows you to render a component's HTML in a different part of the DOM than where the component is declared. 147 | 148 | ```vue 149 | 150 | 154 | 155 | ``` 156 | 157 | ## Suspense 158 | 159 | `` is a built-in component for orchestrating async dependencies in a component tree. It can render a `loading state` while waiting for multiple nested async dependencies down the component tree to be resolved. 160 | 161 | ```vue 162 | 173 | ``` 174 | 175 | ### Combining Suspense with other components 176 | 177 | ```vue 178 | 197 | ``` 198 | -------------------------------------------------------------------------------- /content/vue/component.md: -------------------------------------------------------------------------------- 1 | # Component 2 | 3 | ## Register Component 4 | 5 | ### Global Registration 6 | 7 | ```ts 8 | import MyComponent from './MyComponent.vue' 9 | 10 | app.component('MyComponent', MyComponent) 11 | 12 | // We can chain component method 13 | app 14 | .component('ComponentA', ComponentA) 15 | .component('ComponentB', ComponentB) 16 | .component('ComponentC', ComponentC) 17 | ``` 18 | 19 | Now `MyComponent` is globally available. We can use it in any component like below: 20 | 21 | ```vue 22 | 23 | ``` 24 | 25 | ### Local Registration 26 | 27 | ```vue 28 | 31 | 32 | 35 | ``` 36 | 37 | ## Defining a Component 38 | 39 | ### 1. SFC 40 | 41 | ```vue 42 | 47 | 48 | 51 | ``` 52 | 53 | ### 2. `defineComponent` 54 | 55 | ```ts 56 | import { ref, h, defineComponent } from 'vue' 57 | 58 | const Comp = defineComponent( 59 | (props) => { 60 | 61 | return () => { 62 | return h('div', props.title) 63 | } 64 | }, 65 | { 66 | props: { 67 | title: String, 68 | } 69 | } 70 | ) 71 | 72 | export default Comp 73 | ``` 74 | 75 | ### 3. `defineAsyncComponent` 76 | 77 | ```ts 78 | defineAsyncComponent(() => import('@/components/TestCompo.vue')); 79 | ``` 80 | 81 | ### 4. Using tsx 82 | 83 | ```vue 84 | 89 | 90 | 93 | 94 | ``` 95 | 96 | ::: warning Warning 97 | If using Vite - you need `@vitejs/plugin-vue-jsx` for this 98 | ::: 99 | 100 | ## Props 101 | 102 | ### Defining Props 103 | 104 | ```vue 105 | 128 | ``` 129 | 130 | ### Prop Validation 131 | 132 | We can validate prop using its types, required parameter, validator function. We can also pass default value to the prop. 133 | 134 | ```ts 135 | defineProps({ 136 | // Basic type check 137 | // (`null` and `undefined` values will allow any type) 138 | propA: Number, 139 | 140 | // Multiple possible types 141 | propB: [String, Number], 142 | 143 | // Required string 144 | propC: { 145 | type: String, 146 | required: true 147 | }, 148 | 149 | // Number with a default value 150 | propD: { 151 | type: Number, 152 | default: 100 153 | }, 154 | 155 | // Object with a default value 156 | propE: { 157 | type: Object, 158 | // Object or array defaults must be returned from 159 | // a factory function. The function receives the raw 160 | // props received by the component as the argument. 161 | default(rawProps) { 162 | return { message: 'hello' } 163 | } 164 | }, 165 | 166 | // Custom validator function 167 | // All props passed as 2nd argument in 3.4+ 168 | propF: { 169 | validator(value, props) { 170 | // The value must match one of these strings 171 | return ['success', 'warning', 'danger'].includes(value) 172 | } 173 | }, 174 | 175 | // Function with a default value 176 | propG: { 177 | type: Function, 178 | // Unlike object or array default, this is not a factory 179 | // function - this is a function to serve as a default value 180 | default() { 181 | return 'Default function' 182 | } 183 | }, 184 | 185 | // If you don't pass value to prop by default it will take false. 186 | propH: Boolean, 187 | 188 | // Change the default behavior of Boolean type prop. 189 | propI: { 190 | type: Boolean, 191 | default: undefined, 192 | }, 193 | 194 | }) 195 | ``` 196 | 197 | ### Binding Props 198 | 199 | ```vue 200 | 211 | 212 | 230 | ``` 231 | 232 | ### Two Way binding 233 | 234 | ```vue 235 | 239 | 240 | 243 | ``` 244 | 245 | ```vue 246 | 257 | 258 | 262 | 263 | ``` 264 | 265 | ```vue 266 | 277 | 278 | 281 | ``` 282 | 283 | ## Events 284 | 285 | ### Declaring events 286 | 287 | ```vue 288 | 298 | ``` 299 | 300 | ### Using Events 301 | 302 | ```vue 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | ``` 315 | 316 | ### Event Validation 317 | 318 | ```vue 319 | 339 | ``` 340 | 341 | ## Slots 342 | 343 | ```vue 344 | 402 | ``` 403 | 404 | ## Provide & Inject 405 | 406 | ![Provide and Inject](https://vuejs.org/assets/provide-inject.tIACH1Z-.png) 407 | 408 | ::: code-group 409 | 410 | ```vue{2,8} [Parent.vue] 411 | 420 | 421 | 425 | ``` 426 | 427 | ```vue [Child.vue] 428 | 431 | 432 | 435 | ``` 436 | 437 | ```vue{2,4} [GrandChild.vue ] 438 | 443 | 444 | 449 | ``` 450 | 451 | ::: 452 | -------------------------------------------------------------------------------- /content/vue/composable.md: -------------------------------------------------------------------------------- 1 | # Composable 2 | 3 | A composable is a function that leverages Vue's Composition API to encapsulate and reuse stateful logic. 4 | 5 | ```ts 6 | // mouse.ts 7 | import { ref, onMounted, onUnmounted } from 'vue' 8 | 9 | // by convention, composable function names start with "use" 10 | export function useMouse() { 11 | // state encapsulated and managed by the composable 12 | const x = ref(0) 13 | const y = ref(0) 14 | 15 | // a composable can update its managed state over time. 16 | function update(event) { 17 | x.value = event.pageX 18 | y.value = event.pageY 19 | } 20 | 21 | // a composable can also hook into its owner component's 22 | // lifecycle to setup and teardown side effects. 23 | onMounted(() => window.addEventListener('mousemove', update)) 24 | onUnmounted(() => window.removeEventListener('mousemove', update)) 25 | 26 | // expose managed state as return value 27 | return { x, y } 28 | } 29 | ``` 30 | 31 | ## Convention & Best Practices 32 | 33 | ### Naming 34 | 35 | It is a convention to name composable functions with camelCase names that start with `use`. 36 | 37 | Example: `useMouse()` 38 | 39 | ### Input Arguments 40 | 41 | ```ts 42 | import { toValue } from 'vue' 43 | 44 | function useFeature(maybeRefOrGetter) { 45 | // If maybeRefOrGetter is a ref or a getter, 46 | // its normalized value will be returned. 47 | // Otherwise, it is returned as-is. 48 | const value = toValue(maybeRefOrGetter) 49 | } 50 | ``` 51 | 52 | ### Return values 53 | 54 | ```ts 55 | // x and y are refs 56 | const { x, y } = useMouse() 57 | ``` 58 | -------------------------------------------------------------------------------- /content/vue/forms.md: -------------------------------------------------------------------------------- 1 | # Form Input Bindings 2 | 3 | ## Basic form input 4 | 5 | ```vue 6 | 49 | ``` 50 | 51 | [Try it in the Playground](https://play.vuejs.org/#eNq9VUtP4zAQ/iveXLorUcoutypEAsQBJB4CbmQPaTKlBse2bKeAqvz3nbHzRAW6Fy5tZuabxzf2jDfRsdb76wqieRTb3HDtmAVX6SSVvNTKOLZhBpasZkujSjZB6CSVqcyVtI45eHXsiAA/J2cFd6yEya/WmK8gf4aisTtTwXvTVVaCbewPk4ssf5787TCaD7wn13IQ2YKA3PXG495UVsLxu7H9AQEUN54FhsgNBQelFpkDlBiLV3+SeyJzLnXl4hmKXs1JZOtpqQoQR2lEhNMoYZtN4F7XFCv4nxKphXp97+3eNKCr54zmNGK8GMt9/KYxmMIHENkCBFsqM8KHTFDMqYy2y3Udzzzcs0PfH9Mp/bPQEi0gQDEC9jzPJFtwWTCnmFsBs3gSAZ0Zk721FbF1JipvmE67Pl1SPPafbJ/wcIkpxUORznobcX8jtrEP/gn59Ty/TKpWcpi0EXdP6h0S8ts9acmfYZD0shF3Thr8E/IbJdXtsTNJrnPUGEj6GxCGia4B6fG3vQh4PrdZwdUHJ2XI1hav5LB2HLpR6WEktxXt/RLEj0pemK/yuRf6bPPdB2mHfN4vQfzWfFZnMrnxzn5GmlVCvfGmvjFhU/SdCZtlUEK7apoiEKK040qygttsITBqWzwibgRkFocpBMGexLOAHvsmxx/oTz7Qn470SMInGHBtF55n223HLXzD7H7JerRF8Ui6FWLdmyCyL7xwq/nvgwNN++g72Y0X/IBiPOs2erQXOYvvwZI/7j9ZJfFx21A4HD5Vai7AXPuEOH8YM1STRpkQ6uXC6+ix2mv1fr626J8scp/jx40BC2aNE9DZXGYeAV8KMp/dXflXozNilyuB6E+Mt2CVqKjGADupZIFlD3C+2nP/RHP5eG/PXh1I25KiQglZe3wa4bN9+gn1vtzD/UPvl8o6qv8BvGa6DQ==) 52 | -------------------------------------------------------------------------------- /content/vue/reactivity.md: -------------------------------------------------------------------------------- 1 | # Reactivity 2 | 3 | ## `ref()` 4 | 5 | A ref will make its value deeply reactive. This means you can expect changes to be detected even when you mutate nested objects or arrays. 6 | 7 | ```ts 8 | const count = ref(0); 9 | 10 | console.log(count.value); // 0 11 | 12 | count.value = 10; // Will update the DOM as well 13 | 14 | console.log(count.value); // 10 15 | ``` 16 | 17 | ## `reactive()` 18 | 19 | Unlike a ref which wraps the inner value in a special object, reactive() makes an object itself reactive. 20 | 21 | ```ts 22 | const state = reactive({ count: 1 }); 23 | 24 | console.log(state); // {count: 1} 25 | console.log(state.count); // 1 26 | ``` 27 | 28 | ## `shallowRef()` 29 | 30 | The inner value of a `shallowRef` is stored and exposed as-is, and will not be made deeply reactive 31 | 32 | ```ts 33 | const state = shallowRef({ count: 1 }) 34 | 35 | // does NOT trigger change 36 | state.value.count = 2 37 | 38 | // does trigger change 39 | state.value = { count: 2 } 40 | ``` 41 | 42 | ## Computed Property 43 | 44 | ```vue 45 | 50 | 51 | 57 | ``` 58 | 59 | ## Class and Style Bindings 60 | 61 | ```vue{21-24,27,30,33,36} 62 | 79 | 80 | 102 | 103 | 109 | ``` 110 | 111 | ::: tip 112 | When a `