Skip to content

Latest commit

 

History

History
451 lines (338 loc) · 15.2 KB

README.md

File metadata and controls

451 lines (338 loc) · 15.2 KB

[TOC]

Vue 3 + Vite

This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 <script setup> SFCs, check out the script setup docs to learn more.

Recommended IDE Setup

npm init vite-app <projectName>

cd <projectName>

npm i

npm run dev

1.弹窗封装

vue文件:通过props传入参数,依据参数进行显示,编写css
js文件:调取vue文件,传入必要参数,利用vue的unmount去卸载组件
调取js文件传入参数,参数以props的形式流动

这里可以结合dom闭包卸载

2.pdf封装

想着不用二进制流的方式去传递 使用 vue-pdf-embed,可以显示但是有些模糊,想获取页面的最大page,可是费劲了。
于是,用了某大神封装的 pdf-vue3,和vue-pdf-embed相比就是一个天上一个地下。
在使用 pdf-vue3的基础下,我给加了个 监听ctrl+wheel的事件,可以放大缩小pdf
github地址:https://github.com/hymhub/pdf-vue3
特此感谢!

3.文件上传、断点续传

按照指定大小对文件进行拆分,要求每片文件都有file、filehash、uploaded(是否上传)、chunkIndex等信息。
1.文件切片的流程,就是通过记录切片位置和一次性切片大小,进行分割文件。
2.获取哈希的流程,就是读取流,然后用SparkMD5获取文件哈希。
3.涉及到分批后批量上传,使用基于队列的文件分批上传
4.上传成功后uploaded是true,否则为false
5.断点续传就是对uploaded是false的进行上传

上传每片文件、合并这些文件


tips: 
//读取blob,用于获取文件哈希等
const fileReader = new FileReader();
fileReader.readAsArrayBuffer(file);
//blob流转base64,用于图片转base64
const reader = new FileReader();
reader.readAsDataURL(file);
//文件发送
let fd = new FormData();//要发送的表单数据
fd.append('file', chunk.file);
fd.append('fileHash', chunk.fileHash);
fd.append('chunkIndex', chunk.chunkIndex);

4.动态表单

只考虑功能实现,不考虑css。
不显示、显示1个、显示多个,显示n个,
设计成链表就可以。
0--->null
1---->a-b
2---->{
     1
     c-d
}
.......

后台传递过来数据,根据后台的数据,前台实现逻辑

image.png

image.png

image.png

5.递归template

自己调用自己,适用于高度耦合的对象,

6.树形控件

以下两种情况都要递归调用,结合vue3.0语法
对每一个  打对勾,子要全部 打对勾。------>遍历当前父的每一个子
每一个子  打对勾,父要全部 打对勾 ------->遍历当前子的父/父兄,做判定,

image.pngimage.pngimage.png

7.分批多线程请求、分批但是要求批次的顺序、不分批逐个上传

1.分批多线程---不要求调用顺序----使用队列,

利用执行栈中的顺序,先同步后异步,维护并发队列的长度
出队列之前,队列长度--
有回调结果后,队列长度++,进行下一个任务;
适用于,没有要求调用顺序的。文件分批上传只要,我们把哈希值、分割文件的index、传给后台即可。
但是如果要求调用顺序呢?

image.png

2.分批多线程---不要求调用顺序----利用js的同步异步,虽然 队列的方式 也利用了同步异步

image.png

其实算法思想都一样,都是用的队列,不过第二种含蓄点

3.分批,但是要求批次的顺序。
使用promise.all([....promise请求]).then((allData)=>{
       //递归调用,下一个批次请求
   }).catch((err)=>{
       //抛出错误,throwError(err)
   })
4.逐个上传
callback(arr.shift()).then((result)=>{
    //递归调用,下一个请求
})

8.策略模式

封装策略,实现可复用、可扩展和可维护,并且避免大量复制粘贴的工作。
给了一个表单校验简单demo展示

9.拖拽排序封装

用到了drag的api,实现拖拽排序
核心模块思路,删除原来位置,新位置之前插入,
当然还涉及到一些封装思路。
频繁的拖拽,还要写个防抖函数,略。

image.png

10.内存泄露

闭包、循环引用、dom引用等

11.自定义hooks

调接口、计数器、布尔切换、窗口size
都是提取的公共逻辑,做的封装。

12.虚拟列表

虚拟列表其实是按需显示的一种实现,即只对可见区域进行渲染,对非可见区域中的数据不渲染或部分渲染的技术,从而达到极高的渲染性能;
1.计算外层可视化容量:itemHeight静态Math.ceil(containerHeight / itemHeightRef)
                  itemHeight动态就从fromIndex累加
