# yiliao_95
**Repository Path**: errlei/yiliao_95
## Basic Information
- **Project Name**: yiliao_95
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 0
- **Created**: 2023-12-31
- **Last Updated**: 2025-02-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## 1. 公司项目开发流程
公司项目开发流程?你们公司开发的人员组织情况?
运维(我们是阿里巴巴公司,我现在给天猫app增量一个元旦的活动功能。首先有多个多家的版本多种语言,在北京/武汉/成都/上海/广东等 都有服务器。 需要把我们开发的代码部署到不同的服务器里面去)
项目(产品)经理 ---> 技术总监(前端组长,后端java组长,运维,UI,测试)
产品需求会 ---- 项目经理带着各个团队的人员,开会,拿出来他准备好的 "原型图“, 前端和后端格提出自己的意见,原型图里面有什么需要改动的或者不合理的
这个会开完以后,就会确定产品的一些时间。 UI设计图给前端的时间,前后端联调时间, 测试的时间,UAT上线的前一步验证的时间, 上线的时间
前端组长就会安排团队的3个人负责这个项目, 怎么样创建项目,怎么样确定分支模型,每个人负责什么模块。 后面具体的人就和UI小姐姐对接,他的ui设计稿写完了我们就可以吧静态页面完成
静态页面写完了以后,问后端当前页面的接口写完了没有,如果没有写完,可以使用mock假数据发请求,完成页面。等到了前后端联调,在换个接口地址就可以了
接口联调完毕以后,在交给测试去测试,有bug就去 jira平台 自己找自己的bug,改完了再让他测
都测试了没问题,发uat邮件,给产品经理验收
验收没问题,就找一个晚上的用我们系统没什么人的时间 上线
1.1开会 --- 1.16联调 --- 1.19联调结束,交给测试 --- 1.24测试完毕 ---> 1.26上线
## 2. npm yarn pnpm的区别
他们都是下载npm包的,安装依赖
npm ---- 下载node,安装以后,电脑自动就有npm --- 还需要在家目录里面设置 .npmrc
yarn ---- npm install yarn -g yarn工具是npm下载的,---也要在家目录里面设置.yarnrc
pnpm ---- npm install pnpm -g pnpm也是npm下载
如果要下载一个axios包
npm i axios
yarn add axios
pnpm i axios
看网站质量排名 (国内)
掘金 ---> 思否segmentfort ---> 博客园 ---> CSDN ---> 知乎 --> 简书
谷歌 ---> bing搜索 ---> 百度
npm 5 之前下载包的时候,没有lock文件。同一个项目不同的电脑可能安装的包不一样。 facebook开源了yarn工具,自带有lock文件,保证不同的电脑不同的环境,下载统一项目所有的包版本和地址都一样。速度也必npm快
npm5版本以后,增加了lock。 基本上工作里面npm yarn 都可以用
pnpm也是包管理工具,后面发明的,主要是解决了 node_modules 磁盘占用空间的问题。 核心本质就是通过 硬链接的形式,链接到特殊的地方去找对应的包,不要每个项目下载 相同的包
## 3. import与export混合使用
`export * from './user' // export * 叫统一导出,他的文档在阮一峰的 es6文档里面找 https://es6.ruanyifeng.com/`
```
// 默认导出一个文件只能有一个
export default pinia
// 按需导出一个文件可以有多个
// https://es6.ruanyifeng.com/
export * from './user'
// export * from './A'
// export * from './B'
// export * from './C'
// export * from './D'
// export * from './E'
```
## 4. 二次三次封装axios
```
export default instance
export const request = (url: string, method: string, obj: any) => {
return instance.request({
url,
method,
// 动态的key,使用数组的中括号形式去写
[method.toUpperCase() === 'GET' ? 'params' : 'data']: obj
// data: obj,
// params: obj
})
}
```
## 5. vue3怎么自定义组件名称,组件名称的作用?
1. 再写一个script,用vue2的选项式写法添加name属性
2. 通过插件vite-plugin-vue-setup-extend
```javascript
pnpm install vite-plugin-vue-setup-extend
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
plugins: [
vue(),
Components({
resolvers: [VantResolver()]
}),
VueSetupExtend()
],
```
> 组件的name属性有什么用:
1.vue devtools查看组件 2.keep-alive组件缓存使用 3. 递归组件使用名称
## 6. vue深度选择器问题
添加了scoped以后,van的样式就不会生效,样式穿透的问题,涉及到深度选择器
修改vant-ui的样式,一般是两种方法:
1. 再写一个style标签,不写scoped属性, 在结合一个自定义的父类,实现私有化
```
```
2. 深度选择器的语法,有很多的变化,
```
// 在vue2里面 SASS/SCSS ::v-deep .main LESS /deep/ .main
// 在vue3里面 :deep(.main) {}
```
3. css less sass postcss的区别
less sass 前缀处理器, 比如写less sass的一些 函数 if else,经过sass或者less的 处理器,转换为css
postcss 是后置处理器,有了css文件以后,在结合postcss的一些插件 ,比如postcss-px-to-viewport 将css文件里面的px单位 转换为 vw vh 实现响应式。 还有一些postcss插件,专门给c3属性 添加不同浏览器的前缀 -- autoprefixer
```
-webkit-transform:rotate(-3deg); /*为Chrome/Safari*/
-moz-transform:rotate(-3deg); /*为Firefox*/
-ms-transform:rotate(-3deg); /*为IE*/
-o-transform:rotate(-3deg); /*为Opera*/
transform:rotate(-3deg);
我们工作里面 只用写transform:rotate(-3deg); ,但是postcss的插件autoprefixer,会自动识别一些css3的高级的语法,帮我们给所有浏览器加个兼容性的配置
在我们写vue2 vue3项目的时候,脚手架默认帮我们安装了这些插件,所以我们不用再去做了
```
## 7. vite工程里面使用svg自定义组件
## 8. 路由守卫
路由守卫(路由钩子函数)常用的有哪些?---- https://router.vuejs.org/zh/guide/advanced
钩子函数: 在特定的时机 自动执行的函数
1. 全局: 前置路由守卫,后置路由守卫
2. 路由独享的守卫 beforeEnter
3. 组件内的守卫 3个
```
router.beforeEach((to) => {
console.log('beforeEach钩子', to)
return true // 表示路由放行,类似于vue2的 next()
})
// 没有next函数,一般在这里面修改页面标题,统计 pv uv 数据等等
router.afterEach((to) => {
console.log('afterEach钩子', to)
})
```
```
{
path: '/home',
name: 'home',
beforeEnter: () => {
console.log('当前首页独享的路由守卫,beforeEnter')
},
component: () => import('@/views/Home/index.vue')
},
```
```
import { onBeforeRouteLeave } from 'vue-router'
// 注释法解决bug,就是之前写了什么代码导致的报错,里面注释掉再去看,将错误定位到某一行就可以了
// onBeforeRouteLeave(() => {
// console.log('组件内的钩子,离开组件, onBeforeRouteLeave')
// })
```
## 9. 前端和UI工作流程
1. 根据ui给的设计稿,1:1还原即可
1. 你们公司ui有的工具: figma, skech, 慕客, 墨刀
2. B端 C端 2B 2C ----- 2--two--to
1. business商业 前端来说一般是后台产品
2. customer 用户 前端来说一般的 拼多多,淘宝,京东 ------ UI检查就比较细致 --- ui走查 --上线前最后一步
3. p2p personal to personal 个人对个人
4. o2o online to offline 线上到线下
## 10 身份证号的正则匹配
```
普通替换
'abcedfg'.replace('abc', '') -------- edfg
正则替换, i表示不区分大小写 g表示全局匹配
'abacaeadafaaaag'.replace(/a/ig, '') -------- bcddfg
带有小括号的正则表示 分组匹配, 会自动在replace函数里面 新增多个变量 $1 $2 $3 一个括号多一个变量
表示匹配到的内容。 一般用来加密
33333333333.replace(/^(.{4}).+(.{4})$/, `$1**********$2`)
```
## 11. v-model绑定计算属性
默认就诊人的计算属性: checkbox组件需要的值是 true或者false; 但是后端需要的值是0 1
我们就是用可以修改的计算属性,get函数里面 同0 1 将计算属性改为 true false,在set里面,就是用户点击了checkbox复选框的时候,对计算属性有修改的地方,那么我们就将修改的true 和false,在又反转回 0 1 给后端使用
这个默认的业务一定要说清楚 页面上显示的内容true/false,和后端需要的内容0 1
核心的做法,就是通过可以修改的计算属性 get,set形式。 将v-model上面绑定一个计算属性
```
绑定ref的值,页面显示的值和后端需要的对不上
绑定计算属性的值,计算属性使用get set形式,get就给页面显示用,set就是设置后端数据使用
```
```
const defaultFlagCom = computed({
get() {
return formDetail.value.defaultFlag === 0 ? false : true
},
set(val) {
formDetail.value.defaultFlag = val ? 1 : 0
}
})
```
## 12. vue3里面v-model父子通信的简写
首先vue3没有sync语法,
之前vue2的语法:
vue2里面父子通信的简写 v-model sync。 他们俩的区别就是 v-model一个组件只能用一个,sync语法一个组件可以用多次
```
vue2的 v-model 和 sync简写的语法
```
vue3有区别? vue3废弃了 sync语法, v-model在vue3里面一个组件上也可以使用多次
```
这里是v-model在组件上只用一次的场景,子组件里面
const props: any = defineProps({
modelValue: String
})
const emits = defineEmits(['update:modelValue'])
抛出事件和数据
emits('update:modelValue', props.modelValue + '-')
```
```
这是一个组件上面使用多个 v-model 传值
const props: any = defineProps({
msg: String,
count: Number
})
const emits = defineEmits(['update:msg', 'update:count'])
抛出事件
emits('update:msg', props.msg + '-')
emits('update:count', props.count + 1)
```
## 13. 身份证号校验
## 14. 有没有封装过什么组件?
我工作里面经常封装各种组件,就是将UI给的设计稿一看,将一些页面公共的部分抽离出来,写成一个组件,然后将不同的地方通过 父子通信的方式向子组件传递数据,实现不同组件的定制化需求
我之前写简历上面的第一个项目的时候,是一个h5的项目,封装过个一个公共的顶部导航栏组件
1. 首先这个组件是二次封装的vant-ui组件库的组件,对于不同的页面进行定制化的配置
2. 在一些一级路由页面,导航栏的中间标题,左侧右侧文本,我写了3个属性传递给子组件,如果不传递就给这些值写个默认值,我还是通过vue3的 ts泛型写的传值
3. 这个组件左侧和右侧的部分可以点击,不同的页面点击效果不一样,然后我就将需要定制化的操作封装为一个函数,然后传递给子组件。也给这个函数写个默认值,如果用户传递了函数就是用用户的操作。 例如有些页面右上角是保存和编辑,有些页面使用的是 登录 注册等路由跳转时间。那我在事件处理函数里面,就先判断用户有没有传递函数,有就调用用户的函数没有传递就默认执行事件
## 15. vue3技术栈
vue3 vue-router pinia id-card @vueuse/core
## 16. @vueuse/core
这个包是我开发vue3项目必用的包,里面包含了非常多的实用工具hooks。让代码的封装和可复用性体现的非常全面。例如我之前要写一个resize事件,xxx
## 17. 自己封装一些hooks
我之前写过一个医疗项目,这个项目涉及到一个关注功能,我们的项目,针对于登录的用户,可以关注医生,关注百科文章,关注常见疾病,关注各种新闻等等。 就涉及到**代码逻辑的复用**, vue2有一种技术叫mixin,不是很好用。在vue3里面我们想要封装一些功能的逻辑代码,通常使用和react类似的hooks写法
我们这个关注业务,我是这么封装的:
我给hooks起了个名称useFollow 本质上是一个函数,接受动态的参数, 看我们这个hooks里面封装的函数,调用的时候需要什么参数就传递什么参数。我之前封装这个hooks就一个变量loading和一个发请求的函数follow。 然后在useFollow这个hooks函数里面 返回一个对象,里面有这两个属性。在任何页面想要实现关注的业务,只需要将useFollow调用一下,返回值使用对象解构就可以实现 **逻辑复用**
## 18. 魔法数字ENUM
一些看不懂的数字,如果没有写注释,后面读代码就很困难
ts--- enum 枚举
枚举就类似于 字面量类型 + 联合类型
创建枚举类型 --- 我们开发主要用枚举来解决 代码中魔法数字的问题
\1. 值的内容,默认从0开始,依次累加
\2. 手动改变值也可以, 改数字就是累加
\3. 手动改值是字符串就不累加了
```
export enum ConsultType {
// 找医生
Doctor = 1,
// 快速问诊
Fast,
// 开药问诊
Medication
}
等价于 1|2|3
123数字没有意义看不懂,所以推荐使用枚举类型
```
我之前在写一个医疗项目的时候,关于就诊类型,例如找医生,急速问诊,开药问诊 这三种类型,我们后端需要的值是123,但是这样代码里面就不利于后期维护。所以我使用了枚举类型,enum定义了很多有语义化的变量,来解决项目中的 这种魔法数字问题。大大方便了后期项目的维护
还有类似于看病时间 一周内,一月内 半年内 一年以上。性别男女 12等等。凡是后端需要使用1234这种数字类型的,我都会去使用 枚举定义。不过需要注意的是,枚举的ts会参数代码运行,需要卸载ts后缀文件里面,不能写在d.ts的后缀文件里面
## 19. 布局技巧
需求: 一个页面有上下布局,上面固定高度50,下面自动高度。 下面部分又有左右布局, 左边固定50,右边自动宽度?
2种方案:
1.. 给上面position:fixed 固定定义,当页面过长,滑动页面的时候,顶部就不会走。这个时候上下滑动页面,滚动条属于body,整个页面的滚动
2..给下面div设置一个固定高度`calc(100vh - 50px)` 这样的话,整个页面就不会出现滚动条,因为页面整体就只有100vh。 下面左右会自动出现滚动条
## 20. 有没有封装过组件?
我之前封装过一个自定义结构的复选框组件,
再最近写过的一个医疗项目里面,关于患者的性别,男女的选择。以及患者患病的时间,一周/一月/半年/一年等。还有是否就诊过等业务需求,我都是自己封装组件,将页面上要选择的 内容写成一个个小方块,点击div实现复选框的选择
主要涉及到的属性有 当前要渲染的数组列表list。双向绑定v-model语法糖绑定的后端需要的字段,以及不同页面显示不同结构的 showLeft字段等。 结合vue3 的ts泛型参数,和默认值定义好属性。完成对应结构的复用
## 21. import type 与 import区别
import type 后面导进来的内容 是类型,不能当做值来用
import 导入的可以当做值也可以当做类型
就拿枚举举例
```
// 是否就诊过
export enum Flag {
NoAttendance,
Attendance
}
1.
import { Flag } from '@/enums/index'
const a: Flag = 1 或者 const a: Flag = Flag.Attendance 两个写法都可以
// 冒号哪里是将枚举当做类型,来约束变量a。 等号后面是将枚举当做值来用
这就是将枚举当做类型类使用, 枚举类型等价于 字面量类型 + 联合类型
上面代码等价于 const a: 0|1 = 1
2.
import type { Flag } from '@/enums/index'
加上了type 表示导入进来的就是一个类型,不能当做值来使用
例如 const a = number 肯定报错, number是一个类型,是抽象的东西,是不能赋值的
对应枚举也是一样
const a = Flag.Attendance 也会报错。 类型是不能赋值的
所以枚举的导入不能加import type
其他的接口 泛型 函数 等类型可以用import type
```
## 22.计算属性的get set常用
经常和checkbox放在一起使用
前端读取值的时候,通过get函数 返回true false
后端java接口需要数字的时候,通过set函数,手动返回 0 1这种
复选项checkbox和单选框radio 语法糖 checked属性 + change事件
一般的表单输入框 input 语法糖就是 value + input 事件
```
这个是双向绑定的语法,是一个语法糖,是checked属性 + change事件
等价于
当然也可以不在一个组件上面写属性 + 事件,可以在多个元素上面写
```
## 23. 支付(支付宝与微信)
1. 支付宝支付的函数
我曾经在上一个项目里面对接过支付宝支付。测试的时候,我之前用支付宝的沙箱APP 或者 浏览器的支付宝页面都做过支付。对于我们前端来说,核心要准备的参数就是 订单编号 + 支付方式 + (支付成功以后)的回调页面的地址。 之前这个项目支付方式我们有 微信 支付宝 云闪付三种。 主要的对接的难点我觉得在后端哪里。前端只需要在生成订单以后,做一些校验工作即可
2. 小程序的支付
1.小程序支付先要登录获取token ---- wx.login (得到一个code值) wx.getUserInfo(获取4个参数) ---调公司自己java接口,生成token
2.小程序支付的核心 wx.requestPayment() --- 这个api学员5个参数 ---- 先调java接口 生成订单编号,---- 再调接口生成对应5个参数---- 最后在发起原生支付
```
// 下面这个请求是和我们的java接口通信,java再和支付宝 支付接口对接。 返回一个支付宝的支付连接地址即可
const res = await consultPayRequest({
paymentMethod: paymentMethod.value,
orderId: orderId.value,
// 支付宝支付成功以后,回来跳转的页面
payCallback: 'http://localhost:5173/#/room'
})
console.log(res)
// 请求成功以后,会返回一个支付宝的公网地址,需要使用BOM的location api手动跳过去
window.location.href = res.data.payUrl
```
## 24. 聊天室的UI界面
所谓的聊天室软件,就是将当前页面所有消息的格式,所有的div都写出来,然后在通过v-if结合消息的类型,有条件去展示。对于我们这个项目来说,一条消息就是一个room-message 组件
```
```
```
```
## 25. HTTP网络通信协议
计算机网络: 7层网络协议 ---- 4层网络
物理链路层 ---- TCP(打电话)、UDP(发短信)传输层协议 ---IP 网络层协议 --- 应用层(HTTP FTP POP3, websocket)
TCP的三次握手和四次挥手
HTTP协议: 前端发请求, 后端给响应
websocket协议: 前端可以给后端发, 后端也可以主动给前端发
针对于股票这种网站,数据需要实时的更新的。
还有针对多人聊天室的,有一个发消息,服务器就通知(广播)给所有进入直播间的家人,家人们都会受到对应的信息
## 26. 聊天简历上可写技术栈关键词
websocket socket.io @vueuse/core
聊天室使用websocet协议 写代码的基本步骤
socket.io 是一个工具包,前端和后端都需要安装使用这个包
前端使用的是 socket.io-client 这个包
和后端简历链接进行通信 有下面几个步骤
1. 创建socket实例const socket = io()
2. 建立连接成功 socket.on('connect', () => {})
3. 发消息给别人 socket.emit('自定义事件名称','数据')
4. 收消息 socket.on('自定义事件名称', (e)=> {})
5. 离开页面,关闭socket连接,节约服务器资源 socket.close()
**之前项目的重点**
之前在写医疗项目的时候,我和后端沟通以后,写了这么几个事件
1. **chatMsgList** 先在代码里面 socket.on() 监听这个事件,获取到之前的消息历史
2. 患者给医生发消息 **sendChatMsg** 事件; 医生端就监听这个事件
3. 患者可以接受别人的消息 **receivedChatMsg**事件; 医生端也可以监听这个事件
4. 还有一个获取消息是否读取状态的事件**updateMsgStatus**