面试 场景题

编程知识 更新时间:2023-05-03 01:28:10

原则 :高内聚,低耦合
1如何封装一个组件
比如说二次封装一个react组件
1(如果是二次封装)复用React或第三方的类型声明,快速获得代码提示。(一般可以通过鼠标悬浮原始组件很快找到.d.ts的类型声明文件)同时对于自定义类型声明 如果特别重要或复杂的值需要添加方法注解 比如@param @example @return @description
2 隐藏内部结构是必须的。内部结构或实现细节不应该能被其他组件知道或关联。尽量做到黑盒组件。 最关键的一点就是通过一组 props来提供控制其行为的途径。
3 样式控制 一般来讲普通的组件 样式控制比较少 直接建立统一样式或者如果是复杂组件 会用props某一个属性去拼接className 或者使用策略模式去进行调用 用的比较多的一种就是主题 不同主题不同样式
4 首先你需要明确 你要实现怎么的一个组件 它具有怎么样的属性 哪些是要接受过来的属性 哪些是组件内部的属性
5 此外就一个不是特别简单的组件来说 后期可维护性也是要有 主要是一个拓展性。首先你封装完的组件可能有一些坑需要填 或者要另外加一些功能。不要有太多if else 尽量去通过策略模式去分类。
6 尽量将组件的属性 统一到对象管理,然后拓展运算法输出。避免组件 内容太长

2 比如pro table 二次 封装
1 首先需要明确就是这个组件需要哪些东西 一开始 通过后端接口直接调用数据,request (current+pageSize统一)(不需要写方法,直接传api或者api方法,此时需要后端参与接口返回约束性)非datasouce。 其中具有protable 所有属性(request 参数统一),和edittable可编辑切换。后续进行的拓展 1 通过第三方组件 可拖拽表头+记忆性表头 2双击 单个单元格可编辑表格。 可编辑表格适配所有下拉框+文本+时间选择器3 监听tabl切换visibilitychange 实现接口刷新 监听页面切换
1 .通过ant-design pro .d的类型声明 去为二次封装组件存在的原有方法属性进行一个类型声明,目的是为了后续代码提示方便。然后一遍写代码 一遍给类型声明
2 request 方法(自带参数pamas+查询参数+分页参数)
(1) 通过传入分页参数 动态设置分页 或者默认参数 [props.paginationfield?.pageSize || ‘pageSize’]: pageSize,
(2)通过传入自定义props额外参数 加入参数对象
(3)调用接口 需要统一res.code return succees +data+total
(4)同时还要支持自定义request 方法 重置就行
3 自定义rowSelection 一般来讲的话有2个属性 一个是selectrows selectkeyrows 主要是为了父组件可以获取这两个值 已经设置多选单选 等
4 此外需要配置一个props 主要是为实现 ant 组件其余的所有属性 这个直接拓展运算符,没啥好说的
5 拖拽+记忆性表头主要是拖过 表格名和拖拽属性 主要是通过component去实现一个重置表格 比如说重置表头header

table?: CustomizeComponent;
   header?: {
       wrapper?: CustomizeComponent;
       row?: CustomizeComponent;
       cell?: CustomizeComponent;
   };
   body?: CustomizeScrollBody<RecordType> | {
       wrapper?: CustomizeComponent;
       row?: CustomizeComponent;
       cell?: CustomizeComponent;
   };

(cell 单元格) 首先 这个属性 调用的方法 会接受很多参数 比如title dataIndex record 通过这些参数 以及第三方组件‘react-resizable’ 嵌套一层标签 一开始以为这样的确实现了一个拖拽功能 但实际 有很多的坑需要处理 第一点是监听table的clientWidth属性通过调用mutationObserver 防止自适应布局对它的干扰

 // 观察器的配置(需要观察什么变动)
    const config = { width: true, childList: true, subtree: true };
    // 当观察到变动时执行的回调函数
    const callback = function () {
      tableWidth.current = targetNode?.clientWidth || 0;
      setTableContainerWidth(targetNode?.clientWidth || 0);
    };
    const observer = new MutationObserver(callback);
    if (targetNode) {
      observer.observe(targetNode, config);
    }

