路由规划

本项目在实现的是一个论坛网站,网站划分为三个部分:

  • 前台用户界面:主要是论坛的主题;主题的详细内容及评论;

  • 帐号管理界面:主要是注册、登录等功能;

  • 后台管理界面:主要是主题的管理;评论内容的管理等功能;

修改路由文件

打开文件:src/router/index.js, 编辑其内容如以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import Vue from 'vue';
import VueRouter from 'vue-router';

Vue.use(VueRouter);

const routes = [
{
path: '/', // 前台页面模块及其嵌套子路由
component: () => import('@/views/home/Index.vue'), // 父路由指向的文件一般用于整个模块布局
children: [
{
path: '', // 此处实际访问路径为父子path的结合: /
alias: 'home', // alias(别名)相当于第二个path, 类似重定向的效果, 指向实际路径: /home
name: 'home', // 命名路由
component: () => import('@/views/home/pages/TopicList.vue'), // 指向的实际文件
},
{
path: 'topicdetails/:id', // 此处实际访问路径为父子path的结合: /topicdetails/:id
name: 'topic-details', // 命令路由建议使用 短横线命名 或 Pascal 命名
component: () => import('@/views/home/pages/TopicDetails.vue'),
},
]
},
{
path: '/dashboard', // 后台管理模块及嵌套子路由
component: () => import('@/views/dashboard/Index.vue'), // 父路由指向的文件一般用于整个模块布局
children: [
{
path: '', // 此处实际访问路径为父子path的结合: /dashboard/
alias: 'topiclist', // 别名指向实际路径: /dashboard/topiclist
name: 'topic-manager',
component: () => import('@/views/dashboard/pages/TopicManager.vue'),
},
{
path: 'commentclist', // 此处实际访问路径为父子path的结合: /dashboard/commentclist
name: 'comment-manager',
component: () => import('@/views/dashboard/pages/CommentManager.vue'),
},
{
path: 'createtopic', // 此处实际访问路径为父子path的结合: /dashboard/createtopic
name: 'create-topic',
component: () => import('@/views/dashboard/pages/CreateTopic.vue'),
},
{
// 动态路由, 冒号后面的 id 为传递参数的变量名
// 例如:/dashboard/createtopic/5 , 则参数值 5, 会以变量名 id 传递进去
// 在目标组件可以用 this.$route.params.id 来接收这个值
path: 'edittopic/:id', // 实际指向路径为: /dashboard/createtopic/:id,
name: 'edit-topic',
component: () => import('@/views/dashboard/pages/EditTopic.vue'),
},
]
},
{
path: '/account', // 账号模块及其嵌套子路由
component: () => import('@/views/account/Index.vue'), // 父路由指向的文件一般用于整个模块布局
children: [
{
path: '', // 此处实际访问路径为: /account
alias: 'login', // 别名指向实际路径:/account/login
name: 'login',
component: () => import('@/views/account/pages/Login.vue'),
},
{
path: 'signup', // 此处实际访问路径为父子path的结合: /account/signup
name: 'signup',
component: () => import('@/views/account/pages/SignUp.vue'),
},
]
},
]

const router = new VueRouter({
routes
});

// 使用路由拦截保存跳转到登录页的地址,登录成功后跳转回该页(回跳功能在登录页实现)
router.beforeEach((to, from, next) => {
// 如果 跳转的目标 path 是登录页(看上面的路由设置中对应的path )
if (to.path == '/account' || to.path == '/account/login') {
// 保存当前路由, 用于登录成功后跳转到登录前的页面
localStorage.setItem("preRoute", router.currentRoute.fullPath);
}
next();
});

export default router;

创建与路由对应的文件夹及文件

分别创建以下三个文件夹:

  • src/views/home:存放前台用户界面的 vue 文件;

  • src/views/account:存放用户帐号相关的 vue 文件;

  • src/views/dashboard:存放后台管理界面的 vue 文件;

分别在以上三个文件夹各添加一个 Index.vue 文件,用于该模块的页面布局。

分别在以上三个文件夹内各添加一个 pages 文件夹,并在里面创建各模块所需的视图文件。

具体的各个文件请参照路由 src/router/index.js 中各个 component: () => import('') 内的文件路径进行创建。

创建完毕后的项目结构如下图所示:

编辑 App.vue

打开文件: src/App.vue, 编辑其内容如以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<v-app>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view />
</v-app>
</template>

<script>
export default {
name: "App",

data: () => ({
//
}),
};
</script>

在上面的代码中, 标签 v-app 是所有应用都需要的组件。 这是 Vuetify 组件和功能的挂载点,并确保它将默认的应用 变体 (dark/light)传递给子组件,并可以保证它将默认的应用程序变种(暗色或亮色)传递给子组件,还可以保证跨浏览器支持 Safari 等浏览器中某些点击事件。v-app 应该在应用程序中仅使用一次。

<router-view /> 是路由出口,用于渲染路由匹配到的组件。

在本例中使用了两层的嵌套路由配置,App.vue里面的 <router-view /> 是最顶层的出口,渲染最高级路由匹配到的组件。

对于嵌套的二级路由,则需要在每个模块的 Index.vue 文件中再添加一个 <router-view /> 用于渲染匹配到的组件。

前台用户界面模块布局

