# 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**