其次useEffect去依赖这个监听出来的tableContainerWidth和columns
需要区分(1 隐藏列去除2记录列宽总和设计到一个横向滚动3复选框不涉及宽度)遍历column 区分隐藏 百分比宽 固定px宽 ,还有一个就是没有设置宽度,那么去平分剩余宽度得到一个total和一个总的宽度 此时新的column 已经获得了。 拖拽的时候需要监听mouseup事件 去保存。此外cloumn需要添加onHeaderCell属性 已经设置好第三方组件cresize调用方法。这个方法去获取,第三方组件获取的width,然后返回最新的cloumn已经scroll的长度 方便component 调用时 直接获取这个函数。另外就是宽度 要设置成计算后的

此外查找所有拖拽图标添加阻止冒泡 (拖拽和排序会冲突)

每一次修改表头 通过表格tablename 去调用接口保存 字段的width 每次初始化的时候重置column

最后就是cell 单元格 双击可直接编辑 文本 也是component 里面的body属性去重置cell单元格 重置成form 表单+表单项 这里主要就是针对元数据进行不同的表单项展示 本质就是单元格的重置 如果是默认情况 直接返回一个正常div 里面输出children占位符。 其实这一类在ant-d 官方文档有介绍 复杂的点在于 动态表头数据后端传过来 去搞他是什么类型

4 重构查看原文组件+各类型优化 PDF 给类型图片 tiff
原组件存在的问题 一千多行代码 因为业务问题和不同研发的问题写3个组件 太复杂了 各种不同的类型原文查看通过各种状态去显示 另外还有就是传参 每一个地方都不统一 单文件查看多文件查看 原文接口方式各不相同。另外就是因为这些不同 有多个原文查看组件用在不同的地方 去实现一个统一管理。此外的像接口+其他文件查看自定义的方法都需要设置一个exter***方法传入,便于实现其他方法
1 将各类型显示原文 部分独立出去 一个组件 左侧各类型文件名 预览显示的独立 右侧 该文件目录详情 组件独立 大概就是一个原文查看父组件组件里面包含了三层子小组件 。
2 首先针对一个文件下面(1对1原文和1对多原文的限制),如果传了1对1 文件对象那么会在原文查看父组件 根据传入文件类型和文件ID调用接口获取文件二进制流,二进制流通过window.URL.createObjectURL转blob,转入前释放之前的blob ,(或者根据规则是否进行类型转换)区分他是什么文件后缀类型 传入 原文预览组件 此外还有权限控制等。

3 原文预览组件 比较简单 根据传入的后缀 调用blob 或者第三方组件需要的url id 这一部分需要和父组件进行一个协调 此外的就是设置自己的按钮 水印 遮挡 打印 按钮等有各自权限

4 此外就是pdf组件进行了一个额外的优化 最开始用的是原生的浏览器pdf 比如把iframe调用二进制流 后来用pdfjs 因为他原有组件有样式 所以就是用他的api 获取 将pdf转canvas的方法 然后map 同时设置自己的按钮权限。

3 按钮权限控制
1 封装按钮button 支持 点击触发modal表单 删除验证,点击事件防抖,下拉按钮等(该组件connect 调用dva 获取 当前路由按钮数据state 与组件props传值比较)每次调用 判断传值btnJurisdiction 这是一个权限属性 有的话就是全局权限按钮 没有就是正常的button)
2 对于action的监听主要是路由跳转是调用接口 调用接口在dva中配置 通过 subscriptions 一个属性里面history.listen 订阅监听路由 然后dispath调用异步方法 。后端协助 路由跳转调用接口 返回对应菜单路由的配置按钮 更新store 然后转给封装的组件,如果传过来的权限属性 没有包括这个路由按钮那么就返回null 不显示)
3 准确的说是每一个菜单路由配置所需按钮 在同时为用户角色 配置响应菜单的时候 配置生效的按钮
4菜单路由配置按钮时 按钮数据源来于前端代码存储 限制死 ant-d 自动完成输入下拉框 后端负责保存对应菜单 按钮配置 以及角色路由和按钮配置 形成一个闭环

路由权限控制
1 menu通过后端 请求返回该用户需要的菜单 树形结点类型的数据 生成菜单结构
2 地址栏输入 比较保存在dva全局中的菜单数据 使用history.block 拦截 类似于 路由拦截beforeeach
3 系统管理保存 用户路由权限的做法 一般是前后台一致 比如前端除了代码中的配置 路由path 名称自己输入 还要保存到后端。 UMI框架自带的路由一般是一种固定路由, 前端约束的路由path name 以及固定父子关系。 这里是改成了资源路由类型 用户纯输入路由的name 以及排序所在父级中文名。用户只需获取 config/routes 的name (写了个递归 判断了下权限路由 下面的路由push 到一个数组 然后递归下把每一个tree格式数组铺平) 传给后端数据其实还是一个path 一个name 一些其他的
4 配完之后在角色那里配置 传给后端 形成闭环
5 后面菜单跳转的时候 回来最开始 这里有一个主意的点 要自定义菜单点击方法 不能用他原来的方法 点击的的时候让他push 或者弄个link跳转