打开文件: src/views/home/Index.vue, 编辑其内容如以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div>Home</div>
</template>

<script>
export default {
name: "home",
data: () => ({
//
}),
};
</script>

<style>
</style>

多语言国际化

Vue I18nVue.js 的国际化插件, Vuetify 支持其组件的语言国际化 (i18n), 可以非常容易地将Vue I18nVuetify 进行集成。

安装多语言国际化组件

在控制台输入命令:yarn add vue-i18n

安装的过程显示如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
PS D:\sources\vue_repos\mad-world-app> yarn add vue-i18n
yarn add v1.22.5
[1/4] Resolving packages...
[2/4] Fetching packages...
info fsevents@2.3.1: The platform "win32" is incompatible with this module.
info "fsevents@2.3.1" is an optional dependency and failed compatibility check. Excluding it from installation.
info fsevents@1.2.13: The platform "win32" is incompatible with this module.
info "fsevents@1.2.13" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
warning " > sass-loader@8.0.2" has unmet peer dependency "webpack@^4.36.0 || ^5.0.0".
warning "vue-cli-plugin-vuetify > null-loader@3.0.0" has unmet peer dependency "webpack@^4.3.0".
warning " > vuetify-loader@1.6.0" has unmet peer dependency "webpack@^4.0.0".
[4/4] Building fresh packages...

success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
└─ vue-i18n@8.22.4
info All dependencies
└─ vue-i18n@8.22.4
Done in 78.80s.

添加国际化语言包文件

在项目中创建文件夹:src/locale

添加 English 的语言文件:src/locale/en.js, 编辑其内容如以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import en from 'vuetify/es5/locale/en';

export default {
label: 'English',
//page login
login: 'Log In',
signup: 'Sign Up',
username: 'Username',
password: 'Password',
login_account: 'Login accoount',
// menu
menu: {
home: 'Home',
dashboard: 'Dashboard',
},
//
...en,
}

创建简体中文的语言文件:src/locale/zh-Hans.js, 编辑其内容如以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import zhHans from 'vuetify/es5/locale/zh-Hans';  // 导入Vuetify 自带的简体中文语言包

export default {
label: '简体中文',
// 登录页
login: '登录',
signup: '注册',
username: '用户名',
password: '密码',
login_account: '登录帐户',
// 菜单
menu: {
home: '首页',
dashboard: '仪表盘',
},
// 展开 简体中文语言包的所有项目
...zhHans,
}

如果还需要其他的语言文件,添加相应的文件并按照上面的格式进行修改即可。

国际化的配置文件

打开 Vuetify 的配置文件: src/plugins/vuetify.js`, 修改其内容如以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import Vue from 'vue';
import Vuetify from 'vuetify/lib/framework';

// @ 是项目中文件夹 src 的别名
import zhHans from '@/locale/zh-Hans'; // 导入简体中文语言
import en from '@/locale/en'; // 导入English语言

Vue.use(Vuetify);

export default new Vuetify({
lang: {
locales: { zhHans, en }, // 所有可用的语言
current: 'en', // 当前语言
}
});


添加多语言选择菜单组件

添加新文件:src/components/LocaleLanguage.vue,编辑其内容如以下代码所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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
57
58
59
60
61
62
63
64
65
66
67
68
69
<template>
<div>
<!-- 多语言选择菜单 -->
<v-menu
offset-y
origin="center center"
class="elelvation-1"
transition="scale-transition"
>
<template v-slot:activator="{ on }">
<v-btn text slot="activator" v-on="on">
<v-icon medium>mdi-translate</v-icon>
<!-- 显示当前语言名称 -->
<span class="ml-2"> {{ localeText }} </span>
<v-icon small>mdi-menu-down</v-icon>
</v-btn>
</template>
<!-- 显示所有语言包组成的下拉菜单 -->
<v-list>
<v-list-item-group v-model="$vuetify.lang.current">
<v-list-item
@click="handleChangeLocale(item)"
v-for="item in availableLanguages"
:key="item.value"
:value="item.value"
>
<v-list-item-title v-text="item.text" />
</v-list-item>
</v-list-item-group>
</v-list>
</v-menu>
</div>
</template>

<script>
export default {
name: "locale-language",
methods: {
// 设置当前语言
handleChangeLocale({ value }) {
this.$vuetify.lang.current = value;
},
},

computed: {
// 遍历并获取项目中的所有语言包
availableLanguages() {
const { locales } = this.$vuetify.lang; // 所有的语言,来自 src/plugins/vuetify.js 中的配置
return Object.keys(locales).map((lang) => {
return {
text: locales[lang].label, // 语言包显示的名字
value: lang, // 语言包的值
};
});
},
// 当前语言, 用于语言切换菜单中显示的当前语言名字
localeText() {
const find = this.availableLanguages.find(
(item) => item.value === this.$vuetify.lang.current
);
return find.text;
},
},
};
</script>

<style>
</style>

在需要切换多语言的地方,添加对 LocaleLanguage 组件的引用和注册,并调用该组件即可(这个部分将在后台管理和前台页面完成)。

使用多语言国际化功能

在其他需要使用多语言功能的地方,可以通过类似 {{ $vuetify.lang.t("$vuetify.label") }} 的形式来使用事先在 语言包中定义好的名字,这里的 label 就是在语言包中定义好的变量。

===END===