做电力产品的外贸网站,吉林省建设厅网站查询,成都哪里好玩好吃,浏览器谷歌手机版下载pnpm介绍安装
本质上他是一个包管理工具#xff0c;和npm/yarn没有区别#xff0c;主要优势在于
包安装速度极快磁盘空间利用效率高
安装#xff1a;
npm i pnpm -g使用#xff1a;
npm命令pnpm等效npm installpnpm installnpm i axiospnpm add axiosnpm i webpa…pnpm介绍安装
本质上他是一个包管理工具和npm/yarn没有区别主要优势在于
包安装速度极快磁盘空间利用效率高
安装
npm i pnpm -g使用
npm命令pnpm等效npm installpnpm installnpm i axiospnpm add axiosnpm i webpack -Dpnpm add webpack -Dnpm run devpnpm dev
小结
pnpm 是一个高效的包管理工具使用和npm和yarn基本相同
1、项目创建
使用 create-vue 脚手架创建项目 create-vue即官方的项目脚手架工具提供了搭建基于 Vite且 TypeScript 就绪的 Vue 项目的选项。 步骤
执行创建命令
pnpm create vue
# or
npm init vuelatest
# or
yarn create vue选择项目依赖内容
✔ Project name: … patients-h5-100
✔ Add TypeScript? … No / Yes
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes
✔ Add Pinia for state management? … No / Yes
✔ Add Vitest for Unit Testing? … No / Yes
✔ Add Cypress for both Unit and End-to-End testing? … No / Yes
✔ Add ESLint for code quality? … No / Yes
✔ Add Prettier for code formatting? … No / YesScaffolding project in /Users/zhousg/Desktop/patient-h5-100...Done. Now run:cd patient-h5-100pnpm installpnpm lintpnpm dev2、项目准备工作
vscode插件安装 安装项目开发需要的一些插件 必装
Vue Language Features (Volar) 语法高亮代码提示 volar支持setup语法糖官方推荐vue3使用TypeScript Vue Plugin (Volar) vvue3中更好的ts提示, 让Ts服务知道.vue文件Eslint 代码风格校验 注意 vscode 安装了 Prettier 插件的可以先 禁用或者关闭保存自动格式化功能避免和项目的 Eslint 风格冲突。Volar为vue3开发vetur主要是vue2Volar和vetur不能共存 可选
gitLens 代码git提交记录提示json2ts json自动转ts类型Error Lens 行内错误提示
提示
大中型项目建议开启 TS托管模式 , 更好更快的类型提示。 更高效的开启TS托管模式 Take Over Mode(托管模式)TS服务性能更好 什么是托管模式vscode内置了一套ts服务volar也提供了一套ts服务所以需要开启托管模式让ts性能提示更加高效只需要下面两步即可1.关闭vscode内置的TS服务2.使用Volar提供的TS服务 vscode 插件中搜索 builtin ty在当前工作区禁用ts服务后重启vscode即可。 查看ts已托管成功重启后vscode工具栏下方有这个提示即可 这里就相当于告诉vscode,你不需要提供ts服务了我找个人(volar插件)来替你服务即所谓的托管。 eslint 预制配置
.eslintrc.cjs文件 加入如下配置覆盖原有的eslint配置 rules: {prettier/prettier: [warn,{singleQuote: true,//单引号semi: false,//没有分号printWidth: 80,//行宽度80字符trailingComma: none,//没有对象数组最后一个逗号endOfLine: auto//换行字符串自动系统不一样换行符号不一样}],//新手在组件命名的时候不够规范根据官方风格指南除了根组件App.vue外// 自定义组件名称应该由多单词组成防止和html标签冲突。vue/multi-word-component-names: [warn,{ignores: [index]}],// 允许对 props 进行解构vue/no-setup-props-destructure: [off],// 添加未定义变量错误提示no-undef: error}
格式单引号没有分号行宽度80字符没有对象数组最后一个逗号换行字符串自动系统不一样换行符号不一样vue 组件需要大驼峰命名除去 index 之外App 是默认支持的允许对 props 进行解构我们会开启解构保持响应式的语法糖
执行
# 修复格式
pnpm lintvscode 开启 eslint 自动修复 editor.codeActionsOnSave: {source.fixAll: true,},提示安装Eslint且配置保存修复不要开启默认的自动保存格式化
代码检查工作流
提交代码前做代码检查 -使用husky这个git hooks工具(husky相当于是git的钩子)
husky [ˈhʌski] 哈士奇
eslint只能修复代码的风格不能修复代码的错误此时提交代码比较危险
怎么做安装husky工具这个工具是在commit提交文件之前检查代码是否有问题的和git一起用 初始化git仓库执行git init即可 初始化husky工具配置执行 pnpm dlx husky-init pnpm install修改 .husky/pre-commit 文件,添加pnpm lint 这个命令 pnpm lint是全量检查突然添加就会有耗时问题和检查历史遗留问题所以最好只检查修改的文件在暂存区做lint校验git add .的时候把文件提交到了暂存区在commit命令之前去执行 如何只检查暂存区代码 安装lint-staged包 pnpm i lint-staged -D配置 package.json {// ... 省略 ...lint-staged: {*.{js,ts,vue}: [eslint --fix]}
}{scripts: {// ... 省略 ...lint-staged: lint-staged}
}修改 .husky/pre-commit 文件 pnpm lint-staged图示 项目结构调整 了解每一个目录结构的作用 ./src├── assets 静态资源图片...├── components 通用组件├── composables 组合功能通用函数├── icons svg图标├── router 路由│ └── index.ts├── services 接口服务API├── stores 状态仓库├── styles 样式│ └── main.scss├── types TS类型├── utils 工具函数├── views 页面├── main.ts 入口文件└──App.vue 根组件assets, components, stores, views 清空文件夹 composables, icons, services, styles/main.scss, types, utils 新建文件夹 router/index.ts, main.ts, App.vue 修改 router/index.ts import { createRouter, createWebHistory } from vue-routerconst router createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: []
})export default routermain.ts import { createApp } from vue
import { createPinia } from piniaimport App from ./App.vue
import router from ./router//导入新创建的全局样式文件
import ./styles/main.scssconst app createApp(App)app.use(createPinia())
app.use(router)app.mount(#app)App.vue script setup langts/scripttemplatedivApp/div
/templatestyle scoped/style项目使用sass预处理器安装sass即可支持scss语法
pnpm add sass -D导入 main.ts 作为全局样式
import ./styles/main.scss路由代码解析
import { createRouter, createWebHistory } from vue-router// createRouter 创建路由实例 new VueRouter()
// history 是路由模式hash模式history模式
// createWebHistory() 是开启history模块 http://xxx/user
// createWebHashHistory() 是开启hash模式 http://xxx/#/user// vite 的配置 import.meta.env.BASE_URL 是路由的基准地址默认是 ’/‘
// https://vitejs.dev/guide/build.html#public-base-path
// 如果将来你部署的域名路径是http://xxx/my-path/user
// vite.config.ts 添加配置 base: my-path路由这就会加上 my-path 前缀了const router createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: []
})export default router创建路由实例由 createRouter 实现路由模式 history 模式使用 createWebHistory()hash 模式使用 createWebHashHistory()参数是基础路径默认/
扩展import.meta.env.BASE_URL
import.meta 是 JavaScript 模块暴露的描述模块的信息对象 env.BASE_URL 是Vite 环境变量 3、移动端项目基础架构要做的工作 4、构建界面
vant组件库
文档
安装
# Vue 3 项目安装最新版 Vant
npm i vant
# 通过 yarn 安装
yarn add vant
# 通过 pnpm 安装
pnpm add vant引入组件 - vant 自动引入组件并按需引入组件的样式 在基于 vite、webpack 或 vue-cli 的项目中使用 Vant 时可以使用 unplugin-vue-components 插件它可以自动引入组件。 Vant 官方基于 unplugin-vue-components 提供了自动导入样式的解析器 vant/auto-import-resolver两者可以配合使用。 安装插件 # 通过 npm 安装
npm i vant/auto-import-resolver unplugin-vue-components -D# 通过 yarn 安装
yarn add vant/auto-import-resolver unplugin-vue-components -D# 通过 pnpm 安装
pnpm add vant/auto-import-resolver unplugin-vue-components -D# 通过 bun 安装
bun add vant/auto-import-resolver unplugin-vue-components -D配置插件 如果是基于 vite 的项目在 vite.config.js 文件中配置插件 import vue from vitejs/plugin-vue;
import Components from unplugin-vue-components/vite;
import { VantResolver } from vant/auto-import-resolver;export default {plugins: [vue(),Components({resolvers: [VantResolver()],}),],
};使用组件 templatevan-button typeprimary /
/template引入函数组件的样式 Vant 中有个别组件是以函数的形式提供的包括 ToastDialogNotify 和 ImagePreview 组件。在使用函数组件时unplugin-vue-components 无法解析自动注册组件导致 vant/auto-import-resolver 无法解析样式因此需要手动引入样式。 // Toast
import { showToast } from vant;
import vant/es/toast/style;// Dialog
import { showDialog } from vant;
import vant/es/dialog/style;// Notify
import { showNotify } from vant;
import vant/es/notify/style;// ImagePreview
import { showImagePreview } from vant;
import vant/es/image-preview/style;移动端适配 实现使用 vw 完成移动端适配 文档
安装
npm install postcss-px-to-viewport -D
# or
yarn add -D postcss-px-to-viewport
# or
pnpm add -D postcss-px-to-viewport配置 postcss.config.js
// eslint-disable-next-line no-undef
module.exports {plugins: {postcss-px-to-viewport: {// 设备宽度375计算vw的值viewportWidth: 375,},},
};测试 有一个控制台警告可忽略或者使用 postcss-px-to-viewport-8-plugin 代替当前插件
css变量主题定制 实现使用css变量定制项目主题和修改vant主题 官方文档 全局变量使用场景项目主题 :root {/* 全局css变量 */--main: #999;--cp-primary: #16C2A3;/* 覆盖vant主体色 */--van-primary-color: var(--cp-primary);
}a {/* 使用变量 */color: var(--main)
}局部变量使用场景组件变量 .footer {/* 局部变量 */--footer-color: green;
}.footer {/* 只能在footer下使用 */color: var(--footer-color);
}如何覆盖vant的主题色找到主题色的变量名覆盖即可 styles/main.scss 注意为什么要写两个重复的 :root 由于 vant 中的主题变量也是在 :root 下声明的所以在有些情况下会由于优先级的问题无法成功覆盖。通过 :root:root 可以显式地让你所写内容的优先级更高一些从而确保主题变量的成功覆盖。 :root:root {// 问诊患者色板--cp-primary: #16C2A3;--cp-plain: #EAF8F6;--cp-orange: #FCA21C;--cp-text1: #121826;--cp-text2: #3C3E42;--cp-text3: #6F6F6F;--cp-tag: #848484;--cp-dark: #979797;--cp-tip: #C3C3C5;--cp-disable: #D9DBDE;--cp-line: #EDEDED;--cp-bg: #F6F7F9;--cp-price: #EB5757;// 覆盖vant主题色--van-primary-color: var(--cp-primary);
}App.vue script setup langts/scripttemplate!-- 验证vant颜色被覆盖 --van-button typeprimary按钮/van-buttona href#123/a
/templatestyle scoped langscss
// 使用 css 变量
a {color: var(--cp-primary);
}
/style补充内容 1、css变量 有的网站都会有自己的主题色例如饿了么 所以很多元素都会用到这些颜色例如某些字体颜色弹框提示颜色等等。 如果每次用到的时候都使用十六进制的颜色表示那么效率十分低并且如果万一有一天需要更换主题颜色那么一个一个更改是十分繁琐的。 为了解决以上问题css引入了变量。 var() 函数用于插入 CSS 变量的值。全局变量可以在整个文档进行访问使用局部变量只能在声明它的选择器内部使用。 例如 /* 全局变量 */:root {--main-color: red;}/* 局部变量 */.footer {--footer-color: green;}:root声明的是全局变量如果是一个自定义属性用 -- 作为前缀使用时比如: var(–main-color)就和red相等。 好处: 可维护性 如果没有CSS变量需要手动改变大量的属性值使用批量处理查找和替换可能会影响其他样式规则。使用CSS变量只用改变定义时的值。提高CSS可读性 可以通过变量名判断属性内容 注意事项使用CSS变量要注意大小写敏感不要把长度的变量用于颜色属性等。 2、实例 !DOCTYPE html
html langenheadmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/titlestyle/* 全局变量可以在整个文档进行访问使用 */:root {--main-color: red;}/* 局部变量只能在声明它的选择器内部使用 */.footer {--footer-color: green;}.main {color: var(--main-color); /* √ 生效 */background-color: var(--footer-color); /* × 不生效 */}.footer {color: var(--main-color); /* √ 生效 */background-color: var(--footer-color); /* √ 生效 */}/style
/headbodydiv classmainmain/divbr /div classfooterfooter/div
/body/html5、状态管理
用户状态仓库 完成用户信息仓库创建提供用户信息修改用信息删除用户信息的方法 请求工具需要携带token访问权限控制需要token所以用户信息仓库先完成
需求
用户信息仓库创建提供用户信息修改用信息的方法删除用信息的方法 代码
types/user.d.ts
// 用户信息
export type User {// token令牌token: string// 用户IDid: string// 用户名称account: string// 手机号mobile: string// 头像avatar: string
}stores/user.ts
import { ref } from vue
import { defineStore } from pinia
import type { User } from /types/userexport const useUserStore defineStore(cp-user, () {// 1.用户信息状态const user refUser()// 2.设置用户信息函数const setUser (u: User) {user.value u}// 3.删除用户信息的函数const delUser () {user.value undefined}return {user,setUser,delUser}
})
测试App.vue
script setup langts
import { useUserStore } from /stores/user
import type { User } from ./types/userconst store useUserStore()const login () {const user: User {token: xxx,id: 1,account: xxx,mobile: xxx,avatar: xxx}store.setUser(user)
}
const logout () {store.delUser()
}
/scripttemplatediv{{ store.user }}van-button typeprimary clicklogin登录/van-buttonvan-button typeprimary clicklogout退出/van-button/div
/templatestyle scoped langscss/style
小结
pinia存储这个数据的意义 数据共享提供给项目中任何位置使用 如果存储了数据刷新页面后数据还在吗 不在现在仅仅是js内存中需要进行本地存储持久化
数据持久化 掌握使用 pinia-plugin-persistedstate 实现pinia仓库状态持久化且完成测试 参考文档 安装 pnpm i pinia-plugin-persistedstate
# or
npm i pinia-plugin-persistedstate
# or
yarn add pinia-plugin-persistedstatemain.ts import persist from pinia-plugin-persistedstate
const app createApp(App)app.use(createPinia().use(persist))配置 stores/user.ts import { ref } from vue
import { defineStore } from pinia
import type { User } from /types/userexport const useUserStore defineStore(cp-user,() {// 1.用户信息状态const user refUser()// 2.设置用户信息函数const setUser (u: User) {user.value u}// 3.删除用户信息的函数const delUser () {user.value undefined}return {user,setUser,delUser}},{// 开启本地持久化persist: true}
)测试 App.vue script setup langts
import { useUserStore } from /stores/user
import type { User } from ./types/userconst store useUserStore()const login () {const user: User {token: xxx,id: 1,account: xxx,mobile: xxx,avatar: xxx}store.setUser(user)
}
const logout () {store.delUser()
}
/scripttemplatediv{{ store.user }}van-button typeprimary clicklogin登录/van-buttonvan-button typeprimary clicklogout退出/van-button/div
/templatestyle scoped langscss/style
stores统一导出
如何统一管理? pinia 独立维护 现在初始化代码在 main.ts 中仓库代码在 stores中代码分散职能不单一 优化由 stores 统一维护在 stores/index.ts 中完成 pinia 初始化交付 main.ts 使用 仓库 统一导出 现在使用一个仓库 import { useUserStore } from ./stores/user.ts 不同仓库路径不一致 优化由 stores/index.ts 统一导出导入路径统一 ./stores而且仓库维护在 stores/modules 中
抽取pinia实例代码职能单一
stores/index
import { createPinia } from pinia
import persist from pinia-plugin-persistedstate// 创建pinia实例
const pinia createPinia()
// 使用pinia插件
pinia.use(persist)
// 导出pinia实例给main使用
export default piniamain.ts
import { createApp } from vue
import pinia from ./stores
import App from ./App.vue
import router from ./router
import ./styles/main.scssconst app createApp(App)app.use(pinia)
app.use(router)
app.mount(#app)统一导出代码简洁入口唯一
stores/index
import { createPinia } from pinia
import persist from pinia-plugin-persistedstate// 创建pinia实例
const pinia createPinia()
// 使用pinia插件
pinia.use(persist)
// 导出pinia实例给main使用
export default pinia// import { useUserStore } from ./modules/user
// export { useUserStore }
export * from ./modules/userApp.vue
-import { useUserStore } from ./stores/user
import { useUserStore } from ./stores6、数据交互
请求工具 axios配置
创建axios实例 基准地址超时时间 请求拦截器 携带 token 响应拦截器 业务失败处理摘取核心响应数据401处理 业务失败处理摘取核心响应数据
业务失败处理
如何判断业务失败code 不是 10000失败后需要做什么弹出轻提示此时返回一个失败的 promise传递code给catch
摘取核心响应数据
现在结果 { data: 响应数据 }期望结果 响应数据 响应失败-token无效401处理 代码 实现token请求头携带错误响应处理摘取核心响应数据, 401错误处理 utils/request.ts
模板代码
import axios from axiosconst instance axios.create({// TODO 1. 基础地址超时时间
})instance.interceptors.request.use((config) {// TODO 2. 携带tokenreturn config},(err) Promise.reject(err)
)instance.interceptors.response.use((res) {// TODO 3. 处理业务失败// TODO 4. 摘取核心响应数据return res},(err) {// TODO 5. 处理401错误return Promise.reject(err)}
)export default instance代码实现
import { useUserStore } from /stores
import axios, { AxiosError } from axios
import router from /router
import { showToast } from vant
import vant/es/toast/styleconst instance axios.create({// 1. 基础地址超时时间baseURL: https://consult-api.itheima.net/,timeout: 10000
})instance.interceptors.request.use((config) {// 2. 携带tokenconst store useUserStore()if (store.user?.token config.headers) {config.headers.Authorization Bearer ${store.user.token}}return config},(err) Promise.reject(err)
)instance.interceptors.response.use((res) {// 3. 处理业务失败// 后台约定响应成功但是code不是10000是业务逻辑失败if (res.data.code ! 10000) {// 错误提示showToast(res.data.message || 业务失败)// 返回错误的promise// 传入code将来catch的时候可以使用(res.data包含code)return Promise.reject(res.data)}// 4. 摘取核心响应数据return res.data},(err: AxiosError) {// 5. 处理401错误if (err.response?.status 401) {// 删除用户信息const store useUserStore()store.delUser()// 跳转登录带上接口失效所在页面的地址登录完成后回跳使用router.push({path: /login,query: { returnUrl: router.currentRoute.value.fullPath }})}return Promise.reject(err)}
)export default instance请求函数
函数封装 简化传参逻辑 添加类型 设置响应数据类型 扩展为什么使用axios.request()泛型第二个参数 代码 实现导出一个通用的请求工具函数支持设置响应数据类型 utils/request.ts
import { useUserStore } from /stores
import axios, { AxiosError, type Method } from axios
import router from /router
import { showToast } from vant
import vant/es/toast/styleconst instance axios.create({// 1. 基础地址超时时间baseURL: https://consult-api.itheima.net/,timeout: 10000
})instance.interceptors.request.use((config) {// 2. 携带tokenconst store useUserStore()if (store.user?.token config.headers) {config.headers.Authorization Bearer ${store.user.token}}return config},(err) Promise.reject(err)
)instance.interceptors.response.use((res) {// 3. 处理业务失败// 后台约定响应成功但是code不是10000是业务逻辑失败if (res.data.code ! 10000) {// 错误提示showToast(res.data.message || 业务失败)// 返回错误的promise// 传入code将来catch的时候可以使用(res.data包含code)return Promise.reject(res.data)}// 4. 摘取核心响应数据return res.data},(err: AxiosError) {// 5. 处理401错误if (err.response?.status 401) {// 删除用户信息const store useUserStore()store.delUser()// 跳转登录带上接口失效所在页面的地址登录完成后回跳使用router.push({path: /login,query: { returnUrl: router.currentRoute.value.fullPath }})}return Promise.reject(err)}
)export default instance// 请求工具函数
type DataT {code: numbermessage: stringdata: T
}
export const request T(url: string,method: Method GET,submitData?: object
) {// 参数地址请求方式提交的数据// 返回promisereturn instance.requestany, DataT({url,method,[method.toUpperCase() GET ? params : data]: submitData})
}测试
script setup langts
import { request } from /utils/request
import type { User } from ./types/user
import { useUserStore } from ./storesconst store useUserStore()
const login async () {const res await requestUser(/login/password, POST, {mobile: 13211112222,password: abc12345})store.setUser(res.data)
}
/scripttemplatevan-button typeprimary clicklogin登录/van-button
/template