第一层 行业管理 设置多个行业 这个行业是固定。(高校,档案馆) 行业下面的一层是平台 可以理解为某一个具体的甲方 或者(甲方所具有的多功能系统) 在下面 注册的一些配置 比如系统网段局域网政务网 滑块登录 主题一些可以做的个性化需求之间的区分等 区分角色管理 配置权限(细化按钮 路由) 菜单 里面再配置(每一个菜单的按钮权限 ) 用户这边组织机构区分

@description 一个参数用来描述方法说明。
@param 描述创建实例时的“参数”。有三个参数,第一个参数表示“参数”的数据类型,用 {} 包含。第二个参数表示“参数”名。第三个参数表示“参数”的说明。 “参数”和“参数”说明用‘ - ’连字符来连接,连接符前后需要空格。如果“参数”是个对象则用多个@param 来声明。 “参数”名用[]括起来是,该参数是可选参数,[]内可以用=设置默认参数。“参数”是个数组时,数据类型后添加[]。
@returns 标识方法的返回值 包含两个参数。 第一个参数是返回的数据类型,可返回多种数据类型,用|分割。第二个参数是返回值的说明。
@example 通过例子来解释方法怎么用。

浏览器兼容

不同浏览器的内核不尽相同,所以浏览器对网页的解析也有所差异。
浏览器的内核主要分为两种: 一、 渲染引擎 二、JS引擎。
所以浏览器的兼容问题 一般是 css兼容问题,js兼容问题。

1css 兼容
.不同浏览器的标签默认的(margin和 padding不同)
1一般我们会引入reset.css样式重置 (推荐)
2 用得最多的就是Normalize.css 很多框架在用

首先兼容主要指IE 想其他浏览器 一般都是webkit内核 都兼容谷歌
此外就是兼容主要区分IE9 IE9以下一般不兼容 尤其是ie6以下很麻烦

2ios 兼容
时间格式兼容
new Date(“2020-02-02 08:00”) 变为 new Date(“2020/02/02 08:00”)

3兼容各个机型 最好是用 flexible+postcss
类似于lib-flexible /10

小程序用rpx

4、使用不同类型的浏览器内核前缀
1.Chrome(谷歌浏览器) 与 Safari(苹果浏览器) 内核:Webkit (中译无) 前缀:-webkit-

2.IE (IE浏览器) 内核:Trident (中译三叉戟) 前缀:-ms-

3.Firefox (火狐浏览器) 内核:Gecko(中译壁虎) 前缀:-moz-

4.Opera (欧朋浏览器) 内核:Presto(中译迅速) 前缀:-o-

例:

-webkit-border-radius: 10px; /谷歌浏览器/
-ms-border-radius: 10px; /IE浏览器/
-moz-border-radius: 10px; /火狐浏览器/
-o-border-radius: 10px; /欧朋浏览器/
border-radius: 10px;

5babel-polyfill 针对es6 JavaScript语法报错

6 原生事件的兼容 react 用了合成事件所以不会有这个问题

前端性能优化方式
1减少HTTP请求
2 设置http缓存
3 使用CDN( 就地原则+减少) 压缩前端代码 样式置于header 脚本置于底部
4 资源懒加载
5 异步script标签
6 服务端开启gzip压缩
7 请求并发无缝
8 注意打包每一个文件大小
9 减少重排重绘

webpack 优化
1 打包体积 压缩 gzip压缩
2 构建速度

这个问题比较宽泛 开发环境
现有框架一般都是在dev sever 里面配置 大都都是自带了
1 热更新 hot webpack plut 因为现在框架都是自带的 之前还需要手动打开hot
2 source-map
开发环境 eval-source-map 定位错误代码到指定位置
3 oneof 配置rules 主要是找一个rule 后面就的rule就不走了
4 hash 可以防止命中缓存 打包出来 名字一样 命中浏览器缓存
5 配置一个loader thread-loader 放在babel之前
6 babel缓存 caheDirectory true 第二次构建读取缓存

