pc
简介
此pc端基于nuxt3
前序准备
同管理后台,详见文档:前端
目录结构
├──📂 .nuxt # 开发模式下的产物
├──📂 .output # 打包构建的产物
├──📂 api # 所有请求
├──📂 assets # 静态资源(会经过构建工具构建)
├──📂 components # 全局公用组件
├──📂 composables # 全局可组合物(即hooks)
├──📂 constants # 静态数据
├──📂 enums # 全局枚举
├──📂 layouts # 基础布局
├──📂 middleware # 中间件
├──📂 nuxt # nuxt.config.ts辅助函数
├──📂 pages # 所有页面
├──📂 plugins # 插件安装
├──📂 public # 服务器根目录
├──📂 scripts # js脚本
├──📂 stores # 全局状态管理
├──📂 typings # ts声明文件
├──📂 utils # 全局公用方法
├── .env.xxx # 环境变量配置
├── .eslintrc.cjs # eslint 配置项
├── app.vue # 根组件
├── global.d.ts # 全局ts声明文件
├── nuxt.config.ts # nuxt配置文件
├── package.json # package.json
├── tailwind.config.js # tailwindcss 配置项
├── tsconfig.json # ts 配置项
快速上手
打开项目终端:使用vscode打开pc目录,在vscode左上角菜单中点击
终端
>新建终端
复制env文件
- 复制
.env.example
文件,将复制的文件名修改为.env
- 复制
.env.development.example
,将复制的文件名修改为.env.development
- 复制
.env.production.example
,将复制的文件名修改为.env.production
- 复制
打开
.env.development
文件,修改NUXT_API_URL
变量的值为项目安装部署的服务端地址
// env.development
# 请求域名
NUXT_API_URL=https://likeadmin.yixiangonline.com
安装依赖(仅需要安装一次)
在终端中运行命令npm install
编译运行 在终端中运行命令
npm run dev
项目上线
打包支持seo模式
和非seo模式
(类似于vue的单页面应用),默认为非seo模式
,修改.env
文件可以修改模式
# 是否开启ssr,填些任意值开启,为空则关闭
NUXT_SSR=1
打包前修改接口请求域名,打开.env.production
,修改NUXT_API_URL
变量的值为项目安装部署的服务端地址
// env.production
# 请求域名
NUXT_API_URL=
注意
如果是非seo模式则不需要修改,将NUXT_API_URL
留空即可,这样请求接口时会自动读取当前的域名做为接口请求的域名
seo模式
修改路由基础路径,默认基础路径为
/pc/
,修改为/
,打开.env
文件修改// env # 基础路径 NUXT_BASE_URL=/pc/
在终端中运行命令
npm run build
将打包好后,会自动将打包产物复制到
server/public/pc
下面, 只需要提交代码到服务器即可服务器部署
- 部署之前,如果服务器没有安装node,需要打开宝塔【软件商店】,搜索“node”,安装【Node.js版本管理器 1.6】。
- 打开【网站】-【node项目】-【添加node项目】,设置好项目目录、域名、项目端口(默认端口为3000)等参数,然后添加即可。
- 进入node项目设置,【服务状态】,手动启动项目。
提示
需要修改端口,或者其他部署,请参考文档
非seo模式
- 修改路由基础路径,默认基础路径为
/pc/
,如果不是请修改为/pc/
,打开.env
文件修改// env # 基础路径 NUXT_BASE_URL=/pc/
- 在终端中运行命令
npm run build
- 将打包好后,会自动将打包产物复制到
server/public/pc
下面,只需要提交代码到服务器即可
环境变量
公共环境
pc/.env
# 版本号
NUXT_VERSION=1.0
# 接口默认前缀
NUXT_API_PREFIX=/api
# 客户端类型
NUXT_CLIENT=4
# 基础路径
NUXT_BASE_URL=/
# 是否开启ssr,填些任意值开启,为空则关闭
NUXT_SSR=1
# 端口号
NITRO_PORT=1000
开发环境
pc/.env.production
# 请求域名
NUXT_API_URL=
生产环境
pc/.env.development
# 请求域名
NUXT_API_URL=
路由
页面
页面相关请看文档
如何拦截一个需要登录才能访问的页面
// pages/xxxvue
<script lang="ts" setup>
//...
definePageMeta({
auth: true
})
//...
</script>
接口请求
接口请求基于ohmyfetch
库进行二次封装,并重写了nuxt
的$fetch
函数,位于pc/utils/http
,并且将创建的实例注入到了全局,在任何一个地方只需要使用$request
即可发起请求
├──📂 http
│ ├── request.ts # 封装的请求实例
│ ├── index.ts # 接口返回统一处理及默认配置
一般只需要修改index.ts
文件,其他文件无需修改index.ts
文件说明:
默认配置
const defaultOptions: FetchOptions = {
// 基础接口地址
baseURL: getApiUrl(),
//请求头
headers: {
version: getVersion()
},
// 接口重试次数
retry: 2,
// 请求拦截
async onRequest({ options }) {
const { withToken } = options.requestOptions
const headers = options.headers || {}
// 添加token
if (withToken) {
const token = userStore.token
headers['token'] = token
}
options.headers = headers
},
//自定义的参数
requestOptions: {
//请求前缀
apiPrefix: getApiPrefix(),
// 需要对返回数据进行处理
isTransformResponse: true,
// 是否返回默认的响应
isReturnDefaultResponse: false,
// 是否携带token
withToken: true,
// 是否将params视为data参数,仅限post请求
isParamsToData: true,
// 请求拦截器
requestInterceptorsHook(options) {
console.log(options)
const { apiPrefix, isParamsToData } = options.requestOptions
// 拼接请求前缀
if (apiPrefix) {
options.url = `${apiPrefix}${options.url}`
}
const params = options.params || {}
// POST请求下如果无data,则将params视为data
if (
isParamsToData &&
!Reflect.has(options, 'body') &&
options.method?.toUpperCase() === RequestMethodsEnum.POST
) {
options.body = params
options.params = {}
}
return options
},
// 响应拦截器
async responseInterceptorsHook(response, options) {
const { isTransformResponse, isReturnDefaultResponse } =
options.requestOptions
//返回默认响应,当需要获取响应头及其他数据时可使用
if (isReturnDefaultResponse) {
return response
}
// 是否需要对数据进行处理
if (!isTransformResponse) {
return response._data
}
const { code, data, show, msg } = response._data
switch (code) {
case RequestCodeEnum.SUCCESS:
if (show) {
msg && feedback.msgSuccess(msg)
}
return data
case RequestCodeEnum.FAIL:
if (show) {
msg && feedback.msgError(msg)
}
return Promise.reject(data)
case RequestCodeEnum.LOGIN_FAILURE:
userStore.logout()
setPopupType(PopupTypeEnum.LOGIN)
toggleShowPopup(true)
return Promise.reject(data)
default:
return data
}
},
responseInterceptorsCatchHook(err) {
return err
}
}
}
如何在单个接口中单独使用这些配置
// 配置
export function xxxx(data) {
return $request.post({
url: 'xxx',
header: {
'Content-type': ContentTypeEnum.FORM_DATA
},
data
}, {
// 忽略重复请求
ignoreCancelToken: true,
// 开启请求超时重新发起请求请求机制
isOpenRetry: false,
// 需要对返回数据进行处理
isTransformResponse: false,
})
}
在页面中使用且服务端渲染请求数据
推荐使用useAsyncData搭配api函数,下面为首页的接口请求示例
//api/shop.ts
export function getIndex() {
return $request.get({ url: '/pc/index' })
}
//pages/index.vue
<script lang="ts" setup>
//...
import { getIndex } from '@/api/shop'
const { data: pageData } = await useAsyncData(() => getIndex(), {
default: () => ({
all: [],
hot: [],
new: [],
page: {}
})
})
//...
</script>
如果直接调用getIndex()
获取数据则会先获取到页面再调用接口数据