├── .browserslistrc
├── .editorconfig
├── .env
├── .eslintrc.js
├── .gitignore
├── README.md
├── babel.config.js
├── package.json
├── postcss.config.js
├── public
├── favicon.ico
└── index.html
├── src
├── App.vue
├── api
│ └── example.js
├── assets
│ └── logo.png
├── components
│ ├── base-card
│ │ ├── base-card-item.vue
│ │ └── index.vue
│ ├── effect-success
│ │ └── index.vue
│ └── skeleton-loading
│ │ └── index.vue
├── config.js
├── directives
│ ├── index.js
│ └── waves.js
├── filters
│ ├── currency.js
│ ├── date.js
│ ├── dictinory.js
│ └── index.js
├── i18n.js
├── locales
│ ├── zh-zang.json
│ └── zh.json
├── main.js
├── mock
│ ├── example.js
│ └── index.js
├── router.js
├── store.js
├── styles
│ └── variables.scss
├── utils
│ ├── Permission.js
│ ├── constants.helper.js
│ ├── constants.js
│ ├── ios.hack.js
│ └── request.js
└── views
│ └── features
│ ├── examples
│ ├── axios-wp.vue
│ ├── no-magic-number.vue
│ ├── permission
│ │ ├── flowchart.jpg
│ │ └── index.vue
│ ├── skeleton-screen.vue
│ ├── ue-status-change.vue
│ └── vant-ui.vue
│ └── index.vue
└── vue.config.js
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,ts,tsx,vue}]
2 | indent_style = space
3 | indent_size = 2
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | VUE_APP_I18N_LOCALE=zh
2 | VUE_APP_I18N_FALLBACK_LOCALE=zh
3 | VUE_APP_SITE_TITLE=vue h5 template
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true
5 | },
6 | 'extends': [
7 | 'plugin:vue/essential',
8 | '@vue/standard'
9 | ],
10 | rules: {
11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
13 | 'space-before-function-paren': 'off'
14 | },
15 | parserOptions: {
16 | parser: 'babel-eslint'
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/.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 |
23 | package-lock.json
24 | yarn.lock
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-h5-template
2 |
3 | > 针对 H5 开发的 vue 项目初始模板,基于 vue 和 vant-ui 实现
4 |
5 | 本项目致力于:
6 |
7 | - 省去项目搭建的过程
8 | - 提供便捷工具函数,加快开发速度
9 | - 整合一些开发的最佳实践
10 | - 专注于用户体验
11 | - 按需装载,不同项目可自行定制
12 | - 列举某些系统的 bug 以及提供其解决方案
13 |
14 | ## 功能
15 |
16 | - i18n
17 | - 内置过滤器
18 | - vant-ui
19 | - 权限校验体系
20 | - axios 封装以及 mock 数据
21 | - 封装好的字典映射相关功能
22 | - ...
23 |
24 | ## 开始
25 |
26 | ```
27 | # 克隆项目
28 | git clone https://github.com/tony-cn/vue-h5-template.git
29 |
30 | # 进入项目目录
31 | cd vue-h5-template
32 |
33 | # 安装依赖
34 | npm install
35 |
36 | # 启动服务
37 | npm run serve
38 | ```
39 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ],
5 | plugins: [
6 | ['import', {
7 | libraryName: 'vant',
8 | libraryDirectory: 'es',
9 | style: true
10 | }, 'vant']
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-h5-template",
3 | "version": "0.1.0",
4 | "scripts": {
5 | "serve": "vue-cli-service serve",
6 | "build": "vue-cli-service build",
7 | "lint": "vue-cli-service lint",
8 | "i18n:report": "vue-cli-service i18n:report --src './src/**/*.?(js|vue)' --locales './src/locales/**/*.json'"
9 | },
10 | "dependencies": {
11 | "axios": "^0.18.0",
12 | "core-js": "^2.6.5",
13 | "dayjs": "^1.8.14",
14 | "mockjs": "^1.0.1-beta3",
15 | "node-waves": "^0.7.6",
16 | "normalize.css": "^8.0.1",
17 | "vant": "^1.6.19",
18 | "vue": "^2.6.10",
19 | "vue-i18n": "^8.0.0",
20 | "vue-router": "^3.0.3",
21 | "vuex": "^3.0.1"
22 | },
23 | "devDependencies": {
24 | "@kazupon/vue-i18n-loader": "^0.3.0",
25 | "@vue/cli-plugin-babel": "^3.7.0",
26 | "@vue/cli-plugin-eslint": "^3.7.0",
27 | "@vue/cli-service": "^3.7.0",
28 | "@vue/eslint-config-standard": "^4.0.0",
29 | "babel-eslint": "^10.0.1",
30 | "babel-plugin-import": "^1.11.2",
31 | "eslint": "^5.16.0",
32 | "eslint-plugin-vue": "^5.0.0",
33 | "node-sass": "^4.9.0",
34 | "sass-loader": "^7.1.0",
35 | "vue-cli-plugin-i18n": "^0.6.0",
36 | "vue-template-compiler": "^2.5.21"
37 | },
38 | "repository": {
39 | "type": "git",
40 | "url": "https://github.com/tony-cn/vue-h5-template.git"
41 | },
42 | "keywords": [
43 | "vue",
44 | "h5",
45 | "template"
46 | ],
47 | "author": "tony-cn",
48 | "license": "MIT"
49 | }
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DakerHub/vue-h5-template/5a6f9233833d664c7a1ed353cf7ce60d3db5f278/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
10 |
12 | <%= VUE_APP_SITE_TITLE %>
13 |
14 |
15 |
16 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
--------------------------------------------------------------------------------
/src/api/example.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | export function fetchPostList() {
4 | return request.get('example')
5 | }
6 |
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DakerHub/vue-h5-template/5a6f9233833d664c7a1ed353cf7ce60d3db5f278/src/assets/logo.png
--------------------------------------------------------------------------------
/src/components/base-card/base-card-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ label }}
4 |
5 |
6 |
7 |
8 |
9 |
10 |
40 |
41 |
54 |
--------------------------------------------------------------------------------
/src/components/base-card/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
24 |
25 |
44 |
--------------------------------------------------------------------------------
/src/components/effect-success/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
22 |
23 |
156 |
--------------------------------------------------------------------------------
/src/components/skeleton-loading/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
19 |
20 |
22 |
--------------------------------------------------------------------------------
/src/config.js:
--------------------------------------------------------------------------------
1 | const isDev = process.env.NODE_ENV === 'development'
2 |
3 | export default {
4 | // 是否开启接口mock
5 | mockAPI: isDev,
6 | // 是否开发环境
7 | isDev,
8 | emptyText: '-'
9 | }
10 |
--------------------------------------------------------------------------------
/src/directives/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import waves from './waves'
3 |
4 | Vue.directive('waves', waves)
5 |
--------------------------------------------------------------------------------
/src/directives/waves.js:
--------------------------------------------------------------------------------
1 | // http://fian.my.id/Waves/#api
2 | import Waves from 'node-waves'
3 | import 'node-waves/dist/waves.css'
4 |
5 | export default {
6 | inserted: function (el, arg) {
7 | const config = {
8 | duration: 500,
9 | delay: 0
10 | }
11 | Waves.attach(el, arg.value)
12 | Waves.init(config)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/filters/currency.js:
--------------------------------------------------------------------------------
1 | export default function toThousandFilter(num, prefix = '¥') {
2 | let numFormatted = ''
3 |
4 | const cent = num % 100
5 | const integer = Number.parseInt(num / 100)
6 |
7 | const integerSplitted = (+integer || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ','))
8 |
9 | numFormatted = `${prefix}${integerSplitted}.${cent.toString().padEnd(2, '0')}`
10 |
11 | return numFormatted
12 | }
13 |
--------------------------------------------------------------------------------
/src/filters/date.js:
--------------------------------------------------------------------------------
1 | import dayjs from 'dayjs'
2 |
3 | export default function (value, formatter = 'YYYY-MM-DD') {
4 | if (value === undefined || value === null || value === '') return
5 |
6 | const date = dayjs(value)
7 | return date.isValid() ? date.format(formatter) : ''
8 | }
9 |
--------------------------------------------------------------------------------
/src/filters/dictinory.js:
--------------------------------------------------------------------------------
1 | import * as dictinory from '@/utils/constants'
2 | import config from '@/config'
3 |
4 | export default function(value, dictinoryName) {
5 | if (!dictinory.hasOwnProperty(dictinoryName)) {
6 | throw new Error(`[filter: dictinory] 没有"${dictinoryName}"字典`)
7 | }
8 |
9 | const dict = dictinory[dictinoryName]
10 |
11 | const target = Object.entries(dict).find(([key, val]) => value === val)
12 |
13 | return target ? target[0] : config.emptyText
14 | }
15 |
--------------------------------------------------------------------------------
/src/filters/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import date from './date'
3 | import currency from './currency'
4 | import dictinory from './dictinory'
5 |
6 | Vue.filter('date', date)
7 | Vue.filter('currency', currency)
8 | Vue.filter('dictinory', dictinory)
9 |
--------------------------------------------------------------------------------
/src/i18n.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueI18n from 'vue-i18n'
3 |
4 | Vue.use(VueI18n)
5 |
6 | function loadLocaleMessages () {
7 | const locales = require.context('./locales', true, /[A-Za-z0-9-_,\s]+\.json$/i)
8 | const messages = {}
9 | locales.keys().forEach(key => {
10 | const matched = key.match(/([A-Za-z0-9-_]+)\./i)
11 | if (matched && matched.length > 1) {
12 | const locale = matched[1]
13 | messages[locale] = locales(key)
14 | }
15 | })
16 | return messages
17 | }
18 |
19 | export default new VueI18n({
20 | locale: process.env.VUE_APP_I18N_LOCALE || 'en',
21 | fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'en',
22 | messages: loadLocaleMessages()
23 | })
24 |
--------------------------------------------------------------------------------
/src/locales/zh-zang.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "hello i18n !!"
3 | }
--------------------------------------------------------------------------------
/src/locales/zh.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "hello i18n !!"
3 | }
--------------------------------------------------------------------------------
/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 | import i18n from './i18n'
6 | import config from './config'
7 | import './filters'
8 | import './directives'
9 | import './utils/ios.hack'
10 | import 'normalize.css'
11 |
12 | (async () => {
13 | if (config.mockAPI) {
14 | await import('./mock')
15 | }
16 |
17 | Vue.config.productionTip = false
18 |
19 | new Vue({
20 | router,
21 | store,
22 | i18n,
23 | render: h => h(App)
24 | }).$mount('#app')
25 | })()
26 |
--------------------------------------------------------------------------------
/src/mock/example.js:
--------------------------------------------------------------------------------
1 | export const postList = {
2 | 'list|2-4': [{
3 | id: '@id',
4 | title: '@ctitle',
5 | date: '@date',
6 | author: '@cname'
7 | }],
8 | total: 10
9 | }
10 |
--------------------------------------------------------------------------------
/src/mock/index.js:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs'
2 | import {
3 | postList
4 | } from './example'
5 |
6 | Mock.mock(/example/, postList)
7 |
--------------------------------------------------------------------------------
/src/router.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 |
4 | Vue.use(Router)
5 |
6 | export default new Router({
7 | routes: [{
8 | path: '/',
9 | name: 'Features',
10 | component: () => import('./views/features/index.vue')
11 | }]
12 | })
13 |
--------------------------------------------------------------------------------
/src/store.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | Vue.use(Vuex)
5 |
6 | export default new Vuex.Store({
7 | state: {
8 |
9 | },
10 | mutations: {
11 |
12 | },
13 | actions: {
14 |
15 | }
16 | })
17 |
--------------------------------------------------------------------------------
/src/styles/variables.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DakerHub/vue-h5-template/5a6f9233833d664c7a1ed353cf7ce60d3db5f278/src/styles/variables.scss
--------------------------------------------------------------------------------
/src/utils/Permission.js:
--------------------------------------------------------------------------------
1 | export default class Permission {
2 | static config = {}
3 | static configure(config) {
4 | assert(config, 'isFreeRoute', 'function')
5 | assert(config, 'isUserLoaded', 'function')
6 | assert(config, 'loadUser', 'function')
7 | assert(config, 'hasAuth', 'function')
8 | assert(config, 'onNoAuth', 'function')
9 | assert(config, 'onNoUser', 'function')
10 | Object.assign(this.config, config)
11 | }
12 |
13 | static async interceptor(to, from, next) {
14 | if (await this.config.isFreeRoute(to, from)) {
15 | return next()
16 | }
17 |
18 | let loadUserOK = true
19 | if (!await this.config.isUserLoaded()) {
20 | loadUserOK = await this.config.loadUser()
21 | }
22 |
23 | if (loadUserOK) {
24 | if (await this.config.hasAuth(to, from)) {
25 | return next()
26 | }
27 |
28 | await this.config.onNoAuth(to, from, next)
29 |
30 | return
31 | }
32 |
33 | return this.config.onNoUser(to, from, next)
34 | }
35 | }
36 |
37 | function assert(config, key, type) {
38 | const value = config[key]
39 | /* eslint-disable valid-typeof */
40 | if (!value) {
41 | throw new Error(`[Permission.configure] 缺少参数 ${key}`)
42 | }
43 |
44 | if (typeof value !== type) {
45 | throw new TypeError(`[Permission.configure] ${key} 类型应该是 ${type}`)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/utils/constants.helper.js:
--------------------------------------------------------------------------------
1 | export function dictionary2entries(dictionary) {
2 | return Object.entries(dictionary).map(([label, value]) => ({
3 | label,
4 | value
5 | }))
6 | }
7 |
--------------------------------------------------------------------------------
/src/utils/constants.js:
--------------------------------------------------------------------------------
1 | export const FRUITS = {
2 | 苹果: 1,
3 | 香蕉: 2,
4 | 梨: 3
5 | }
6 |
--------------------------------------------------------------------------------
/src/utils/ios.hack.js:
--------------------------------------------------------------------------------
1 | // 微信ios系统上键盘收起后布局不重置的bug
2 |
3 | window.addEventListener('focusout', function () {
4 | setTimeout(() => {
5 | window.scrollTo(0, document.documentElement.scrollTop || document.body.scrollTop)
6 | })
7 | })
8 |
--------------------------------------------------------------------------------
/src/utils/request.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 |
3 | const axiosInstance = axios.create({
4 | baseURL: '/'
5 | })
6 |
7 | axiosInstance.interceptors.request.use(function (config) {
8 | // 在这里对请求进行统一处理,比如添加token
9 | return config
10 | }, function (error) {
11 | return Promise.reject(error)
12 | })
13 |
14 | axiosInstance.interceptors.response.use(function (response) {
15 | return response.data
16 | }, function (error) {
17 | return Promise.reject(error)
18 | })
19 |
20 | export default axiosInstance
21 |
--------------------------------------------------------------------------------
/src/views/features/examples/axios-wp.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
axios封装
4 |
由于项目不同,对于axios的需求也不一样,所以这里没有过多的对axios进行封装,这里给出一些小提示,可能会有帮助
5 |
6 | - 可以在requestInterceptors中为请求添加token或者自定义请求头
7 | - 可以在requestInterceptors中剔除掉值为null和undefined的参数
8 | - 可以在responseInterceptors中对错误进行统一处理,比如401跳转登录
9 |
10 |
11 | 更多设置请参考
12 | axios文档
13 |
14 |
接口数据Mock
15 |
16 |
17 |
{{ item.title }}
18 |
19 | {{item.date}}
20 | {{item.author}}
21 |
22 |
23 |
24 |
刷新列表
25 |
目录结构
26 |
27 |
28 |
29 | src/
30 | ├─ api/
31 | │ └─ post.js
32 | └─ mock/
33 | ├─ index.js
34 | └─ post.js
35 |
36 |
37 |
38 | - 我们将接口拆分成单个js文件以防止当接口过多时产生混乱。
39 | - 而mock的配置文件我们将其放入src/mock/文件夹下,在index.js中引用并匹配请求地址。
40 | - config.mockAPI设为false禁用mock
41 | -
42 | 具体如何进行mock数据编写请参考
43 | Mock.js
44 |
45 |
46 |
47 |
48 |
49 |
50 |
75 |
76 |
93 |
--------------------------------------------------------------------------------
/src/views/features/examples/no-magic-number.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 还在使用
5 | my.favoriteFruit === 1 做判断吗?
6 |
7 |
8 |
考虑一下以下做法:
9 |
10 | cosnt FRUITS = {{FRUITS}}
11 |
12 | my.favoriteFruit === FRUITS.苹果
13 |
14 |
15 | 我们在
16 | /utils/contants.js中统一定义所有的魔法数字对应关系。
17 |
18 |
这样就不用再担心关系一变就要到处去找被影响的代码修改。
19 |
并且通过汉字作为对象键,更加符合我们的认知习惯,因为毕竟不是所有程序员都能写出容易理解的英文变量名。😂
20 |
以上做法是否更加的清晰明了?
21 |
22 |
● dictionary2entries
23 |
24 | 当然很多时候我们需要将这些对应关系转换为选项数组。这里我们提供了转换方法
25 | dictionary2entries。
26 |
27 |
28 | import { dictionary2entries } from '@/utils/constants.helper'
29 | // ...
30 | const entries = dictionary2entries(FRUITS)
31 |
32 |
这样,我们拿到了
33 |
34 | {{ entries }}
35 |
36 |
37 |
● 字典过滤器
38 |
我们常见的一种情况,需要将魔法数字转换为对应的中文标识。
39 |
在采用了我们上面的统一做法后,我们可以使用一下过滤器:
40 |
41 |
1 | dictinory('FRUITS')
42 |
43 | 1
44 | {{1 | dictinory('FRUITS')}}
45 |
46 |
47 |
48 |
49 |
73 |
74 |
76 |
--------------------------------------------------------------------------------
/src/views/features/examples/permission/flowchart.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DakerHub/vue-h5-template/5a6f9233833d664c7a1ed353cf7ce60d3db5f278/src/views/features/examples/permission/flowchart.jpg
--------------------------------------------------------------------------------
/src/views/features/examples/permission/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 |
6 |
Have a try!
7 |
8 |
9 |
10 |
11 |
12 |
模拟一下
13 |
14 |
15 | {{item}}
16 |
17 |
18 |
19 |
20 |
21 |
22 |
105 |
106 |
130 |
--------------------------------------------------------------------------------
/src/views/features/examples/skeleton-screen.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |

17 |
18 |
19 |
标题
20 |
简介巴拉巴拉巴拉巴拉巴拉巴拉巴拉巴
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
48 |
49 |
109 |
--------------------------------------------------------------------------------
/src/views/features/examples/ue-status-change.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
31 |
32 |
43 |
--------------------------------------------------------------------------------
/src/views/features/examples/vant-ui.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
默认按钮
4 |
主要按钮
5 |
按需加载,减少主bundle的体积
6 |
vant开发文档
7 |
8 |
9 |
10 |
22 |
23 |
28 |
--------------------------------------------------------------------------------
/src/views/features/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 简体中文
6 | English
7 |
8 | {{ $t('hello') }}
9 |
10 |
11 |
12 | 日期过滤器 - date
13 | 2018-12-1
14 | {{'2018-12-1'|date('YYYY年MM月DD日')}}
15 | 金额过滤器 - currency
16 | 430000(分)
17 | {{'430000'|currency}}
18 |
19 |
20 |
21 | vant-ui
22 |
23 |
24 |
25 |
26 | 波纹效果(点击)
27 |
31 | 状态改变
32 | 成功失败图标
33 |
34 |
35 |
36 |
37 | 骨架屏
38 |
39 |
40 |
41 |
42 | 魔法数字说拜拜
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
90 |
91 |
138 |
139 |
140 | {
141 | "en": {
142 | "hello": "hello world!"
143 | },
144 | "zh": {
145 | "hello": "你好世界!"
146 | }
147 | }
148 |
149 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | pluginOptions: {
3 | i18n: {
4 | locale: 'zh',
5 | fallbackLocale: 'zh',
6 | localeDir: 'locales',
7 | enableInSFC: true
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------