生产环境
1 externals 引入外部包 排除打包 CDN 生产环境
2 splitChunks 可以把node_modules 抽离成公共代码 比如第三方组件
3 懒加载和预加载 路由默认懒加载 webpackChunkName:‘懒加载’ webpackPrefetch:true ‘预加载’
4 terset webpack 代码压缩 主要是可以 排除console.log
5 three shaking 排除无用代码
6 PWA serve work配置一个

配置单页应用和多页应用

单页一般是标准版的webpack
比方说一个entry 入口 一个plugins
output: 与entry相呼应entry的配置不一样,output可能稍有不同,例:如果entry配置的是多入口output.filename需要将名称设置为[name].js

webpack 构建场景
1初始化参数 主要是从配置中 读取合并参数
2 开始编译 用上一步参数 去Compiler 对象 加载所有配置的插件 调用run方法
3 确定入口 根据entry 找到入口文件
4 从入口文件出发 调用所有配置的loader 对模块进行翻译,然后找到模块依赖的模块,这里比较复杂 一般是递归这个步骤 对这些依赖模块
5 模块编译之后 每一个模块都被翻译成最终内容 以及他们之间的依赖关系
6 输出资源
7 写入硬盘目录

前端seo
1 在header设置合理标题 描述
2 尽量使用语义化html 符合W3C规范
3 少用iframe
4 图片尽量用alt 属性
5 提升网站速度

1 获取code

在确保微信公众账号拥有授权作用域(scope参数)的权限的前提下(服务号获得高级接口后,默认拥有scope参数中的snsapi_base和snsapi_userinfo),引导关注者打开如下页面:

https://open.weixin.qq/connect/oauth3/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

若提示“该链接无法访问”,请检查参数是否填写错误,是否拥有scope参数对应的授权作用域权限。

尤其注意:由于授权操作安全等级较高,所以在发起授权请求时,微信会对授权链接做正则强匹配校验,如果链接的参数顺序不对,授权页面将无法正常访问

其中:

AppID - 公众号的唯一标识
REDIRECT_URI - 跳转url
SCOPE - 值为snsapi_base(不弹出授权页面,直接跳转,只能获取用户openid) 或snsapi_userinfo (弹 出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)
STATE - 开发者可以自定义填写a-zA-Z0-9的参数值

2 通过code换取网页授权access_token

如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。
state就是上面的STATE参数原样传过来的

大屏视频

vh vw
@designWidth:1920;

.width(@c) {
width:calc( @c/@designWidth:) * 100vw;;
}

.border{
.width(2px)
border-radius:@width * 5;
}

css scale 适配方案
得到宽高比 比较当前宽高比

// * 默认缩放值
const scale = {
  width: '1',
  height: '1',
}

// * 设计稿尺寸(px)-- 需跟ui确认
const baseWidth = 1920
const baseHeight = 1080
// const baseWidth = document.body.clientWidth
// const baseHeight = document.body.clientHeight  


 mounted () {
    this.calcRate()
    window.addEventListener('resize', this.resize)
  },
  beforeDestroy () {
    window.removeEventListener('resize', this.resize)
  },
  methods: {
    calcRate () {
      const appRef = this.$refs["appRef"]
      // const geoMap = document.getElementById('geomap-container')
      if (!appRef) return 
      // 当前宽高比
      const currentRate = parseFloat((window.innerWidth / window.innerHeight).toFixed(5))
      if (appRef) {
        if (currentRate > baseProportion) {
          // 表示更宽
          scale.width = ((window.innerHeight * baseProportion) / baseWidth).toFixed(5)
          scale.height = (window.innerHeight / baseHeight).toFixed(5)
          appRef.style.transform = `scale(${scale.width}, ${scale.height}) translate(-50%, -50%)`
          // geoMap.style.transform = `scale(${-scale.width}, ${-scale.height}) translate(-50%, -50%)`
        } else {
          // 表示更高
          scale.height = ((window.innerWidth / baseProportion) / baseHeight).toFixed(5)
          scale.width = (window.innerWidth / baseWidth).toFixed(5)
          appRef.style.transform = `scale(${scale.width}, ${scale.height}) translate(-50%, -50%)`
          // geoMap.style.transform = `scale(${-scale.width}, ${-scale.height}) translate(-50%, -50%)`
        }
      }
    },
    resize () {
      clearTimeout(this.drawTiming)
      this.drawTiming = setTimeout(() => {
        this.calcRate()
      }, 200)
    } 

更多推荐

面试 场景题

本文发布于:2023-04-29 21:04:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/c55a48f83898cdb291ec2719eac1d9c0.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:场景

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!

  • 112242文章数
  • 28550阅读数
  • 0评论数