用 create-vue 从 0 到 1 搭建一个后台管理系统

当前网站开发用到的是 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 规范目录结构

项目能正常运行之后,我们就需要在基础项目上,搭建一个完整的前端项目了。

稍微的改动一下目录结构,在原有的基础上增加了两个目录 utilsstyles。接下来我们具体列一下这几个目录的作用。

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现阶段分三种模式 createWebHistroycreateWebHashHistroycreateMemoryHistroy

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. 总结

大体的界面代码目录结构和基础代码都写完了,如有不对的地方,请指出,谢谢🙏

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容