2.计算列表数据对于container的偏移数量(offset),同上
3.计算在container区域内可显示的数据个数(calculateRange)。start: offset - overscan;end: offset + visibleCount + overscan。overscan为可允许溢出container范围的最大个数;
4.计算wrapper所有item总体的高度;可以用计算属性
5.列表距container的高度(distanceTop)
6.设置wrapper的高度和偏移量.
7.设置wrapper展示dom;
8.监听scroll事件,动态计算显示区域个数、显示区域范围、已经滚动的高度、wrapper的高度以及mariginTop

虚拟列表适用于渲染大量数据项的长列表场景。
经过测试99*10^4个dom节点都不在话下

png

13.时间分片

把长时间运行的任务,分成多个小任务,穿插在空闲时间(用requestIdleCallback),以便让浏览器有时间进行渲染和响应用户输入。这种技术使得应用在执行繁重计算任务时,仍然能够保持界面的流畅性和响应性。
//第一种做法:固定eachRenderNum
1.计算时间片,一次性渲染多少个(eachRenderNum ),总数据(originalList)除以,得到总共渲染多少次(times)
2.开始渲染数据,通过 index > times 判断渲染完成,如果没有渲染完成,那么通过 requestIdleCallback 浏览器空闲执行下一帧渲染
3.通过 renderList 把已经渲染的 element 缓存起来.

//第二种:动态eachRenderNum
1.空闲时间剩余 deadline.timeRemaining()
2.持续时间 performance.now() - startTime
3.若最大允许持续时间为16

在完成一帧中的输入处理、渲染和合成之后,线程会进入空闲时期(idle period),直到下一帧开始,或者队列中的任务被激活,又或者收到了用户新的输入。requestIdleCallback 定义的回调就是在这段空闲时期执行:

png

14.axios封装

基础配置文件暴露 请求基础地址(baseURL)、是否开启token认证(useTokenAuthorization)

axios 请求拦截中
1.若开启token认证,headers['Authorization'] =localStorage.getItem("token")
2.若没有设置请求头(!config.headers["Content-Type"]),并且是post请求,
  则headers["Content-Type"] = "application/x-www-form-urlencoded";
    data = qs.stringify(config.data);//序列化
3.headers["Content-Type"]默认是 "application/json"; 

axios相应拦截,就是设定不同状态返回。

15.ref封装

ref本质也用了proxy,
通过ref文件,可以完成数据的修改,均可被get、set监听到。

get中 if(activeWatcher){//有watcher
      dep.depend(activeWatcher)//收集依赖
}
set中就通知更新dep.notify()

16.图片懒加载

通过判断图片是否在视口内部,决定是否加载图片,
const {top,right,bottom,left,} = element.getBoundingClientRect();拿到视口位置
在视口内部,就取消lazy类,并src=data-src

17.表单封装

因为不同模块的表单,内容上、逻辑上均高度相似,于是对表单做了封装
父组件的输入:
{
    itemType:text/number/textarea/select,//输入框类型
    labelName:'xxx'//输入框label
    propName:'xxx'//输入框字段
    isRequired:'true'//是否必填
    placeHolder:'',
    optionsArr:[...]//如果输入框类型是select要有
}
子组件,格式类似下面进行嵌套,根据itemType去回显
<el-form v-for="(item,index) in formHeader">
     </el-form-item  v-if="item.itemType == 'text'/'number'/'textarea'">
            <el-input></el-input>
     </el-form-item>
     </el-form-item v-if="item.itemType == 'select'">
            <el-select></el-select>
     </el-form-item>
</el-form>
然后就是,绑定change事件、写校验函数、确定、重置等
1.change事件里面,可以用正则表达式进行判断,判断不通过,对应的value为null,
2.校验函数,发现value为null,就可以根根据itemType,抛出错误。
3.提交函数,调用校验函数,进行校验,,校验成功,通过emit发送事件通知父组件
4.重置函数,调用form表单的重置方法,并把form表单v-model绑定的值设定为空对象。

18.分页封装

分页用的是 <el-pagination></el-pagination>
只要是table,就要用到分页,因此可以进行以下封装
1.传入当前页、一页显示多少条、总的数据量、等数据给封装后的组件
2.当前页改变,通知父组件修改数据

19.less使用

https://juejin.cn/post/7283422522535673856
变量、计算、混入、函数、通过函数动态计算、导入、继承、	嵌套

