├── .editorconfig ├── .eslintrc.cjs ├── .github └── workflows │ ├── textlint.yaml │ └── vitepress.yml ├── .gitignore ├── .prettierrc.js ├── .textlintrc ├── .vscode ├── extensions.json └── settings.json ├── GUIDE.md ├── LICENSE ├── README.md ├── docs ├── .gitignore ├── .vitepress │ ├── components │ │ └── PlusOne.vue │ ├── config.ts │ └── theme │ │ └── index.ts ├── component.md ├── create.md ├── event.md ├── images │ ├── favicon-32.png │ ├── sample.png │ ├── v_for_result1.png │ ├── v_for_result2.png │ ├── vite-app.png │ └── vscode.png ├── index.md ├── methods.md ├── overview.md ├── package-lock.json ├── package.json ├── public │ └── vue3-lab-handson-images.zip ├── rendering.md ├── setup.md ├── slot.md ├── v-for.md └── v-if.md ├── examples ├── component │ ├── index.html │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── images │ │ │ ├── item1.jpg │ │ │ ├── item2.jpg │ │ │ ├── item3.jpg │ │ │ ├── item4.jpg │ │ │ └── logo.svg │ ├── src │ │ ├── App.vue │ │ ├── components │ │ │ └── Card.vue │ │ └── main.js │ └── vite.config.js ├── event │ ├── index.html │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── images │ │ │ ├── item1.jpg │ │ │ ├── item2.jpg │ │ │ ├── item3.jpg │ │ │ ├── item4.jpg │ │ │ └── logo.svg │ ├── src │ │ ├── App.vue │ │ └── main.js │ └── vite.config.js ├── methods │ ├── index.html │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── images │ │ │ ├── item1.jpg │ │ │ ├── item2.jpg │ │ │ ├── item3.jpg │ │ │ ├── item4.jpg │ │ │ └── logo.svg │ ├── src │ │ ├── App.vue │ │ └── main.js │ └── vite.config.js ├── overview │ ├── index.html │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── images │ │ │ ├── item1.jpg │ │ │ ├── item2.jpg │ │ │ ├── item3.jpg │ │ │ ├── item4.jpg │ │ │ └── logo.svg │ ├── src │ │ ├── App.vue │ │ ├── assets │ │ │ ├── base.css │ │ │ ├── logo.svg │ │ │ └── main.css │ │ ├── components │ │ │ ├── HelloWorld.vue │ │ │ ├── TheWelcome.vue │ │ │ ├── WelcomeItem.vue │ │ │ └── icons │ │ │ │ ├── IconCommunity.vue │ │ │ │ ├── IconDocumentation.vue │ │ │ │ ├── IconEcosystem.vue │ │ │ │ ├── IconSupport.vue │ │ │ │ └── IconTooling.vue │ │ └── main.js │ ├── style.css │ └── vite.config.js ├── rendering │ ├── index.html │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── images │ │ │ ├── item1.jpg │ │ │ ├── item2.jpg │ │ │ ├── item3.jpg │ │ │ ├── item4.jpg │ │ │ └── logo.svg │ ├── src │ │ ├── App.vue │ │ └── main.js │ └── vite.config.js ├── slot │ ├── index.html │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── images │ │ │ ├── item1.jpg │ │ │ ├── item2.jpg │ │ │ ├── item3.jpg │ │ │ ├── item4.jpg │ │ │ └── logo.svg │ ├── src │ │ ├── App.vue │ │ ├── components │ │ │ └── Card.vue │ │ └── main.js │ └── vite.config.js ├── v-for │ ├── index.html │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── images │ │ │ ├── item1.jpg │ │ │ ├── item2.jpg │ │ │ ├── item3.jpg │ │ │ ├── item4.jpg │ │ │ └── logo.svg │ ├── src │ │ ├── App.vue │ │ └── main.js │ └── vite.config.js └── v-if │ ├── index.html │ ├── package.json │ ├── public │ ├── favicon.ico │ └── images │ │ ├── item1.jpg │ │ ├── item2.jpg │ │ ├── item3.jpg │ │ ├── item4.jpg │ │ └── logo.svg │ ├── src │ ├── App.vue │ └── main.js │ └── vite.config.js ├── index.html ├── package-lock.json ├── package.json ├── public ├── favicon.ico └── images │ ├── item1.jpg │ ├── item2.jpg │ ├── item3.jpg │ ├── item4.jpg │ └── logo.svg ├── src ├── App.vue ├── components │ └── Card.vue └── main.js └── vite.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 2 6 | indent_style = space 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | require('@rushstack/eslint-patch/modern-module-resolution') 2 | 3 | module.exports = { 4 | root: true, 5 | env: { 6 | node: true, 7 | 'vue/setup-compiler-macros': true 8 | }, 9 | extends: [ 10 | 'plugin:vue/vue3-recommended', 11 | 'eslint:recommended', 12 | '@vue/eslint-config-prettier' 13 | ], 14 | rules: { 15 | 'vue/html-closing-bracket-newline': [ 16 | 'error', 17 | { 18 | singleline: 'never', 19 | multiline: 'never' 20 | } 21 | ], 22 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 23 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 24 | 'prettier/prettier': 'off' // eslint-plugin-prettierの部分だけoffにする 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/textlint.yaml: -------------------------------------------------------------------------------- 1 | name: textlint 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | env: 12 | NODE_VERSION: '16.x' 13 | 14 | jobs: 15 | textlint: 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | - uses: actions/setup-node@v2 21 | with: 22 | node-version: ${{ env.NODE_VERSION }} 23 | cache: npm 24 | - name: Restore Packages 25 | run: npm ci 26 | - name: Run textlint 27 | run: npm run textlint:docs 28 | -------------------------------------------------------------------------------- /.github/workflows/vitepress.yml: -------------------------------------------------------------------------------- 1 | name: VitePress CI/CD 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - '.github/workflows/vitepress.yml' 9 | - 'docs/**' 10 | pull_request: 11 | branches: 12 | - main 13 | paths: 14 | - '.github/workflows/vitepress.yml' 15 | - 'docs/**' 16 | workflow_dispatch: 17 | 18 | permissions: 19 | pages: write 20 | id-token: write 21 | 22 | concurrency: 23 | group: "pages" 24 | cancel-in-progress: false 25 | 26 | jobs: 27 | build: 28 | if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') 29 | runs-on: ubuntu-latest 30 | defaults: 31 | run: 32 | working-directory: docs 33 | steps: 34 | - uses: actions/checkout@v3 35 | - name: Use Node.js 36 | uses: actions/setup-node@v3 37 | with: 38 | node-version: '18.x' 39 | cache: 'npm' 40 | cache-dependency-path: docs/package-lock.json 41 | - run: npm ci 42 | - run: npm run build --if-present 43 | - run: echo 'handson.vuejs-jp.org' > CNAME 44 | working-directory: docs/.vitepress/dist 45 | - uses: actions/upload-artifact@v3 46 | with: 47 | name: dist 48 | path: docs/.vitepress/dist 49 | 50 | deploy: 51 | if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' # PR 時はデプロイを実行しない 52 | runs-on: ubuntu-latest 53 | needs: build 54 | 55 | environment: 56 | name: github-pages 57 | url: ${{ steps.deployment.outputs.page_url }} 58 | 59 | steps: 60 | - uses: actions/download-artifact@v3 61 | with: 62 | name: dist 63 | - uses: actions/upload-pages-artifact@v1 64 | with: 65 | path: . 66 | - name: Deploy to GitHub Pages 67 | id: deployment 68 | uses: actions/deploy-pages@v1 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /docs/dist 5 | 6 | 7 | # local env files 8 | .env.local 9 | .env.*.local 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | pnpm-debug.log* 16 | 17 | # Editor directories and files 18 | .idea 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | singleQuote: true, 3 | semi: false, 4 | trailingComma: 'none' 5 | } 6 | -------------------------------------------------------------------------------- /.textlintrc: -------------------------------------------------------------------------------- 1 | { 2 | "filters": { 3 | "allowlist": { 4 | "allow": [ 5 | "/<< ` でリンクを表現します。 22 | ```md 23 | 本文があります。 24 | 25 | > [String() に関する詳細](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/String) 26 | 27 | 本文があります。 28 | ``` 29 | 30 | ## 外部リンク先について 31 | - 原則として、リンク先は公式ドキュメントとします 32 | - 例えば、Vue.js 本体に関しては Vue.js 公式ドキュメント([V3](https://v3.ja.vuejs.org/guide/introduction.html) 、 [V2](https://jp.vuejs.org/v2/guide/))にリンクします 33 | - HTML、CSS、JavaScript の仕様に関しては [MDN Web Docs](https://developer.mozilla.org/ja/docs/Web) にリンクします 34 | 35 | ## 改行について 36 | マークダウンでは、原則では改行されないためひとつの文章内では改行させない。改行したい場合は明示的に空行を入れて改行させるようにする 37 | 38 | ## 文章の校正( textlint )について 39 | 40 | ドキュメントは、 [textlint](https://github.com/textlint/textlint) を使って校正を行います。校正のチェックルールは、Vue.js 日本ユーザーグループが翻訳プロジェクト等で利用している [プリセット](https://github.com/vuejs-jp/textlint-rule-preset-vuejs-jp) を参照しています。 41 | 42 | ### Pull Request 時の自動チェック 43 | 44 | Pull Request を発行すると、GitHub Actions によって自動的に textlint によるルール評価が行われます。ルールに合わない問題が見つかった場合は、Pull Request のステータスチェックがエラー表示になるので、対応する PR の `Checks` タブで GitHub Actions のログから `Run textlint` の詳細を展開してエラー内容を確認してください。 45 | 46 | ### ローカルでのチェック方法 47 | 48 | Pull Request で textlint のエラーが出た場合や、PR 前に事前にチェックをしたい場合は、ローカルで以下のコマンドを実行して確認することができます。 49 | 50 | ```bash 51 | npm run textlint {チェックしたいファイル名} 52 | ``` 53 | 54 | エラーが無い場合は何も表示されませんが、エラーが見つかった場合はログに問題の箇所と内容が表示されるので、ログに従って修正してください。 55 | 56 | ```bash 57 | ✓ vuejs-jp/ja-space-between-half-and-full-width: 原則として、全角文字と半角文字の間にスペースを入れます。 58 | /Users/miyake/repos/handson-vue3-examples/GUIDE.md:45:22 59 | v 60 | 44. 61 | 45. Pull Request でtextlintのエラーが出た場合や、PR 前に事前にチェックをしたい場合は、ローカルで以下のコマンドを実行して確認することができます。 62 | 46. 63 | ``` 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Vue.js Japan User Group 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.js 3 ハンズオン 2 | 3 | [![MIT License](https://img.shields.io/apm/l/atomic-design-ui.svg?)](https://github.com/tterb/atomic-design-ui/blob/master/LICENSEs) 4 | 5 | Vue.js 3 ハンズオンへようこそ😀 このハンズオンは、初めて Vue.js に触れる人がスムーズに学習できるように作られた学習用教材です。この教材は、以下の2通りの方法でご利用いただけます。 6 | 7 | ## ✏利用方法 8 | ### 1. Vue.js 日本ユーザーグループの公式ハンズオンに参加する 9 | 本ハンズオンを作成した [Vue.js 日本ユーザーグループ](https://vuejs-jp.org/) では、定期的にこの教材を使ったハンズオンイベントの開催を予定しています。ハンズオンイベントは誰でも自由に参加できます。イベントの予定は [connpass](https://vuejs-meetup.connpass.com/event/) に掲載していますので、ぜひチェックしてください。 10 | 11 | ### 2. 自由に利用する 12 | 本ハンズオンの文章、ソースコードを含むあらゆる内容は、自由にご利用いただけます。個人の学習や、グループ・会社での勉強会、もくもく会、セミナーなど、あらゆる用途にご活用ください。 13 | 14 | ## 💪コントリビューター 15 | 誤りやよりよい改善を見つけた方は、[Issues](https://github.com/vuejs-jp/handson-vue3-examples/issues) または [Pull requests](https://github.com/vuejs-jp/handson-vue3-examples/pulls) を作成してください。 16 | 17 | - [MIYAKE Kazuyuki](https://github.com/k-miyake) 18 | - [NAKATA Kazuhiro](https://github.com/nalpan) 19 | - [ISHIBASHI Yuuki](https://github.com/YuukiIshibashi) 20 | - [happylifetaka](https://github.com/happylifetaka) 21 | - [OKI Yoshiya](https://github.com/448jp) 22 | - [KAWAGUCHI Kazuya](https://github.com/kazupon) 23 | - Photo by Tyler Nix, matthew reyes, Amy Flak, Elena Rabkina on Unsplash 24 | 25 | ## ©ライセンス 26 | [MIT](https://opensource.org/licenses/MIT) 27 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | 4 | # vitepress build output 5 | .vitepress/dist 6 | .vitepress/cache 7 | -------------------------------------------------------------------------------- /docs/.vitepress/components/PlusOne.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 22 | 23 | 56 | -------------------------------------------------------------------------------- /docs/.vitepress/config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress' 2 | 3 | export default defineConfig({ 4 | lang: 'ja-JP', 5 | title: 'Vue3 Hands-on', 6 | description: 'Vue.js-jp Vue3 Hands-on', 7 | head: [['link', { rel: 'icon', href: '/images/favicon-32.png' }]], 8 | themeConfig: { 9 | siteTitle: 'Vue3 ハンズオン', 10 | sidebar: [ 11 | { 12 | text: '準備編', 13 | items: [ 14 | { 15 | text: '環境構築', 16 | link: '/setup' 17 | }, 18 | { 19 | text: 'プロジェクトの作成', 20 | link: '/create' 21 | } 22 | ] 23 | }, 24 | { 25 | text: '本編', 26 | items: [ 27 | { 28 | text: 'ハンズオンの概要', 29 | link: '/overview' 30 | }, 31 | { 32 | text: 'data を定義し、商品をレンダリングする', 33 | link: '/rendering' 34 | }, 35 | { 36 | text: 'v-for で商品を複数表示する', 37 | link: '/v-for' 38 | }, 39 | { 40 | text: 'v-if で表示・非表示を切り替える', 41 | link: '/v-if' 42 | }, 43 | { 44 | text: '関数で価格にカンマを入れる', 45 | link: '/methods' 46 | }, 47 | { 48 | text: '@click で商品を選択する', 49 | link: '/event' 50 | }, 51 | { 52 | text: '商品をコンポーネント化する', 53 | link: '/component' 54 | }, 55 | { 56 | text: 'コンポーネントにスロットを使用する', 57 | link: '/slot' 58 | } 59 | ] 60 | } 61 | ] 62 | } 63 | }) 64 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import Theme from 'vitepress/theme' 2 | import PlusOne from '../components/PlusOne.vue' 3 | 4 | export default { 5 | ...Theme, 6 | 7 | enhanceApp({ app }) { 8 | app.component('PlusOne', PlusOne) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /docs/component.md: -------------------------------------------------------------------------------- 1 | # 商品をコンポーネント化する 2 | 3 | ## 本章の概要とゴール 4 | 本章では、1 つ 1 つの商品を表示するコードをコンポーネントとして分離し、再利用できるようにプログラムを改修していきます。 5 | 本章を実践すると、プログラムの一部を再利用できるコンポーネントとして切り出したり、 `props` を使ってコンポーネントに必要な情報を渡すことができるようになります。 6 | 7 | ## コンポーネントとは 8 | 9 | Vue.js ではテンプレート、ロジック、そしてスタイルを 1 つのファイルにまとめることで、単一ファイルコンポーネント(`Single File Components`、略称 `SFC`)として利用することができます。`SFC` は ` 15 | 16 | 19 | ``` 20 | 21 | 現在は商品を表示しているだけですが、ヘッダーの情報が増えたり、フッターなどのコンテンツを足していくと `template` のコードはどんどん肥大化していきます。それだけでなく、例えば商品に複数写真を表示、個数によって表示金額の変更、といった機能を追加していくと `script` のコードも肥大化していきます。肥大化するとコードの見通しも悪くなり、メンテナンスも大変になってきます。そのような状況に陥らないために、商品をコンポーネントに変更してみましょう。 22 | 23 | ### 前回までのコードの確認 24 | 25 | 現在のコードは以下のようになっています。 26 | 27 | #### template 28 | 29 | <<< @/../examples/event/src/App.vue#template 30 | 31 | #### script 32 | 33 | <<< @/../examples/event/src/App.vue#script 34 | 35 | ## 一部をモジュールとして切り出す 36 | モジュールとして切り出す時、どの範囲で切り出すか迷うかもしれません。そのような場合は、再利用可能という観点で考えてみてもよいかもしれません。今回の場合、商品の部分は、`v-for` の中で何度も呼ばれているので、この範囲で切り出してみるのが良さそうです。 37 | 38 | ### コンポーネントの作成 39 | 40 | `Card` コンポーネントとして切り出しますが、`src` ディレクトリの下に新たに `components` ディレクトリを作成し、そこに `Card.vue` ファイルを作成します。今後コンポーネントを新たに作っていく場合は、`components` ディレクトリに格納していくとよいでしょう。作成後は下記のようなディレクトリ構成になっていると思います。 41 | 42 | ``` 43 | src 44 | ┣━ components 45 | ┃ ┗━ Card.vue 46 | ┣━ App.vue 47 | ┗━ main.js 48 | ``` 49 | 50 | 次にいよいよモジュールを切り出す作業に入ります。以下のハイライト部分を `Card.vue` に移します。また、`pricePrefix()` や関連する `style` も一緒に移します。 51 | 52 | #### template 53 | 54 | <<< @/../examples/event/src/App.vue#template{17-26} 55 | 56 | #### script 57 | 58 | <<< @/../examples/event/src/App.vue#script{47-53} 59 | 60 | #### style 61 | 62 | <<< @/../examples/event/src/App.vue#style{54-82} 63 | 64 | 移し替えて出来上がった `Card.vue` は下記のようになります。 65 | 66 | #### Card.vue 67 | 68 | ```vue 69 | 78 | 79 | 91 | 92 | 118 | ``` 119 | 120 | ## Card コンポーネントを使用する 121 | 切り出しができたので、作成したコンポーネントを `App.vue` で使えるようにしましょう。 122 | 123 | #### App.vue / template 124 | 125 | ```vue{14} 126 | 144 | ``` 145 | 146 | #### App.vue / script 147 | 148 | ```vue{3} 149 | 156 | ``` 157 | 158 | `Card` コンポーネントを `import` して、`template` 内で呼び出しています。しかし現状エラーがでて動きません。作成した `Card` コンポーネントは `item` のデータを持っていないためです。そのため、`Card` コンポーネントでも `item` のデータを使えるように、親のコンポーネント(`App.vue`)から `props` として渡す必要があります。 159 | 160 | ### 親のコンポーネント( App.vue )から値を受け取る準備をする 161 | 162 | まず必要なデータを受け取るために準備をします。 163 | 164 | 現在 `item` オブジェクト内のデータを参照していますが、 シンプルに必要な値のみを受け取り、表示するようにするために、コードを書き換えます。 165 | 166 | #### Card.vue / template 167 | 168 | ```vue{4,8-10} 169 | 181 | ``` 182 | 183 | 次に親のコンポーネントから `props` を受け取る設定を記述します。 184 | 185 | #### Card.vue / script 186 | 187 | ```vue{2-23} 188 | 215 | ``` 216 | 217 | `defineProps` の中に受け取る `props` を書いていきます。`type` は型、`default` は初期値、`required` は必須要素を表しています。 218 | 219 | ::: tip ヒント 220 | `defineProps` とこのあと紹介する `defineEmits` は ` 301 | ``` 302 | 303 | ` 316 | ``` 317 | 318 | 次に `template` に売り切れのボタンを作成します。 319 | 320 | ```vue{5} 321 | 327 | ``` 328 | 329 | 売り切れのボタンをクリックすると `defineEmits` を実行します。 330 | 331 | ### App.vue で実行する関数を定義 332 | 333 | `Card` コンポーネントからの `emits` を受け取り、実行される関数を定義していきます。 334 | 335 | ```vue{7} 336 | 343 | ``` 344 | 345 | `Card` コンポーネントには `sold-out` の `emits` を受け取った場合に `changeSoldOut` が実行されるように設定しました。次に、実行される `changeSoldOut` を定義します。 346 | 347 | ```vue{5-8} 348 | 357 | ``` 358 | 359 | 子のコンポーネントの売り切れのボタンをクリックすると、該当の `soldOut` プロパティを変更し、商品を非表示にすることができました。 360 | -------------------------------------------------------------------------------- /docs/create.md: -------------------------------------------------------------------------------- 1 | # プロジェクトの作成 2 | 3 | ## create-vue でのプロジェクト新規作成 4 | 5 | [create-vue](https://github.com/vuejs/create-vue) を使って生成されるアプリケーションをプロジェクトと呼びます。ここではプロジェクトを新しく作成してみましょう。 6 | 7 | 1. アプリケーションを作成するディレクトリを決めておきます(この例では `vue3-lab` としています)。`create-vue` でプロジェクトを作成すると、決めたディレクトリの配下にファイル群が生成されます。 8 | 9 | 2. ターミナルで、プロジェクトのディレクトリを作成する親ディレクトリに移動します。もし、ホームディレクトリの直下にプロジェクトを作成するのであれば、ターミナルで以下のコマンドを使って移動しておきます。 10 | 11 | ```sh 12 | cd ~ 13 | ``` 14 | 15 | ::: tip ヒント 16 | ホームディレクトリとは、ユーザー固有のファイルやフォルダを保存できる領域であり、通常ユーザー名でディレクトリが作成されています。 17 | ::: 18 | 19 | 3. `create-vue` でプロジェクトを新規作成します。ターミナルで以下のコマンドを実行します(コマンド実行後はそのまま待機しておいてください)。プロジェクトのディレクトリは `create-vue` によって自動的に作成されます。 20 | 21 | ```sh 22 | npm create vue@latest vue3-lab 23 | ``` 24 | 25 | 4. コマンドを実行すると、ターミナルにいくつかの質問が表示されます。このハンズオンでは以下のように選択します。 26 | 27 | 下記のメッセージが表示された場合は `y` と入力して `enter / return` キーを押します。 28 | ``` 29 | Need to install the following packages: 30 | create-vue@latest 31 | Ok to proceed? (y) -> y 32 | ``` 33 | 34 | 以降の質問には、基本的に `No` を選択して進めます。 35 | 36 | ::: tip ヒント 37 | 矢印キーでアンダースコアを移動させることで項目を選択します。 38 | enter / return キーで項目を確定できます。 39 | ::: 40 | 41 | ``` 42 | Vue.js - The Progressive JavaScript Framework 43 | ? Add TypeScript? › No / Yes -> No 44 | ? Add JSX Support? › No / Yes -> No 45 | ? Add Vue Router for Single Page Application development? › No / Yes -> No 46 | ? Add Pinia for state management? › No / Yes -> No 47 | ? Add Vitest for Unit Testing? › No / Yes -> No 48 | ? Add an End-to-End Testing Solution? › - Use arrow-keys. Return to submit. 49 | ❯ No 50 | Cypress 51 | Nightwatch 52 | Playwright 53 | -> No 54 | ? Add ESLint for code quality? › No / Yes -> No 55 | ``` 56 | 57 | ## プロジェクトの起動 58 | 59 | 作成したプロジェクトを起動してみましょう。プロジェクトの起動には外部パッケージをインストールしてから起動コマンドを実行します。 60 | 61 | 1. 作成したプロジェクトのディレクトリに移動し(この例では `vue3-lab`)、`npm install` で外部パッケージをインストールします。 62 | 63 | ```sh 64 | cd vue3-lab 65 | npm install 66 | ``` 67 | 68 | 2. `npm install` の処理が完了したら `npm run dev` でプロジェクトを起動します。 69 | 70 | ```sh 71 | npm run dev 72 | ``` 73 | 74 | 3. `npm run dev` の実行が完了したら、ブラウザで `http://localhost:5173/` にアクセスします。 75 | 76 | 4. ブラウザに「You did it!」等と表示されていれば、無事にプロジェクトの作成が成功しています。 77 | 78 | ## プロジェクトの確認 79 | 80 | プロジェクト新規作成後、以下のようなディレクトリ構造になります。 81 | 82 | ``` 83 | vue3-lab 84 | ├── README.md 85 | ├── index.html 86 | ├── node_modules 87 | ├── package-lock.json 88 | ├── package.json 89 | ├── public 90 | │   └── favicon.ico 91 | ├── src 92 | │   ├── App.vue 93 | │   ├── assets 94 | │   │   ├── base.css 95 | │   │   ├── logo.svg 96 | │   │   └── main.css 97 | │   ├── components 98 | │   │   ├── HelloWorld.vue 99 | │   │   ├── TheWelcome.vue 100 | │   │   ├── WelcomeItem.vue 101 | │   │   └── icons 102 | │   │   ├── IconCommunity.vue 103 | │   │   ├── IconDocumentation.vue 104 | │   │   ├── IconEcosystem.vue 105 | │   │   ├── IconSupport.vue 106 | │   │   └── IconTooling.vue 107 | │   └── main.js 108 | └── vite.config.js 109 | 110 | 6 directories, 19 files 111 | ``` 112 | 113 | これらのファイルが `create-vue` で作成されます。 114 | 115 | ![Vite App](./images/vite-app.png) 116 | -------------------------------------------------------------------------------- /docs/event.md: -------------------------------------------------------------------------------- 1 | # @click で商品を選択する 2 | 3 | ## 本章の概要とゴール 4 | 本章では、クリックイベントを定義して購入する商品をクリックで選択できるようにプログラムを改修していきます。商品をクリックすると選択中となり、選択中の商品は背景の色は変わるようにします。 5 | 本章を実践すると、`v-on` ディレクティブを使ってイベントリスナーの登録ができるようになります。 6 | また、`v-bind` ディレクティブを使って選択中かそうでないかを判断して、動的に style を変化させることができるようになります。 7 | 8 | ### 実装の考え方 9 | 10 | どのように実装していけば良いか 1 つずつ分解して考えてみると、以下のようになります。 11 | 12 | 1. 選択状態を表す style を用意する 13 | 2. クリックすると商品を"選択状態"にする 14 | 3. "選択状態"の時にだけ、1 の style を適用する 15 | 16 | 1 つ 1 つの処理は難しくありません。順番に実装してみましょう。 17 | 18 | ### 前回までのコードの確認 19 | 20 | 現在のコードは以下のようになっています。 21 | 22 | template 23 | 24 | <<< @/../examples/methods/src/App.vue#template 25 | 26 | script 27 | 28 | <<< @/../examples/methods/src/App.vue#script 29 | 30 | ## 1. 選択状態を表す style を用意する 31 | 32 | まず、選択中の商品に適用する style を用意しましょう。` 140 | // endregion style 141 | -------------------------------------------------------------------------------- /examples/component/src/components/Card.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 46 | 47 | 77 | -------------------------------------------------------------------------------- /examples/component/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /examples/component/vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | plugins: [vue()], 9 | resolve: { 10 | alias: { 11 | '@': fileURLToPath(new URL('./src', import.meta.url)) 12 | } 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /examples/event/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | handson-vue3-examples 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/event/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "event", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview --port 4173" 9 | }, 10 | "dependencies": { 11 | "vue": "^3.2.37" 12 | }, 13 | "devDependencies": { 14 | "@vitejs/plugin-vue": "^3.0.1", 15 | "vite": "^3.0.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/event/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/event/public/favicon.ico -------------------------------------------------------------------------------- /examples/event/public/images/item1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/event/public/images/item1.jpg -------------------------------------------------------------------------------- /examples/event/public/images/item2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/event/public/images/item2.jpg -------------------------------------------------------------------------------- /examples/event/public/images/item3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/event/public/images/item3.jpg -------------------------------------------------------------------------------- /examples/event/public/images/item4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/event/public/images/item4.jpg -------------------------------------------------------------------------------- /examples/event/public/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/event/src/App.vue: -------------------------------------------------------------------------------- 1 | // region script 2 | 56 | // endregion script 57 | 58 | // region template 59 | 89 | // endregion template 90 | 91 | // region style 92 | 178 | // endregion style 179 | -------------------------------------------------------------------------------- /examples/event/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /examples/event/vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | plugins: [vue()], 9 | resolve: { 10 | alias: { 11 | '@': fileURLToPath(new URL('./src', import.meta.url)) 12 | } 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /examples/methods/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | handson-vue3-examples 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/methods/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "methods", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview --port 4173" 9 | }, 10 | "dependencies": { 11 | "vue": "^3.2.37" 12 | }, 13 | "devDependencies": { 14 | "@vitejs/plugin-vue": "^3.0.1", 15 | "vite": "^3.0.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/methods/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/methods/public/favicon.ico -------------------------------------------------------------------------------- /examples/methods/public/images/item1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/methods/public/images/item1.jpg -------------------------------------------------------------------------------- /examples/methods/public/images/item2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/methods/public/images/item2.jpg -------------------------------------------------------------------------------- /examples/methods/public/images/item3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/methods/public/images/item3.jpg -------------------------------------------------------------------------------- /examples/methods/public/images/item4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/methods/public/images/item4.jpg -------------------------------------------------------------------------------- /examples/methods/public/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/methods/src/App.vue: -------------------------------------------------------------------------------- 1 | // region script 2 | 52 | // endregion script 53 | 54 | // region template 55 | 83 | // endregion template 84 | 85 | 167 | -------------------------------------------------------------------------------- /examples/methods/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /examples/methods/vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | plugins: [vue()], 9 | resolve: { 10 | alias: { 11 | '@': fileURLToPath(new URL('./src', import.meta.url)) 12 | } 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /examples/overview/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | handson-vue3-examples 8 | 9 | 10 | 11 | 14 |
15 |
16 | 17 |

Vue.js ハンズオン

18 |
19 |
20 |
21 |
22 | 23 |
24 |
25 |

アボカドディップバケット

26 |

27 | 刻んだ野菜をアボカドと混ぜてディップに。こんがり焼いたバゲットとお召し上がりください。 28 |

29 | ¥480 30 |
31 |
32 |
33 |
34 | 35 |
36 |
37 |

あの日夢見たホットケーキ

38 |

39 | 子供のころに食べたかった、あのホットケーキを再現しました。素朴でどこか懐かしい味をどうぞ。 40 |

41 | ¥1,180 42 |
43 |
44 |
45 |
46 | 47 |
48 |
49 |

HOP WTR

50 |

51 | ロサンゼルス生まれのスパークリングウォーター。ノンカロリー、ノンアルコールの新感覚飲料です。 52 |

53 | ¥320 54 |
55 |
56 |
57 |
58 | 59 |
60 |
61 |

チーズフレンチフライ

62 |

63 | イタリア産チーズをたっぷりかけたアツアツのフレンチフライ。みんな大好きな一品です。 64 |

65 | ¥670 66 |
67 |
68 |
69 |
70 | 71 | 72 | -------------------------------------------------------------------------------- /examples/overview/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "overview", 3 | "private": true, 4 | "version": "0.1.1", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview --port 4173" 9 | }, 10 | "dependencies": { 11 | "vue": "^3.2.37" 12 | }, 13 | "devDependencies": { 14 | "@vitejs/plugin-vue": "^3.0.1", 15 | "vite": "^3.0.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/overview/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/overview/public/favicon.ico -------------------------------------------------------------------------------- /examples/overview/public/images/item1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/overview/public/images/item1.jpg -------------------------------------------------------------------------------- /examples/overview/public/images/item2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/overview/public/images/item2.jpg -------------------------------------------------------------------------------- /examples/overview/public/images/item3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/overview/public/images/item3.jpg -------------------------------------------------------------------------------- /examples/overview/public/images/item4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/overview/public/images/item4.jpg -------------------------------------------------------------------------------- /examples/overview/public/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/overview/src/App.vue: -------------------------------------------------------------------------------- 1 | // region script 2 | 6 | // endregion script 7 | 8 | // region template 9 | 22 | // endregion template 23 | 24 | // region style 25 | 53 | // endregion style 54 | -------------------------------------------------------------------------------- /examples/overview/src/assets/base.css: -------------------------------------------------------------------------------- 1 | /* color palette from */ 2 | :root { 3 | --vt-c-white: #ffffff; 4 | --vt-c-white-soft: #f8f8f8; 5 | --vt-c-white-mute: #f2f2f2; 6 | 7 | --vt-c-black: #181818; 8 | --vt-c-black-soft: #222222; 9 | --vt-c-black-mute: #282828; 10 | 11 | --vt-c-indigo: #2c3e50; 12 | 13 | --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); 14 | --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); 15 | --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); 16 | --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); 17 | 18 | --vt-c-text-light-1: var(--vt-c-indigo); 19 | --vt-c-text-light-2: rgba(60, 60, 60, 0.66); 20 | --vt-c-text-dark-1: var(--vt-c-white); 21 | --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); 22 | } 23 | 24 | /* semantic color variables for this project */ 25 | :root { 26 | --color-background: var(--vt-c-white); 27 | --color-background-soft: var(--vt-c-white-soft); 28 | --color-background-mute: var(--vt-c-white-mute); 29 | 30 | --color-border: var(--vt-c-divider-light-2); 31 | --color-border-hover: var(--vt-c-divider-light-1); 32 | 33 | --color-heading: var(--vt-c-text-light-1); 34 | --color-text: var(--vt-c-text-light-1); 35 | 36 | --section-gap: 160px; 37 | } 38 | 39 | @media (prefers-color-scheme: dark) { 40 | :root { 41 | --color-background: var(--vt-c-black); 42 | --color-background-soft: var(--vt-c-black-soft); 43 | --color-background-mute: var(--vt-c-black-mute); 44 | 45 | --color-border: var(--vt-c-divider-dark-2); 46 | --color-border-hover: var(--vt-c-divider-dark-1); 47 | 48 | --color-heading: var(--vt-c-text-dark-1); 49 | --color-text: var(--vt-c-text-dark-2); 50 | } 51 | } 52 | 53 | *, 54 | *::before, 55 | *::after { 56 | box-sizing: border-box; 57 | margin: 0; 58 | position: relative; 59 | font-weight: normal; 60 | } 61 | 62 | body { 63 | min-height: 100vh; 64 | color: var(--color-text); 65 | background: var(--color-background); 66 | transition: color 0.5s, background-color 0.5s; 67 | line-height: 1.6; 68 | font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, 69 | Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; 70 | font-size: 15px; 71 | text-rendering: optimizeLegibility; 72 | -webkit-font-smoothing: antialiased; 73 | -moz-osx-font-smoothing: grayscale; 74 | } 75 | -------------------------------------------------------------------------------- /examples/overview/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/overview/src/assets/main.css: -------------------------------------------------------------------------------- 1 | @import "./base.css"; 2 | 3 | #app { 4 | max-width: 1280px; 5 | margin: 0 auto; 6 | padding: 2rem; 7 | 8 | font-weight: normal; 9 | } 10 | 11 | a, 12 | .green { 13 | text-decoration: none; 14 | color: hsla(160, 100%, 37%, 1); 15 | transition: 0.4s; 16 | } 17 | 18 | @media (hover: hover) { 19 | a:hover { 20 | background-color: hsla(160, 100%, 37%, 0.2); 21 | } 22 | } 23 | 24 | @media (min-width: 1024px) { 25 | body { 26 | display: flex; 27 | place-items: center; 28 | } 29 | 30 | #app { 31 | display: grid; 32 | grid-template-columns: 1fr 1fr; 33 | padding: 0 2rem; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/overview/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 20 | 21 | 44 | -------------------------------------------------------------------------------- /examples/overview/src/components/TheWelcome.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 85 | -------------------------------------------------------------------------------- /examples/overview/src/components/WelcomeItem.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 87 | -------------------------------------------------------------------------------- /examples/overview/src/components/icons/IconCommunity.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /examples/overview/src/components/icons/IconDocumentation.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /examples/overview/src/components/icons/IconEcosystem.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /examples/overview/src/components/icons/IconSupport.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /examples/overview/src/components/icons/IconTooling.vue: -------------------------------------------------------------------------------- 1 | 2 | 20 | -------------------------------------------------------------------------------- /examples/overview/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | 4 | import './assets/main.css' 5 | 6 | createApp(App).mount('#app') 7 | -------------------------------------------------------------------------------- /examples/overview/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | margin: 0; 4 | -webkit-font-smoothing: antialiased; 5 | -moz-osx-font-smoothing: grayscale; 6 | } 7 | 8 | #app { 9 | width: 90%; 10 | margin: 0 5%; 11 | text-align: center; 12 | color: #242424; 13 | } 14 | 15 | .header { 16 | display: flex; 17 | align-content: center; 18 | align-items: center; 19 | margin-top: 40px; 20 | margin-bottom: 40px; 21 | } 22 | 23 | .header > img { 24 | width: 100px; 25 | height: 100px; 26 | margin-right: 20px; 27 | } 28 | 29 | .header > h1 { 30 | font-size: 80px; 31 | font-weight: bold; 32 | line-height: 80px; 33 | margin-top: 0; 34 | margin-bottom: 0; 35 | } 36 | 37 | .main { 38 | display: grid; 39 | grid-template-columns: 3fr 3fr 3fr 3fr; 40 | column-gap: 24px; 41 | row-gap: 24px; 42 | } 43 | 44 | .item { 45 | padding: 10px; 46 | cursor: pointer; 47 | } 48 | 49 | .item:hover { 50 | transition: 0.2s transform ease-out; 51 | transform: scale(1.05); 52 | } 53 | 54 | .item > div.thumbnail > img { 55 | width: 100%; 56 | height: calc(100%); 57 | object-fit: cover; 58 | } 59 | 60 | .item > div.description { 61 | text-align: left; 62 | margin-top: 20px; 63 | } 64 | 65 | .item > div.description > p { 66 | margin-top: 0px; 67 | margin-bottom: 0px; 68 | font-size: 18px; 69 | line-height: 25px; 70 | } 71 | 72 | .item > div.description > span { 73 | display: block; 74 | margin-top: 10px; 75 | font-size: 20px; 76 | } 77 | 78 | .item > div.description > span > .price { 79 | font-size: 28px; 80 | font-weight: bold; 81 | } 82 | 83 | .selected-item { 84 | background: #e3f2fd; 85 | } 86 | -------------------------------------------------------------------------------- /examples/overview/vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | plugins: [vue()], 9 | resolve: { 10 | alias: { 11 | '@': fileURLToPath(new URL('./src', import.meta.url)) 12 | } 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /examples/rendering/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | handson-vue3-examples 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/rendering/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rendering", 3 | "private": true, 4 | "version": "0.1.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview --port 4173" 9 | }, 10 | "dependencies": { 11 | "vue": "^3.2.37" 12 | }, 13 | "devDependencies": { 14 | "@vitejs/plugin-vue": "^3.0.1", 15 | "vite": "^3.0.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/rendering/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/rendering/public/favicon.ico -------------------------------------------------------------------------------- /examples/rendering/public/images/item1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/rendering/public/images/item1.jpg -------------------------------------------------------------------------------- /examples/rendering/public/images/item2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/rendering/public/images/item2.jpg -------------------------------------------------------------------------------- /examples/rendering/public/images/item3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/rendering/public/images/item3.jpg -------------------------------------------------------------------------------- /examples/rendering/public/images/item4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/rendering/public/images/item4.jpg -------------------------------------------------------------------------------- /examples/rendering/public/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/rendering/src/App.vue: -------------------------------------------------------------------------------- 1 | // #region script 2 | 13 | // #endregion script 14 | 15 | // region template 16 | 38 | // endregion template 39 | 40 | // region style 41 | 123 | // endregion style -------------------------------------------------------------------------------- /examples/rendering/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /examples/rendering/vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | plugins: [vue()], 9 | resolve: { 10 | alias: { 11 | '@': fileURLToPath(new URL('./src', import.meta.url)) 12 | } 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /examples/slot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | handson-vue3-examples 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/slot/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "slot", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview --port 4173" 9 | }, 10 | "dependencies": { 11 | "vue": "^3.2.37" 12 | }, 13 | "devDependencies": { 14 | "@vitejs/plugin-vue": "^3.0.1", 15 | "vite": "^3.0.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/slot/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/slot/public/favicon.ico -------------------------------------------------------------------------------- /examples/slot/public/images/item1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/slot/public/images/item1.jpg -------------------------------------------------------------------------------- /examples/slot/public/images/item2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/slot/public/images/item2.jpg -------------------------------------------------------------------------------- /examples/slot/public/images/item3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/slot/public/images/item3.jpg -------------------------------------------------------------------------------- /examples/slot/public/images/item4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/slot/public/images/item4.jpg -------------------------------------------------------------------------------- /examples/slot/public/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/slot/src/App.vue: -------------------------------------------------------------------------------- 1 | // region script 2 | 50 | // endregion script 51 | 52 | // region template 53 | 82 | // endregion template 83 | 84 | // region style 85 | 143 | // endregion style 144 | -------------------------------------------------------------------------------- /examples/slot/src/components/Card.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 41 | 42 | 72 | -------------------------------------------------------------------------------- /examples/slot/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /examples/slot/vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | plugins: [vue()], 9 | resolve: { 10 | alias: { 11 | '@': fileURLToPath(new URL('./src', import.meta.url)) 12 | } 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /examples/v-for/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | handson-vue3-examples 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/v-for/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "v-for", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview --port 4173" 9 | }, 10 | "dependencies": { 11 | "vue": "^3.2.37" 12 | }, 13 | "devDependencies": { 14 | "@vitejs/plugin-vue": "^3.0.1", 15 | "vite": "^3.0.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/v-for/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/v-for/public/favicon.ico -------------------------------------------------------------------------------- /examples/v-for/public/images/item1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/v-for/public/images/item1.jpg -------------------------------------------------------------------------------- /examples/v-for/public/images/item2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/v-for/public/images/item2.jpg -------------------------------------------------------------------------------- /examples/v-for/public/images/item3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/v-for/public/images/item3.jpg -------------------------------------------------------------------------------- /examples/v-for/public/images/item4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/v-for/public/images/item4.jpg -------------------------------------------------------------------------------- /examples/v-for/public/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/v-for/src/App.vue: -------------------------------------------------------------------------------- 1 | // region script 2 | 40 | // endregion script 41 | 42 | // region template 43 | 69 | // endregion template 70 | 71 | 153 | -------------------------------------------------------------------------------- /examples/v-for/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /examples/v-for/vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | plugins: [vue()], 9 | resolve: { 10 | alias: { 11 | '@': fileURLToPath(new URL('./src', import.meta.url)) 12 | } 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /examples/v-if/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | handson-vue3-examples 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/v-if/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "v-if", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview --port 4173" 9 | }, 10 | "dependencies": { 11 | "vue": "^3.2.37" 12 | }, 13 | "devDependencies": { 14 | "@vitejs/plugin-vue": "^3.0.1", 15 | "vite": "^3.0.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/v-if/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/v-if/public/favicon.ico -------------------------------------------------------------------------------- /examples/v-if/public/images/item1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/v-if/public/images/item1.jpg -------------------------------------------------------------------------------- /examples/v-if/public/images/item2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/v-if/public/images/item2.jpg -------------------------------------------------------------------------------- /examples/v-if/public/images/item3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/v-if/public/images/item3.jpg -------------------------------------------------------------------------------- /examples/v-if/public/images/item4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/examples/v-if/public/images/item4.jpg -------------------------------------------------------------------------------- /examples/v-if/public/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/v-if/src/App.vue: -------------------------------------------------------------------------------- 1 | // region script 2 | 44 | // endregion script 45 | 46 | // region template 47 | 75 | // endregion template 76 | 77 | 159 | -------------------------------------------------------------------------------- /examples/v-if/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /examples/v-if/vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | plugins: [vue()], 9 | resolve: { 10 | alias: { 11 | '@': fileURLToPath(new URL('./src', import.meta.url)) 12 | } 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | handson-vue3-examples 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "handson-vue3-examples", 3 | "version": "1.1.1", 4 | "scripts": { 5 | "dev": "vite", 6 | "dev:methods": "npm run dev -w=methods", 7 | "dev:rendering": "npm run dev -w=rendering", 8 | "dev:event": "npm run dev -w=event", 9 | "dev:overview": "npm run dev -w=overview", 10 | "dev:v-for": "npm run dev -w=v-for", 11 | "dev:v-if": "npm run dev -w=v-if", 12 | "dev:component": "npm run dev -w=component", 13 | "dev:slot": "npm run dev -w=slot", 14 | "build": "vite build", 15 | "preview": "vite preview --port 4173", 16 | "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore", 17 | "textlint": "textlint --format pretty-error", 18 | "textlint:docs": "textlint --format pretty-error docs/**" 19 | }, 20 | "dependencies": { 21 | "vue": "^3.2.37" 22 | }, 23 | "devDependencies": { 24 | "@rushstack/eslint-patch": "1.1.0", 25 | "@vitejs/plugin-vue": "^3.0.1", 26 | "@vue/eslint-config-prettier": "7.0.0", 27 | "eslint": "8.5.0", 28 | "eslint-plugin-vue": "8.4.1", 29 | "prettier": "2.5.1", 30 | "textlint": "12.1.0", 31 | "textlint-filter-rule-allowlist": "4.0.0", 32 | "textlint-rule-preset-vuejs-jp": "github:vuejs-jp/textlint-rule-preset-vuejs-jp", 33 | "vite": "^3.0.1" 34 | }, 35 | "workspaces": [ 36 | "examples/*" 37 | ], 38 | "browserslist": [ 39 | "> 1%", 40 | "last 2 versions", 41 | "not dead", 42 | "not ie 11" 43 | ], 44 | "volta": { 45 | "node": "18.6.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/public/favicon.ico -------------------------------------------------------------------------------- /public/images/item1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/public/images/item1.jpg -------------------------------------------------------------------------------- /public/images/item2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/public/images/item2.jpg -------------------------------------------------------------------------------- /public/images/item3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/public/images/item3.jpg -------------------------------------------------------------------------------- /public/images/item4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs-jp/handson-vue3/9c3525529c50ba9007b62adc3645558e6e421ab6/public/images/item4.jpg -------------------------------------------------------------------------------- /public/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 49 | 50 | 80 | 81 | 139 | -------------------------------------------------------------------------------- /src/components/Card.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 41 | 42 | 72 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | plugins: [vue()], 9 | resolve: { 10 | alias: { 11 | '@': fileURLToPath(new URL('./src', import.meta.url)) 12 | } 13 | } 14 | }) 15 | --------------------------------------------------------------------------------