当前网站开发用到的是 Vue3 版本,如果平时项目用 Vue2 版本可以当扩展阅读,在网站和目录布局设计上看其实两个版本差太多。当然很多细节实现还是有一些差异的。
1. 环境准备
1.1 安装 nodejs
如果本地没有装 node
的先去 node 官网 进行下载。
需安装最新版本的 node
1.2 安装 Vue CLI
现在 Vue 官网建议使用 create-vue 去搭建 vue 项目。
2. 搭建 Vue 项目
2.1 使用 CLI 创建项目
执行命令 npm init vue@3
2.2 安装依赖
进入项目目录去安装相应的依赖。推荐使用 pnpm
进行安装依赖,但是现阶段 pnpm install
有时候会有依赖缺失问题,所以可以先进行 pnpm install
,如果有依赖缺失的话,可以使用 npm install
进行安装。
2.3 启动项目
如果不知道启动的命令可以打开 package.json
进行查看。也可以通过 cat package.json
进行查看。
执行命令 npm run dev
启动。💢 可恶报错了。
然后经过一番周旋知道是因为node
过低导致的。所以我们借助 nrm
或者 n
来切换我们使用的 node 版本。这里我用 n
安装了 18.12.0
版本。
然后使用 node/18.12.0
版本。最后,我们再去试一下,项目能否正常运行。
🎉 项目正常运行了
2.4 规范目录结构
项目能正常运行之后,我们就需要在基础项目上,搭建一个完整的前端项目了。
稍微的改动一下目录结构,在原有的基础上增加了两个目录 utils
和 styles
。接下来我们具体列一下这几个目录的作用。
public
放置静态资源目录,可通过路由拼接直接访问。
src/assets
放置图片等资源,不可通过url
拼接直接访问,打包会直接打入代码内部。
src/components
放置公共的组件,提取的公共组件可放入这个文件夹。
src/router
放置路由配置,可在内部实现进入路由和出路由处理业务的相关逻辑。
src/stores
放置全局使用的变量,可以理解为一个单例。
src/styles
放置全局通用的样式代码。
src/utils
放置全局共用的脚本。
src/views
放置网页代码。
App.vue
为项目的入口界面。
main.ts
为项目的入口文件。
2.5 使用 vue-router
我们通过脚手架搭建的项目,自己就自带了 vue-router
,如果我们不通过脚手架的话,需要自己安装 vue-router
。安装 vue-router
通过下面指令。
# npm
$ npm i -S vue-router
# yarn
$ yarn add vue-router
# pnpm
$ pnpm i -S vue-router
其次,我们需要在主入口 main.ts
文件中进行引用。
// main.ts
import router from '@/router'
// ...
app.use(router)
然后,我们进入 src/router
文件中。看一下现有的代码是怎么写的。
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '@/views/HomeView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('@/views/AboutView.vue')
}
]
})
export default router
我们可以看到通过 vue-router
的方法 createRouter
创建了 router 实例。其中传参有两个,一个 history
,另一个 routes
。这两个参数有什么含义呢?vue-router
路由几种模式:创建 h5 历史、创建 Hash 历史和创建基于内存的历史记录。对于这几种模式的讲解会在另外的博客中进行讲解。这里就不讲解了,节省文章内容。根据以上说明,可以了解 history
现阶段分三种模式 createWebHistroy
、createWebHashHistroy
和 createMemoryHistroy
。
那 routes
是什么呢?
routes
里面你可以理解为是存放网页访问界面的匹配规则。比如我现在启动项目,页面通过访问 http://localhost:5173
就可以访问界面,这个界面访问的就是 ‘/’ 规则匹配的首页。
那很明显,就是我们在网页访问 http://localhost:5173/about
就可以访问 /about
匹配的界面了。
接下来,我们自己写一个界面,写一个简单的那就个人信息吧!让我们更熟悉一下界面是怎么生成的。
首先,我们在 src/views
目录下新建一个文件src/user/basic/index.vue
。
备注: 这里我们统一文件命名以小写字母。
src/user/basic/index.vue
具体的内容为下面。(Vue2 和 Vue3 的一个差别就是Vue3支持 Fragment 碎片化,节省了多余标签的定义)
// src/user/basic/index.vue
<template>
<h1>个人信息</h1>
<div>
<!-- 展示具体的个人信息 -->
</div>
</template>
然后,我们需要在 router/index.ts
文件中,新建一个规则去匹配这个界面。
// outer/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '@/views/HomeView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('@/views/AboutView.vue')
},
{
path: '/basicInfo',
name: 'basicInfo',
component: () => import('@/views/user/basic/index.vue')
}
]
})
export default router
通过 () => import()
方式去拉取页面,是为了节省资源的加载引发的内存和时间。这种方式也被称为按需加载,只在正确的时机加载需要的内容。
看,我们的界面代码起效果了,感觉有点不合适,我们将多余的内容给优化一下吧。
看看我们优化后的 App.vue
的代码。删除了很多代码。当然还有很多 css 的样式的去处,在这里就不一一列举了。
// App.vue
<script setup lang="ts">
import { RouterView } from 'vue-router'
</script>
<template>
<RouterView />
</template>
2.6 使用 vuex
在通过 create-vue
创建的项目没有使用 vuex
而是使用了Pinia
,根据大部分人的习惯,我们这边还是对原来的项目进行改造一下。
首先,我们安装 vuex
到项目中
# npm
$ npm i -S vuex
# yarn
$ yarn add vuex
# pnpm
$ pnpm i -S vuex
安装完成之后,我们在主入口 main.ts
中引入。同时,去掉 Pinia
。
// main.ts
import store from '@/stores'
// ...
app.use(store)
文件 stores/index.ts
的内容为
// stores/index.ts
import { createStore } from 'vuex'
import getters from './getters'
const modulesFiles: any = import.meta.globEager('./modules/*.ts')
const modules = Object.keys(modulesFiles).reduce((modules: Record<string, any>, modulePath: string) => {
const moduleName = modulePath.replace(/^./(.*).\w+$/, '$1')
modules[moduleName] = modulesFiles[modulePath].default
return modules
}, {})
export default createStore({
getters,
modules,
})
stores/getters.ts
的内容为
// stores/getters.ts
export default {
// TODO
}
然后目录结构为下面这张图展示
注意在这边 index.ts 文件中会存在 类型“NodeReuire”上不存在属性“context”
的报错,这里我们需要使用import.meta.globEager
的方式去写
改造后的 stores/index.ts
文件如下
// stores/index.ts
import { createStore } from 'vuex'
import getters from './getters'
const modulesFiles: any = import.meta.globEager('./modules/*.ts')
const modules = Object.keys(modulesFiles).reduce((modules: Record<string, any>, modulePath: string) => {
const moduleName = modulePath.replace(/^./(.*).\w+$/, '$1').replace('modules/', '')
modules[moduleName] = modulesFiles[modulePath].default
return modules
}, {})
export default createStore({
getters,
modules,
})
改造完成之后,我们需要测试一下这样的设计是否有用,所以我们需要在 stores/modules
下面新建 user.ts
,文件内容如下:
// stores/modules/user.ts
import type { ActionContext } from 'vuex'
export interface IUser {
name: string;
}
const state = {
name: '杨洋',
}
const mutations = {
SER_NAME: (state: IUser, name: string) => {
state.name = name
}
}
const actions = {
changeName(context: ActionContext<IUser, any>, name: string) {
context.commit('SER_NAME', name)
},
}
export default {
namespace: true,
state,
mutations,
actions,
}
stores/getters.ts
进行改造
// stores/getters.ts
import type { IUser } from "./modules/user"
export default {
name: (state: Record<'user', IUser>) => state.user.name
}
然后,在个人信息界面去使用
// src/user/basic/index.vue
<script lang="ts">
import { computed } from 'vue'
import { useStore, } from 'vuex'
export default {
name: 'Basic',
setup () {
const store = useStore()
const name = computed(() => store.state.user.name)
return {
name,
changeName () {
store.commit('SER_NAME', 'commit 开发杨洋')
},
changeDispatchName () {
store.dispatch('changeName', 'dispatch 开发杨洋')
}
}
}
}
</script>
<template>
<h1>个人信息</h1>
<div>
<!-- 展示具体的个人信息 -->
{{ name }}
<button @click="changeName">commit 方式修改个人信息</button>
<button @click="changeDispatchName">dipatch 方式修改个人信息</button>
</div>
</template>
界面展示如图所示:
2.7 使用 axios 调用外部数据
Axios
是基于 Promise 的 HTTP 客户端,用于 node.js 和浏览器。
我们的网页肯定不是静态网站,所以我们需要跟外界,比如跟服务器进行交互,由此我们需要在项目中使用 axios
。
在我们网站中通过 npm
安装 axios
# npm
$ npm i -S axios
# yarn
$ yarn add axios
# pnpm
$ pnpm i -S axios
安装完成之后,我们在 utils
目录下面新建文件 request.ts
文件。文件内容如下:
// utils/request.ts
import axios from 'axios'
const service = axios.create({
baseURL: '', // url = basic url + request url
timeout: 5000, // 请求超时时间设定,超过时间限制,自动认为请求失败
})
// 请求拦截器
service.interceptors.request.use(
config => {
// 在发送请求的过程中,需要验证当前的 Token 或其他相关权限校验
return config
},
error => {
console.error(error)
return Promise.reject(error)
}
)
// 相应拦截器
service.interceptors.response.use(
response => {
const res = response.data
// 在这里根据不同的返回 code 去做不同的逻辑判断
return res
},
error => {
console.error(error)
return Promise.reject(error)
}
)
export default service
代码使用
// src/user/basic/index.vue
<script lang="ts">
import { computed } from 'vue'
import { useStore, } from 'vuex'
import request from '@/utils/request'
export default {
name: 'Basic',
setup () {
const store = useStore()
const name = computed(() => store.state.user.name)
// 请求接口
request.get('http://www.baidu.com').then(res => {
console.log('得到的数据', res)
})
return {
name,
changeName () {
store.commit('SER_NAME', 'commit 开发杨洋')
},
changeDispatchName () {
store.dispatch('changeName', 'dispatch 开发杨洋')
}
}
}
}
</script>
2.8 集成 Element Plus 绘制基础界面
现阶段用的组件库比较流行的是 Element Plus
。官网地址: https://element-plus.org/zh-CN/
在项目中安装并使用:
# 选择一个你喜欢的包管理器
# NPM
$ npm install element-plus --save
# Yarn
$ yarn add element-plus
# pnpm
$ pnpm install element-plus
在 main.ts
中引入
// main.ts
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// ...
app.use(ElementPlus)
// ...
改造一下基础信息界面
// src/user/basic/index.vue
<script lang="ts">
import { computed } from 'vue'
import { useStore, } from 'vuex'
export default {
name: 'Basic',
setup () {
const store = useStore()
const name = computed(() => store.state.user.name)
return {
name,
changeName () {
store.commit('SER_NAME', 'commit 开发杨洋')
},
changeDispatchName () {
store.dispatch('changeName', 'dispatch 开发杨洋')
}
}
}
}
</script>
<template>
<h1>个人信息</h1>
<div>
<!-- 展示具体的个人信息 -->
{{ name }}
<el-button type="primary" @click="changeName">commit 方式修改个人信息</el-button>
<el-button type="success" @click="changeDispatchName">dipatch 方式修改个人信息</el-button>
</div>
</template>
3. 总结
大体的界面代码目录结构和基础代码都写完了,如有不对的地方,请指出,谢谢🙏
暂无评论内容