less  sass区别
sass有复杂的控制结构和函数支持 @if @for @each @while
sass解决了命名冲突问题 @use

20.SSE(Server-Sent-Events),实现chatgpt一个字一个字跳出来

//前端vue
 const message = ref('');
 const eventSource = new EventSource('http://localhost:5000/stream');
 eventSource.onmessage = (event) => {
      message.value += event.data;
 }

21.websocket

  //前端value
    const message = ref('');
    const messages = ref([]);
    let socket = null;
    //接口返回
    const connectWebSocket = () => {
      socket = new WebSocket('ws://localhost:5001/');
      socket.onmessage = (event) => {
        messages.value.push( "server value:"+event.data);
      };
    };
    //输入框输入后,
    const sendMessage = () => {
      if (message.value.trim() !== '') {
        socket.send(message.value);
        messages.value.push(`You: ${message.value}`);
        message.value = '';
      }
    };
    // Connect WebSocket when component is mounted
    connectWebSocket();

22.SSE 和 WebSocket的不同

1.SSE 是比较适合单向数据传递的场景,尤其是当不需要从客户端频繁地向服务器发送数据时。SSE 可以用标准 HTTP 服务实现,对于服务器的改造相对较小。
2.WebSocket 比 SSE 更为强大,适用于需要快速、双向通信的应用。WebSocket 更复杂,需要专门的服务器和客户端支持。然而,它们提供了更低的延迟和更灵活的通信能力。

23.在线视频、直播

在线视频使用,vue3-video-play
在线直播使用,LivePlayer

livePlayer直播的时候可以隐藏滚动条,vue3-video-play配置起来更简单

24.路由

实现简易的 vue-router-hash
1.写个路由对象
2.监听hashChange事件,得到hash改变后的url
window.addEventListener('hashchange', () => {
  currentPath.value = window.location.hash
})
3.判断url是否在路由对象内,jue'ding

25.单点登录

//参考https://juejin.cn/post/7088978055737114638
1.同域 用cookie设置主域,所有的子域都可以访问到主域的cookie.
2.不同域,部署SSO(Single Sign On)认证中心
    1.输入用户名、密码进行登录。登录成功获取token。存储在cookie中。
    2.从cookie中获取token,
       token不存在跳转到登录页。
       token存在,用token换取code。
       code不存在,清除cookie,跳转登录页。
       code存在,同域,直接将redirectUrl返回,,无需携带code接口返回的值,然后跳转。
       code存在,不同域,也就是第三方系统,redirecturl 拼接 code 后重定向到redirecturl.
    3.用户退出后,
       调用注销Api,
       清除cookie
       重定向到登录页。

tips:这里的token,是用来共享用户的登录状态。
后续,访问受保护的内容,可以用code(授权码)换取访问令牌(access token)、刷新令牌(refresh token)、会话令牌(session token)等。

26.动态路由

//https://blog.csdn.net/lzfengquan/article/details/122918158
beforeEach路由拦截
      if(本地没有路由数据){
          1.axios后台获取路由
          2.使用递归对路由 componets组件拼接
          3.使用addRoutes添加路由
          4.拿到路由后再next()
      }else{
          next();
      }

image.png

27.vue3.0组件传值

父子传值:父传子props,子传父emit
跨层级传输:provide inject
复杂组件:vuex;

28.el-tree复杂

1.添加

用双向链表 抽象 原始数据,格式按照项目形式,选中状态全部false。用el-tree的click事件,选中/不选种递归状态检查。其中可以显示三个按钮,它是叶子结点,并且是选中状态

最后,提交事件中,遍历树,只要不是未选中状态的,就加入数组。

2.编辑
用双向链表 抽象原始数据,格式按照项目形式,选中状态全部false。传递过来的数据,用哈希id当key, (顺便把状态是all的加入回显数组,供回显)。对抽象数据,做二次抽象,用深度优先算法,匹配哈希id,修改状态,以及三个按钮。

用el-tree的click事件,选中/不选种递归状态检查。其中可以显示三个按钮,它是叶子结点,并且是选中状态

最后,提交事件中,遍历树,只要不是未选中状态的,就加入数组。

29.cascader巨复杂

就是字符串分割 id自增 哈希优化等,
难点不在算法,在于实际业务工程化,反推

30.cookie 搭桥

a67957a00836749139bb34e8ba754ee.png

以及 利用 storage 事件 监听两个相同域名 之间 互相本地存储的改变 从而去 window.reload()