├── .nvmrc ├── .node-version ├── docs ├── guide │ └── README.md ├── demo │ ├── modal_store │ │ └── README.md │ ├── computed_filter │ │ └── README.md │ └── README.md ├── .vuepress │ ├── axios.js │ ├── views │ │ ├── index.js │ │ ├── DemoForm.vue │ │ ├── DemoModal.vue │ │ ├── DemoVuexTransition.vue │ │ ├── DemoI18n.vue │ │ └── LayoutDemo.vue │ ├── store.js │ ├── config.js │ ├── enhanceApp.js │ └── routes.js └── README.md ├── .eslintignore ├── form ├── .babelrc ├── src │ ├── mixins │ │ ├── index.js │ │ └── form-item.js │ ├── lib │ │ ├── index.js │ │ ├── BaseSelectFormItem.js │ │ ├── BaseForm.js │ │ └── BaseFormItem.js │ ├── forms │ │ ├── index.js │ │ ├── items │ │ │ ├── index.js │ │ │ ├── TitleFormItem.js │ │ │ ├── NameFormItem.js │ │ │ ├── BodyFormItem.js │ │ │ ├── PasswordFormItem.js │ │ │ ├── CategoryFormItem.js │ │ │ └── EmailFormItem.js │ │ ├── SampleForm.js │ │ ├── PasswordUpdateForm.js │ │ └── ContactForm.js │ ├── components │ │ ├── index.js │ │ ├── FormInput.vue │ │ ├── FormTextarea.vue │ │ └── FormSelect.vue │ ├── App.vue │ ├── store.js │ ├── helpers │ │ ├── store.js │ │ └── validators.js │ ├── main.js │ ├── views │ │ ├── Complete.vue │ │ ├── PasswordUpdate.vue │ │ ├── Confirm.vue │ │ ├── Form.vue │ │ └── SampleValidationAttribute.vue │ ├── store │ │ └── form.js │ └── router.js ├── .postcssrc ├── vue.config.js ├── public │ ├── favicon.ico │ └── index.html ├── tests │ ├── unit │ │ ├── .eslintrc │ │ ├── forms │ │ │ ├── SampleForm.spec.js │ │ │ └── ContactForm.spec.js │ │ ├── helpers │ │ │ ├── store.spec.js │ │ │ └── validators.spec.js │ │ ├── views │ │ │ ├── Form.spec.js │ │ │ ├── Confirm.spec.js │ │ │ └── Complete.spec.js │ │ ├── lib │ │ │ ├── BaseSelectFormItem.spec.js │ │ │ ├── BaseForm.spec.js │ │ │ └── BaseFormItem.spec.js │ │ ├── App.spec.js │ │ ├── store │ │ │ └── form.spec.js │ │ ├── components │ │ │ ├── FormSelect.spec.js │ │ │ ├── FormTextarea.spec.js │ │ │ └── FormInput.spec.js │ │ └── mixins │ │ │ └── form-item.spec.js │ └── resources │ │ └── components │ │ └── FormItem.vue ├── .gitignore ├── jest.config.js ├── package.json ├── .eslintrc.js └── README.md ├── i18n ├── .babelrc ├── .postcssrc ├── public │ ├── locales │ │ ├── about │ │ │ ├── ja.json │ │ │ └── en.json │ │ ├── home │ │ │ ├── ja.json │ │ │ └── en.json │ │ └── common │ │ │ ├── en.json │ │ │ └── ja.json │ ├── favicon.ico │ └── index.html ├── src │ ├── views │ │ ├── About.vue │ │ └── Home.vue │ ├── App.vue │ ├── main.js │ ├── router.js │ └── i18n.js ├── .gitignore ├── README.md ├── package.json └── .eslintrc.js ├── computed_filter ├── .babelrc ├── .postcssrc ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── assets │ │ └── logo.png │ ├── main.js │ ├── components │ │ ├── FilterExample.vue │ │ ├── ComputedExample.vue │ │ └── ComputedForm.vue │ └── App.vue ├── .gitignore ├── README.md ├── package.json └── .eslintrc.js ├── samples ├── modal_store │ ├── .babelrc │ ├── .postcssrc │ ├── src │ │ ├── assets │ │ │ └── scss │ │ │ │ └── styles.scss │ │ ├── components │ │ │ ├── index.js │ │ │ ├── BaseButton.vue │ │ │ └── TheModal.vue │ │ ├── store.js │ │ ├── helpers │ │ │ └── store.js │ │ ├── main.js │ │ ├── App.vue │ │ ├── router.js │ │ ├── views │ │ │ ├── Home.vue │ │ │ └── About.vue │ │ └── store │ │ │ └── modal.js │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ ├── .gitignore │ ├── README.md │ ├── package.json │ └── .eslintrc.js ├── vuex_transition_problem │ ├── .babelrc │ ├── .postcssrc │ ├── src │ │ ├── constants │ │ │ └── api.js │ │ ├── axios.js │ │ ├── helpers │ │ │ └── store.js │ │ ├── views │ │ │ ├── Home.vue │ │ │ ├── ProblemAsc.vue │ │ │ ├── ProblemDesc.vue │ │ │ ├── ExpectAsc.vue │ │ │ └── ExpectDesc.vue │ │ ├── App.vue │ │ ├── store.js │ │ ├── main.js │ │ ├── layouts │ │ │ ├── Expect.vue │ │ │ └── Problem.vue │ │ ├── router.js │ │ └── store │ │ │ └── section.js │ ├── public │ │ ├── favicon.ico │ │ ├── api │ │ │ └── sections │ │ │ │ ├── asc.json │ │ │ │ └── desc.json │ │ └── index.html │ ├── .gitignore │ ├── README.md │ ├── package.json │ └── .eslintrc.js └── README.md ├── .gitignore ├── .eslintrc.js ├── LICENSE ├── package.json └── README.md /.nvmrc: -------------------------------------------------------------------------------- 1 | v10.8.0 2 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | v10.8.0 2 | -------------------------------------------------------------------------------- /docs/guide/README.md: -------------------------------------------------------------------------------- 1 | # Guide 2 | 3 | 準備中🐈 -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | computed_filter 2 | form 3 | i18n 4 | samples 5 | -------------------------------------------------------------------------------- /form/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@vue/app" 4 | ] 5 | } -------------------------------------------------------------------------------- /i18n/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@vue/app" 4 | ] 5 | } -------------------------------------------------------------------------------- /form/src/mixins/index.js: -------------------------------------------------------------------------------- 1 | export { formItemMixin } from './form-item'; 2 | -------------------------------------------------------------------------------- /computed_filter/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@vue/app" 4 | ] 5 | } -------------------------------------------------------------------------------- /docs/demo/modal_store/README.md: -------------------------------------------------------------------------------- 1 | # Vuexを使ったモーダルの表示 2 | 3 | 4 | -------------------------------------------------------------------------------- /form/.postcssrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": { 3 | "autoprefixer": {} 4 | } 5 | } -------------------------------------------------------------------------------- /form/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | lintOnSave: undefined, 3 | }; 4 | -------------------------------------------------------------------------------- /i18n/.postcssrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": { 3 | "autoprefixer": {} 4 | } 5 | } -------------------------------------------------------------------------------- /samples/modal_store/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@vue/app" 4 | ] 5 | } -------------------------------------------------------------------------------- /computed_filter/.postcssrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": { 3 | "autoprefixer": {} 4 | } 5 | } -------------------------------------------------------------------------------- /i18n/public/locales/about/ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "about": { 3 | "title": "概要" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /samples/modal_store/.postcssrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": { 3 | "autoprefixer": {} 4 | } 5 | } -------------------------------------------------------------------------------- /samples/modal_store/src/assets/scss/styles.scss: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | -------------------------------------------------------------------------------- /samples/vuex_transition_problem/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@vue/app" 4 | ] 5 | } -------------------------------------------------------------------------------- /i18n/public/locales/about/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "about": { 3 | "title": "About" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /samples/vuex_transition_problem/.postcssrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": { 3 | "autoprefixer": {} 4 | } 5 | } -------------------------------------------------------------------------------- /form/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mya-ake/vue-tips-samples/HEAD/form/public/favicon.ico -------------------------------------------------------------------------------- /i18n/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mya-ake/vue-tips-samples/HEAD/i18n/public/favicon.ico -------------------------------------------------------------------------------- /i18n/src/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /computed_filter/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mya-ake/vue-tips-samples/HEAD/computed_filter/public/favicon.ico -------------------------------------------------------------------------------- /i18n/public/locales/home/ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "home": { 3 | "title": "ホーム", 4 | "text": "$t と v-t の動作検証" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /computed_filter/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mya-ake/vue-tips-samples/HEAD/computed_filter/src/assets/logo.png -------------------------------------------------------------------------------- /samples/vuex_transition_problem/src/constants/api.js: -------------------------------------------------------------------------------- 1 | export const SORT_ORDERS = { 2 | ASC: 'asc', 3 | DESC: 'desc', 4 | }; 5 | -------------------------------------------------------------------------------- /samples/modal_store/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mya-ake/vue-tips-samples/HEAD/samples/modal_store/public/favicon.ico -------------------------------------------------------------------------------- /form/tests/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jest": true 4 | }, 5 | "rules": { 6 | "import/no-extraneous-dependencies": "off" 7 | } 8 | } -------------------------------------------------------------------------------- /i18n/public/locales/common/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "nav": { 3 | "home": "Home", 4 | "about": "About", 5 | "change-language": "日本語" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /i18n/public/locales/common/ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "nav": { 3 | "home": "ホーム", 4 | "about": "概要", 5 | "change-language": "English" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /i18n/public/locales/home/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "home": { 3 | "title": "Home", 4 | "text": "Operation verification of $ t and v-t" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /docs/.vuepress/axios.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | const client = axios.create({ 4 | baseURL: '/api', 5 | }); 6 | 7 | export default client; 8 | -------------------------------------------------------------------------------- /samples/modal_store/src/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as BaseButton } from './BaseButton'; 2 | export { default as TheModal } from './TheModal'; 3 | -------------------------------------------------------------------------------- /samples/vuex_transition_problem/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mya-ake/vue-tips-samples/HEAD/samples/vuex_transition_problem/public/favicon.ico -------------------------------------------------------------------------------- /form/src/lib/index.js: -------------------------------------------------------------------------------- 1 | export { BaseForm } from './BaseForm'; 2 | export { BaseFormItem } from './BaseFormItem'; 3 | export { BaseSelectFormItem } from './BaseSelectFormItem'; 4 | -------------------------------------------------------------------------------- /samples/vuex_transition_problem/src/axios.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | const client = axios.create({ 4 | baseURL: '/api', 5 | }); 6 | 7 | export default client; 8 | -------------------------------------------------------------------------------- /form/src/forms/index.js: -------------------------------------------------------------------------------- 1 | export { ContactForm } from './ContactForm'; 2 | export { SampleForm } from './SampleForm'; 3 | export { PasswordUpdateForm } from './PasswordUpdateForm'; 4 | -------------------------------------------------------------------------------- /computed_filter/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App.vue'; 3 | 4 | Vue.config.productionTip = false; 5 | 6 | new Vue({ 7 | render: h => h(App), 8 | }).$mount('#app'); 9 | -------------------------------------------------------------------------------- /form/src/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as FormInput } from './FormInput'; 2 | export { default as FormTextarea } from './FormTextarea'; 3 | export { default as FormSelect } from './FormSelect'; 4 | -------------------------------------------------------------------------------- /docs/demo/computed_filter/README.md: -------------------------------------------------------------------------------- 1 | # computed と filter の例 2 | 3 | ## computed 4 | 5 | 6 | 7 | ## filter 8 | 9 | 10 | 11 | ## Computed Form 12 | 13 | -------------------------------------------------------------------------------- /form/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 11 | 13 | -------------------------------------------------------------------------------- /form/src/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | 4 | import * as formModule from '@/store/form'; 5 | 6 | Vue.use(Vuex); 7 | 8 | export default new Vuex.Store({ 9 | modules: { 10 | form: formModule, 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /form/src/helpers/store.js: -------------------------------------------------------------------------------- 1 | export const buildModuleTypes = ({ moduleName, types }) => { 2 | return Object.entries(types).reduce((exportTypes, [type, value]) => { 3 | exportTypes[type] = `${moduleName}/${value}`; 4 | return exportTypes; 5 | }, {}); 6 | }; 7 | -------------------------------------------------------------------------------- /samples/modal_store/src/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | import * as modalModule from '@/store/modal'; 4 | 5 | Vue.use(Vuex); 6 | 7 | export default new Vuex.Store({ 8 | modules: { 9 | modal: modalModule, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /samples/modal_store/src/helpers/store.js: -------------------------------------------------------------------------------- 1 | export const buildModuleTypes = ({ moduleName, types }) => { 2 | return Object.entries(types).reduce((exportTypes, [type, value]) => { 3 | exportTypes[type] = `${moduleName}/${value}`; 4 | return exportTypes; 5 | }, {}); 6 | }; 7 | -------------------------------------------------------------------------------- /form/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App.vue'; 3 | import router from './router'; 4 | import store from './store'; 5 | 6 | Vue.config.productionTip = false; 7 | 8 | new Vue({ 9 | router, 10 | store, 11 | render: h => h(App), 12 | }).$mount('#app'); 13 | -------------------------------------------------------------------------------- /samples/vuex_transition_problem/src/helpers/store.js: -------------------------------------------------------------------------------- 1 | export const buildModuleTypes = ({ moduleName, types }) => { 2 | return Object.entries(types).reduce((exportTypes, [type, value]) => { 3 | exportTypes[type] = `${moduleName}/${value}`; 4 | return exportTypes; 5 | }, {}); 6 | }; 7 | -------------------------------------------------------------------------------- /form/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | -------------------------------------------------------------------------------- /docs/.vuepress/views/index.js: -------------------------------------------------------------------------------- 1 | export { default as LayoutDemo } from './LayoutDemo'; 2 | export { default as DemoForm } from './DemoForm'; 3 | export { default as DemoI18n } from './DemoI18n'; 4 | export { default as DemoModal } from './DemoModal'; 5 | export { default as DemoVuexTransition } from './DemoVuexTransition'; 6 | -------------------------------------------------------------------------------- /i18n/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | -------------------------------------------------------------------------------- /computed_filter/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | -------------------------------------------------------------------------------- /samples/modal_store/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | -------------------------------------------------------------------------------- /form/src/forms/items/index.js: -------------------------------------------------------------------------------- 1 | export { NameFormItem } from './NameFormItem'; 2 | export { EmailFormItem } from './EmailFormItem'; 3 | export { CategoryFormItem } from './CategoryFormItem'; 4 | export { TitleFormItem } from './TitleFormItem'; 5 | export { BodyFormItem } from './BodyFormItem'; 6 | export { PasswordFormItem } from './PasswordFormItem'; 7 | -------------------------------------------------------------------------------- /samples/modal_store/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App.vue'; 3 | import router from './router'; 4 | import store from './store'; 5 | 6 | import './assets/scss/styles.scss'; 7 | 8 | Vue.config.productionTip = false; 9 | 10 | new Vue({ 11 | router, 12 | store, 13 | render: h => h(App), 14 | }).$mount('#app'); 15 | -------------------------------------------------------------------------------- /samples/vuex_transition_problem/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /form/src/lib/BaseSelectFormItem.js: -------------------------------------------------------------------------------- 1 | import { BaseFormItem } from './BaseFormItem'; 2 | 3 | export class BaseSelectFormItem extends BaseFormItem { 4 | constructor(value = '') { 5 | super(value); 6 | this.options = []; 7 | } 8 | 9 | valid(value) { 10 | return this.options.some(option => value === option.value); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /samples/vuex_transition_problem/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /form/tests/unit/forms/SampleForm.spec.js: -------------------------------------------------------------------------------- 1 | import { BaseForm } from '@/lib'; 2 | import { SampleForm } from '@/forms'; 3 | 4 | describe('ContactForm', () => { 5 | describe('constructor', () => { 6 | it('basic', () => { 7 | const form = new SampleForm(); 8 | expect(form instanceof BaseForm).toBe(true); 9 | }); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /samples/vuex_transition_problem/src/App.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 14 | -------------------------------------------------------------------------------- /form/tests/resources/components/FormItem.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /samples/vuex_transition_problem/src/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | 4 | import axios from './axios'; 5 | 6 | import * as sectionModule from '@/store/section'; 7 | 8 | Vue.use(Vuex); 9 | 10 | const store = new Vuex.Store({ 11 | modules: { 12 | section: sectionModule, 13 | }, 14 | }); 15 | 16 | store.axios = axios; 17 | 18 | export default store; 19 | -------------------------------------------------------------------------------- /samples/README.md: -------------------------------------------------------------------------------- 1 | # 章の中の一部のサンプルコードなどをまとめて入れているフォルダー 2 | 3 | ## 章と対象フォルダー 4 | 5 | ### 4 章 Vuex の tips 6 | 7 | Vuex を使ったモーダルの表示のサンプルコードです。 8 | 9 | [modal_store](https://vue-tips-support-page.mya-ake.org/demo/modal_store/) 10 | 11 | Vuex と transition コンポーネントを使った場合の問題となる動作のサンプルコードです。 12 | 13 | [vuex_transition_problem](https://vue-tips-support-page.mya-ake.org/demo/vuex_transition_problem/) 14 | -------------------------------------------------------------------------------- /form/src/views/Complete.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | 19 | 21 | -------------------------------------------------------------------------------- /samples/vuex_transition_problem/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueAxios from 'vue-axios'; 3 | import axios from './axios'; 4 | import App from './App.vue'; 5 | import router from './router'; 6 | import store from './store'; 7 | 8 | Vue.config.productionTip = false; 9 | 10 | Vue.use(VueAxios, axios); 11 | 12 | new Vue({ 13 | router, 14 | store, 15 | render: h => h(App), 16 | }).$mount('#app'); 17 | -------------------------------------------------------------------------------- /docs/.vuepress/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | 4 | import * as formModule from './store/form'; 5 | import * as modalModule from './store/modal'; 6 | import * as sectionModule from './store/section'; 7 | 8 | Vue.use(Vuex); 9 | 10 | export default new Vuex.Store({ 11 | modules: { 12 | form: formModule, 13 | modal: modalModule, 14 | section: sectionModule, 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /form/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testURL: 'http://localhost', 3 | moduleFileExtensions: ['js', 'jsx', 'json', 'vue'], 4 | transform: { 5 | '^.+\\.vue$': 'vue-jest', 6 | '^.+\\.jsx?$': 'babel-jest', 7 | }, 8 | moduleNameMapper: { 9 | '^@/(.*)$': '/src/$1', 10 | '^~resources/(.*)$': '/tests/resources/$1', 11 | }, 12 | snapshotSerializers: ['jest-serializer-vue'], 13 | }; 14 | -------------------------------------------------------------------------------- /docs/.vuepress/views/DemoForm.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 15 | 16 | 21 | -------------------------------------------------------------------------------- /docs/demo/README.md: -------------------------------------------------------------------------------- 1 | # Demo 2 | 3 | 一部無理やり拡張して表示しているデモもあるため、リロードすると 404 になる場合があります。 4 | 5 | ## 1章 computedとfilter 6 | 7 | - [computedとfilterの例](/demo/computed_filter/) 8 | 9 | ## 2章, 3章 フォーム 10 | 11 | - [formの例](/demo/form/) 12 | 13 | ## 4章 Vuexのtips 14 | 15 | - [UIの操作にストアを使う例](/demo/modal_store/) 16 | - [遷移前に表示が変わる問題の例](/demo/vuex_transition_problem/) 17 | 18 | ## 6章 vue-i18nのLazy loadingとvue-router 19 | 20 | - [i18nの例](/demo/i18n/) 21 | -------------------------------------------------------------------------------- /i18n/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 24 | -------------------------------------------------------------------------------- /samples/modal_store/README.md: -------------------------------------------------------------------------------- 1 | # 4 章 Vuex の tips 2 | 3 | Vuex を使ったモーダルの表示のサンプルコードです。 4 | 5 | ## デモ 6 | 7 | https://vue-tips-support-page.mya-ake.org/demo/modal_store/ 8 | 9 | ## commands 10 | 11 | ### yarn 12 | 13 | #### インストール 14 | 15 | ``` 16 | $ yarn 17 | ``` 18 | 19 | #### 動作確認 20 | 21 | ``` 22 | $ yarn serve 23 | ``` 24 | 25 | ### npm 26 | 27 | #### インストール 28 | 29 | ``` 30 | $ npm install 31 | ``` 32 | 33 | #### 動作確認 34 | 35 | ``` 36 | $ npm run serve 37 | ``` 38 | -------------------------------------------------------------------------------- /samples/modal_store/src/App.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 21 | 22 | 23 | 25 | -------------------------------------------------------------------------------- /computed_filter/README.md: -------------------------------------------------------------------------------- 1 | # 1 章 computed と filter 2 | 3 | computed と filter の使い分けに関する章のサンプルコードです。 4 | 5 | ## デモ 6 | 7 | https://vue-tips-support-page.mya-ake.org/demo/computed_filter/ 8 | 9 | ## commands 10 | 11 | ### yarn 12 | 13 | #### インストール 14 | 15 | ``` 16 | $ yarn 17 | ``` 18 | 19 | #### 動作確認 20 | 21 | ``` 22 | $ yarn serve 23 | ``` 24 | 25 | ### npm 26 | 27 | #### インストール 28 | 29 | ``` 30 | $ npm install 31 | ``` 32 | 33 | #### 動作確認 34 | 35 | ``` 36 | $ npm run serve 37 | ``` 38 | -------------------------------------------------------------------------------- /form/tests/unit/helpers/store.spec.js: -------------------------------------------------------------------------------- 1 | import * as store from '@/helpers/store'; 2 | 3 | describe('Store helpers', () => { 4 | it('buildModuleTypes', () => { 5 | const moduleName = 'user'; 6 | const types = { 7 | SET_NAME: 'SET_NAME', 8 | SET_EMAIL: 'SET_EMAIL', 9 | }; 10 | 11 | const moduleTypes = store.buildModuleTypes({ moduleName, types }); 12 | 13 | expect(moduleTypes.SET_NAME).toBe('user/SET_NAME'); 14 | expect(moduleTypes.SET_EMAIL).toBe('user/SET_EMAIL'); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | locales: { 3 | '/': { 4 | lang: 'ja', 5 | title: '現場で使えるVue.js tips集のサポートページ', 6 | description: '現場で使えるVue.js tips集のサポートページです。書籍内で書ききれなかった解説などが書かれる予定です。', 7 | } 8 | }, 9 | themeConfig: { 10 | nav: [ 11 | { text: 'Home', link: '/' }, 12 | { text: 'Guide', link: '/guide/' }, 13 | { text: 'Demo', link: '/demo/' }, 14 | ], 15 | sidebar: [], 16 | repo: 'mya-ake/vue-tips-samples', 17 | repoLabel: 'GitHub', 18 | }, 19 | } -------------------------------------------------------------------------------- /samples/vuex_transition_problem/README.md: -------------------------------------------------------------------------------- 1 | # 4 章 Vuex の tips 2 | 3 | Vuex と transition コンポーネントを使った場合の問題となる動作のサンプルコードです。 4 | 5 | ## デモ 6 | 7 | https://vue-tips-support-page.mya-ake.org/demo/?r=demo-vuex_transition_problem 8 | 9 | ## commands 10 | 11 | ### yarn 12 | 13 | #### インストール 14 | 15 | ``` 16 | $ yarn 17 | ``` 18 | 19 | #### 動作確認 20 | 21 | ``` 22 | $ yarn serve 23 | ``` 24 | 25 | ### npm 26 | 27 | #### インストール 28 | 29 | ``` 30 | $ npm install 31 | ``` 32 | 33 | #### 動作確認 34 | 35 | ``` 36 | $ npm run serve 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/.vuepress/views/DemoModal.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | 22 | # doc 23 | docs/.vuepress/components 24 | docs/.vuepress/store 25 | docs/.vuepress/public/api 26 | docs/.vuepress/public/locales 27 | docs/.vuepress/i18n.js 28 | docs/.vuepress/mixins 29 | docs/.vuepress/lib 30 | docs/.vuepress/forms 31 | docs/.vuepress/helpers 32 | -------------------------------------------------------------------------------- /i18n/README.md: -------------------------------------------------------------------------------- 1 | # 6 章 vue-i18n の Lazy loading と vue-router 2 | 3 | vue-i18n の Lazy loading の実装をしている章のサンプルコードです。 4 | また Lazy loading する際に vue-router のナビゲーションガードが深く関わったのでその実装もあります。 5 | 6 | ## デモ 7 | 8 | https://vue-tips-support-page.mya-ake.org/demo/?r=demo-i18n 9 | 10 | ## commands 11 | 12 | ### yarn 13 | 14 | #### インストール 15 | 16 | ``` 17 | $ yarn 18 | ``` 19 | 20 | #### 動作確認 21 | 22 | ``` 23 | $ yarn serve 24 | ``` 25 | 26 | ### npm 27 | 28 | #### インストール 29 | 30 | ``` 31 | $ npm install 32 | ``` 33 | 34 | #### 動作確認 35 | 36 | ``` 37 | $ npm run serve 38 | ``` 39 | -------------------------------------------------------------------------------- /samples/modal_store/src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Router from 'vue-router'; 3 | import Home from './views/Home.vue'; 4 | import About from './views/About.vue'; 5 | 6 | Vue.use(Router); 7 | 8 | export default new Router({ 9 | mode: 'history', 10 | routes: [ 11 | { 12 | path: '/', 13 | name: 'home', 14 | component: Home, 15 | }, 16 | { 17 | path: '/about', 18 | name: 'about', 19 | component: About, 20 | }, 21 | { 22 | path: '*', 23 | component: Home, 24 | }, 25 | ], 26 | }); 27 | -------------------------------------------------------------------------------- /samples/vuex_transition_problem/public/api/sections/asc.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": [ 3 | { 4 | "number": 1, 5 | "title": "computedとfilter" 6 | }, 7 | { 8 | "number": 2, 9 | "title": "フォーム基礎編" 10 | }, 11 | { 12 | "number": 3, 13 | "title": "フォーム実践編" 14 | }, 15 | { 16 | "number": 4, 17 | "title": "Vuexのtips" 18 | }, 19 | { 20 | "number": 5, 21 | "title": "vue-test-utilsでなにをテストするか" 22 | }, 23 | { 24 | "number": 6, 25 | "title": "vue-i18nのLazy loadingとvue-router" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /samples/vuex_transition_problem/public/api/sections/desc.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": [ 3 | { 4 | "number": 6, 5 | "title": "vue-i18nのLazy loadingとvue-router" 6 | }, 7 | { 8 | "number": 5, 9 | "title": "vue-test-utilsでなにをテストするか" 10 | }, 11 | { 12 | "number": 4, 13 | "title": "Vuexのtips" 14 | }, 15 | { 16 | "number": 3, 17 | "title": "フォーム実践編" 18 | }, 19 | { 20 | "number": 2, 21 | "title": "フォーム基礎編" 22 | }, 23 | { 24 | "number": 1, 25 | "title": "computedとfilter" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /i18n/src/App.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 26 | -------------------------------------------------------------------------------- /computed_filter/src/components/FilterExample.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 28 | -------------------------------------------------------------------------------- /form/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | form 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /i18n/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | i18n 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /samples/modal_store/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 29 | -------------------------------------------------------------------------------- /form/tests/unit/views/Form.spec.js: -------------------------------------------------------------------------------- 1 | import { shallowMount, createLocalVue } from '@vue/test-utils'; 2 | import Vuex from 'vuex'; 3 | 4 | import Form from '@/views/Form'; 5 | import * as formModule from '@/store/form'; 6 | 7 | const localVue = createLocalVue(); 8 | localVue.use(Vuex); 9 | 10 | describe('Form view', () => { 11 | let store; 12 | 13 | beforeEach(() => { 14 | store = new Vuex.Store({ 15 | modules: { 16 | form: formModule, 17 | }, 18 | }); 19 | }); 20 | 21 | it('mount', () => { 22 | const wrapper = shallowMount(Form, { store, localVue }); 23 | expect(wrapper.isVueInstance()).toBe(true); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /samples/modal_store/src/views/About.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 29 | -------------------------------------------------------------------------------- /computed_filter/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | computed_filter 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /samples/modal_store/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | modal_store 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /form/tests/unit/lib/BaseSelectFormItem.spec.js: -------------------------------------------------------------------------------- 1 | import { BaseSelectFormItem } from '@/lib'; 2 | 3 | describe('BaseSelectFormItem', () => { 4 | describe('Built-in validator', () => { 5 | it('valid, true', () => { 6 | const baseSelectFormItem = new BaseSelectFormItem(); 7 | baseSelectFormItem.options = [ 8 | { 9 | text: 'test', 10 | value: 'test', 11 | }, 12 | ]; 13 | expect(baseSelectFormItem.valid('test')).toBe(true); 14 | }); 15 | 16 | it('valid, false', () => { 17 | const baseSelectFormItem = new BaseSelectFormItem(); 18 | expect(baseSelectFormItem.valid('test')).toBe(false); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /computed_filter/src/components/ComputedExample.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 35 | -------------------------------------------------------------------------------- /samples/vuex_transition_problem/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | vuex_transition_problem 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /form/src/helpers/validators.js: -------------------------------------------------------------------------------- 1 | export const isEmptyString = value => { 2 | return String(value).length === 0; 3 | }; 4 | 5 | /** 6 | * 正規表現はinput[type="email"]を引用 7 | * https://www.w3.org/TR/html5/forms.html#valid-e-mail-address 8 | */ 9 | export const isEmail = value => { 10 | return /^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test( 11 | value, 12 | ); 13 | }; 14 | 15 | export const isExpectLength = (value, { max = Infinity, min = 0 } = {}) => { 16 | const str = String(value); 17 | if (str.length > max) { 18 | return false; 19 | } 20 | if (str.length < min) { 21 | return false; 22 | } 23 | return true; 24 | }; 25 | -------------------------------------------------------------------------------- /samples/vuex_transition_problem/src/layouts/Expect.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | 21 | 32 | -------------------------------------------------------------------------------- /samples/vuex_transition_problem/src/layouts/Problem.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | 21 | 32 | -------------------------------------------------------------------------------- /docs/.vuepress/views/DemoVuexTransition.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 21 | 22 | 27 | 28 | -------------------------------------------------------------------------------- /form/tests/unit/App.spec.js: -------------------------------------------------------------------------------- 1 | import { shallowMount, createLocalVue } from '@vue/test-utils'; 2 | import VueRouter from 'vue-router'; 3 | import Vuex from 'vuex'; 4 | 5 | import App from '@/App'; 6 | import * as formModule from '@/store/form'; 7 | 8 | const localVue = createLocalVue(); 9 | localVue.use(VueRouter); 10 | localVue.use(Vuex); 11 | 12 | const router = new VueRouter(); 13 | 14 | describe('App view', () => { 15 | let store; 16 | 17 | beforeEach(() => { 18 | store = new Vuex.Store({ 19 | modules: { 20 | form: formModule, 21 | }, 22 | }); 23 | }); 24 | 25 | it('mount', () => { 26 | const wrapper = shallowMount(App, { store, router, localVue }); 27 | expect(wrapper.isVueInstance()).toBe(true); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /form/src/forms/SampleForm.js: -------------------------------------------------------------------------------- 1 | import { BaseForm } from '@/lib'; 2 | import { EmailFormItem } from './items'; 3 | 4 | export class SampleForm extends BaseForm { 5 | constructor({ 6 | email = '', 7 | emailDirty = '', 8 | emailTouched = '', 9 | emailTouechAndDirty = '', 10 | emailTouchedAfterDirty = '', 11 | } = {}) { 12 | super(); 13 | this.addItem('email', new EmailFormItem(email)); 14 | this.addItem('emailDirty', new EmailFormItem(emailDirty)); 15 | this.addItem('emailTouched', new EmailFormItem(emailTouched)); 16 | this.addItem('emailTouechAndDirty', new EmailFormItem(emailTouechAndDirty)); 17 | this.addItem( 18 | 'emailTouchedAfterDirty', 19 | new EmailFormItem(emailTouchedAfterDirty), 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /form/src/forms/items/TitleFormItem.js: -------------------------------------------------------------------------------- 1 | import { BaseFormItem } from '@/lib'; 2 | import { isExpectLength } from '@/helpers/validators'; 3 | 4 | const MESSAGES = { 5 | EXPECT_LENGTH: '32文字以内で入力してください', 6 | }; 7 | 8 | export class TitleFormItem extends BaseFormItem { 9 | constructor(value = '') { 10 | super(value); 11 | this.maxlength = 33; 12 | 13 | this._addValidators(); 14 | } 15 | 16 | _addValidators() { 17 | this.addValidator({ 18 | message: `${this.maxlength - 1}文字以内で入力してください`, 19 | validator: this._isExpectLengthValidator, 20 | }); 21 | } 22 | 23 | _isExpectLengthValidator(value) { 24 | return isExpectLength(value, { 25 | max: this.maxlength - 1, 26 | }); 27 | } 28 | } 29 | 30 | TitleFormItem.MESSAGES = MESSAGES; 31 | -------------------------------------------------------------------------------- /computed_filter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "computed_filter", 3 | "version": "0.2.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve --open", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "vue": "^2.5.17" 12 | }, 13 | "devDependencies": { 14 | "@vue/cli-plugin-babel": "^3.0.0", 15 | "@vue/cli-plugin-eslint": "^3.0.0", 16 | "@vue/cli-service": "^3.0.0", 17 | "@vue/eslint-config-prettier": "^3.0.0", 18 | "babel-core": "^7.0.0-0", 19 | "node-sass": "^4.9.3", 20 | "sass-loader": "^6.0.6", 21 | "vue-template-compiler": "^2.5.17" 22 | }, 23 | "browserslist": [ 24 | "> 1%", 25 | "last 2 versions", 26 | "not ie <= 8" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /form/tests/unit/views/Confirm.spec.js: -------------------------------------------------------------------------------- 1 | import { shallowMount, createLocalVue } from '@vue/test-utils'; 2 | import VueRouter from 'vue-router'; 3 | import Vuex from 'vuex'; 4 | 5 | import Confirm from '@/views/Confirm'; 6 | import * as formModule from '@/store/form'; 7 | 8 | const localVue = createLocalVue(); 9 | localVue.use(VueRouter); 10 | localVue.use(Vuex); 11 | 12 | const router = new VueRouter(); 13 | 14 | describe('Confirm view', () => { 15 | let store; 16 | 17 | beforeEach(() => { 18 | store = new Vuex.Store({ 19 | modules: { 20 | form: formModule, 21 | }, 22 | }); 23 | }); 24 | 25 | it('mount', () => { 26 | const wrapper = shallowMount(Confirm, { store, router, localVue }); 27 | expect(wrapper.isVueInstance()).toBe(true); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /form/tests/unit/views/Complete.spec.js: -------------------------------------------------------------------------------- 1 | import { shallowMount, createLocalVue } from '@vue/test-utils'; 2 | import VueRouter from 'vue-router'; 3 | import Vuex from 'vuex'; 4 | 5 | import Complete from '@/views/Complete'; 6 | import * as formModule from '@/store/form'; 7 | 8 | const localVue = createLocalVue(); 9 | localVue.use(VueRouter); 10 | localVue.use(Vuex); 11 | 12 | const router = new VueRouter(); 13 | 14 | describe('Complete view', () => { 15 | let store; 16 | 17 | beforeEach(() => { 18 | store = new Vuex.Store({ 19 | modules: { 20 | form: formModule, 21 | }, 22 | }); 23 | }); 24 | 25 | it('mount', () => { 26 | const wrapper = shallowMount(Complete, { store, router, localVue }); 27 | expect(wrapper.isVueInstance()).toBe(true); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /samples/modal_store/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "modal_store", 3 | "version": "0.2.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve --open", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "vue": "^2.5.17", 12 | "vue-router": "^3.0.1", 13 | "vuex": "^3.0.1" 14 | }, 15 | "devDependencies": { 16 | "@vue/cli-plugin-babel": "^3.0.0", 17 | "@vue/cli-plugin-eslint": "^3.0.0", 18 | "@vue/cli-service": "^3.0.0", 19 | "@vue/eslint-config-prettier": "^3.0.0", 20 | "node-sass": "^4.9.3", 21 | "sass-loader": "^6.0.6", 22 | "vue-template-compiler": "^2.5.17" 23 | }, 24 | "browserslist": [ 25 | "> 1%", 26 | "last 2 versions", 27 | "not ie <= 8" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /computed_filter/src/App.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 38 | -------------------------------------------------------------------------------- /form/src/forms/items/NameFormItem.js: -------------------------------------------------------------------------------- 1 | import { BaseFormItem } from '@/lib'; 2 | import { isEmptyString, isExpectLength } from '@/helpers/validators'; 3 | 4 | export class NameFormItem extends BaseFormItem { 5 | constructor(value = '') { 6 | super(value); 7 | this.maxlength = 17; 8 | 9 | this._addValidators(); 10 | } 11 | 12 | _addValidators() { 13 | this.addValidator({ 14 | message: '入力が必須の項目です', 15 | validator: this._isEmptyValidator, 16 | }); 17 | 18 | this.addValidator({ 19 | message: '16文字以内で入力してください', 20 | validator: this._isExpectLengthValidator, 21 | }); 22 | } 23 | 24 | _isEmptyValidator(value) { 25 | return isEmptyString(value) === false; 26 | } 27 | 28 | _isExpectLengthValidator(value) { 29 | return isExpectLength(value, { max: this.maxlength - 1 }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /i18n/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "i18n", 3 | "version": "0.2.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve --open", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.18.0", 12 | "vue": "^2.5.17", 13 | "vue-i18n": "^8.0.0", 14 | "vue-router": "^3.0.1" 15 | }, 16 | "devDependencies": { 17 | "@vue/cli-plugin-babel": "^3.0.0", 18 | "@vue/cli-plugin-eslint": "^3.0.0", 19 | "@vue/cli-service": "^3.0.0", 20 | "@vue/eslint-config-prettier": "^3.0.0", 21 | "babel-core": "^7.0.0-0", 22 | "babel-jest": "^22.0.4", 23 | "node-sass": "^4.9.3", 24 | "sass-loader": "^6.0.6", 25 | "vue-template-compiler": "^2.5.17" 26 | }, 27 | "browserslist": [ 28 | "> 1%", 29 | "last 2 versions", 30 | "not ie <= 8" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /samples/vuex_transition_problem/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuex_transition_problem", 3 | "version": "0.2.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve --open", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.18.0", 12 | "vue": "^2.5.17", 13 | "vue-axios": "^2.1.3", 14 | "vue-router": "^3.0.1", 15 | "vuex": "^3.0.1" 16 | }, 17 | "devDependencies": { 18 | "@vue/cli-plugin-babel": "^3.0.0", 19 | "@vue/cli-plugin-eslint": "^3.0.0", 20 | "@vue/cli-service": "^3.0.0", 21 | "@vue/eslint-config-prettier": "^3.0.0", 22 | "node-sass": "^4.9.3", 23 | "sass-loader": "^6.0.6", 24 | "vue-template-compiler": "^2.5.17" 25 | }, 26 | "browserslist": [ 27 | "> 1%", 28 | "last 2 versions", 29 | "not ie <= 8" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /form/src/forms/items/BodyFormItem.js: -------------------------------------------------------------------------------- 1 | import { BaseFormItem } from '@/lib'; 2 | import { isEmptyString, isExpectLength } from '@/helpers/validators'; 3 | 4 | export class BodyFormItem extends BaseFormItem { 5 | constructor(value = '') { 6 | super(value); 7 | this.maxlength = 501; 8 | 9 | this._addValidators(); 10 | } 11 | 12 | _addValidators() { 13 | this.addValidator({ 14 | message: '入力が必須の項目です', 15 | validator: this._isEmptyValidator, 16 | stop: true, 17 | }); 18 | 19 | this.addValidator({ 20 | message: `${this.maxlength - 1}文字以内で入力してください`, 21 | validator: this._isExpectLengthValidator, 22 | }); 23 | } 24 | 25 | _isEmptyValidator(value) { 26 | return isEmptyString(value) === false; 27 | } 28 | 29 | _isExpectLengthValidator(value) { 30 | return isExpectLength(value, { 31 | max: this.maxlength - 1, 32 | }); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /docs/.vuepress/views/DemoI18n.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 30 | 31 | 36 | -------------------------------------------------------------------------------- /i18n/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App.vue'; 3 | import router from './router'; 4 | import { 5 | i18n, 6 | allowLanguage, 7 | extractLanguage, 8 | setLang, 9 | loadLocaleMessage, 10 | } from './i18n'; 11 | 12 | Vue.config.productionTip = false; 13 | 14 | // 遷移時に必要な言語ファイルを取りにいく 15 | router.beforeEach(async (to, from, next) => { 16 | const lang = to.params.lang; 17 | 18 | if (allowLanguage(lang) === false) { 19 | next(`/${i18n.locale}`); 20 | return; 21 | } 22 | 23 | const { locale } = to.meta; 24 | await setLang(lang); 25 | await loadLocaleMessage(lang, locale.category); 26 | next(); 27 | }); 28 | 29 | // 最初の言語を決めるためにマウント前に言語ファイルを取りにいく 30 | (async () => { 31 | const lang = extractLanguage(); 32 | await setLang(lang); 33 | await loadLocaleMessage(lang, 'common'); 34 | new Vue({ 35 | router, 36 | i18n, 37 | render: h => h(App), 38 | }).$mount('#app'); 39 | })(); 40 | -------------------------------------------------------------------------------- /form/src/components/FormInput.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 40 | 41 | 43 | -------------------------------------------------------------------------------- /samples/vuex_transition_problem/src/views/ProblemAsc.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 39 | -------------------------------------------------------------------------------- /samples/vuex_transition_problem/src/views/ProblemDesc.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 39 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # 現場で使える Vue.js tips 集のサポートページ 2 | 3 | ## 書籍について 4 | 5 | Vue.js の実装例をケースに基づき解説している書籍になります。 6 | 筆者が現場で得てきた知見を元にしています。 7 | 8 | 主に Form 周りに関して、UX を向上させるような処理をサポートするようなローカルのライブラリを作り、 Form の複雑さに立ち向かう内容となっています。 9 | 合わせて Vue.js の周辺ライブラリの Vuex、Vue Router、vue-test-utils、vue-i18n などについても書かせていただきました。 10 | 11 | 次のサイトにネットから購入可能な店舗の情報が記載されているので、合わせてご確認ください。 12 | 13 | [https://nextpublishing.jp/book/10057.html](https://nextpublishing.jp/book/10057.html) 14 | 15 | ## このサイトについて 16 | 17 | 主にこのサイトはデモページの提供と書籍内で不足していると思われる情報を発信するために用意しました。 18 | Twitter などで見かけた声を元に充実させていけたらと考えています。 19 | 20 | また、このサイトは筆者が個人的に運営しているサイトです。 21 | 出版元のインプレス R&D は関わっておりません。 22 | 23 | このサイトの記載内容に関するお問い合わせは筆者の[Twitter](https://twitter.com/mya_ake)、または GitHub のリポジトリの [Issues](https://github.com/mya-ake/vue-tips-samples/issues)にお願いします。 24 | 25 | ## サンプルコード 26 | 27 | 書籍内で記述しているコードはほぼ [GitHub のリポジトリ](https://github.com/mya-ake/vue-tips-samples)で公開されています。 28 | ライセンスは MIT ライセンスとなっているので、コピーしてお使いいただいても問題ありません。 29 | -------------------------------------------------------------------------------- /form/src/forms/items/PasswordFormItem.js: -------------------------------------------------------------------------------- 1 | import { BaseFormItem } from '@/lib'; 2 | import { isEmptyString, isExpectLength } from '@/helpers/validators'; 3 | 4 | export class PasswordFormItem extends BaseFormItem { 5 | constructor(value = '') { 6 | super(value); 7 | this.minlength = 8; 8 | this.maxlength = 65; 9 | 10 | this._addValidators(); 11 | } 12 | 13 | _addValidators() { 14 | this.addValidator({ 15 | message: '入力が必須の項目です', 16 | validator: this._isEmptyValidator, 17 | stop: true, 18 | }); 19 | 20 | this.addValidator({ 21 | message: `${this.minlength}~${this.maxlength - 1}文字で入力してください`, 22 | validator: this._isExpectLengthValidator, 23 | }); 24 | } 25 | 26 | _isEmptyValidator(value) { 27 | return isEmptyString(value) === false; 28 | } 29 | 30 | _isExpectLengthValidator(value) { 31 | return isExpectLength(value, { 32 | min: this.min, 33 | max: this.maxlength - 1, 34 | }); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /form/src/components/FormTextarea.vue: -------------------------------------------------------------------------------- 1 |