如何上传大文件
server端
初始化文件( 分片文件 )上传的目录
根据md5和fileName 创建一个文件夹
接收文件分片
在接收文件分片的时候,我们首先会获取分片存储位置,然后计算分片的md5,然后将分片命名为${partIndex}|${partFileMd5}.part,存储到对应路径下。
合并文件分片
拿到分片 list,根据index进行排序, 然后进行文件的合并, 使用流进行合并
const writeStream = fse.createWriteStream(outputPath);
const readStreamList = inputPathList.map((path) => {
return fse.createReadStream(path);
});
return new Promise((resolve, reject) => {
const multiStream = new MultiStream(readStreamList);
multiStream.pipe(writeStream);
multiStream.on('end', () => {
fse.closeSync(fd);
resolve(true);
});
multiStream.on('error', () => {
fse.closeSync(fd);
reject(false);
});
});
}
client端
blob的slice 可以对文件进行切片, 然后 for循环 进行上传
如何做到断点续传
客户端维护一个 retryList 列表, 分片上传失败的时候, 加入 retryList 最后 上传这个retryList
每个分片有一个index值, 如果这个分片没传上去, 会在下一次对分片组进行排序 然后重新传
如何进行响应式布局
rem + 媒体查询(element-ui提供的 column 属性)
使用rem的时候需要在 css 加载之前, 定义 html 的 font-size
markdown转为HTML,如何自定义风格
使用 markdown-it 这个开源库,将markdown文本转换成HTML,通过学习markdown-it-anchor的源码,自己写markdown-it 的插件,通过某个函数,在某个元素前面加自定义的类名,然后引入自定义的 CSS 样式即可
如何自定义编辑器
编辑器的功能有哪些
和普通的博客编辑器一样功能,还增加了mermaid流程图。 难点是如何显示粘贴的图片
复制的图片如何粘贴
- 前端监听粘贴事件
- 一旦发生粘贴事件,就将获取到的粘贴资源上传到后端服务器存起来
- 存好过后,后端返给前端链接,就可以查看了
-
同步滚动功能是怎么做的
动态加载tag是怎么做的以及遇到了哪些困难
如何判断tag超了
根据 tag-wrapper 的高度进行判断
- 如何让 tag 只显示一行
(1) 使用高度进行判断,如果超出了wrapper的高度,就给wrapper overflow: hidden 的属性
但问题是,无法统计超出的 tag 的数量
(2) 如果高度超出了,将tag从最后,一个一个往前删除,直到高度没超为止。
很明显,这是一个重复调用的过程,在什么时机去执行这个函数,很重要
遇到的问题是,如果不在 nextTick 去执行,就不会生效
- 父组件的宽度动态变化应该如何去做
在子组件的mounted阶段,table 父组件的某一列的宽度还是未固定的, 导致的结果是父组件mounted生命周期之后, tag 全被折叠起来了。
解决办法是,在父组件的mounted周期之后去更新子组件,给子组件一个prop,在父组件的 mounted阶段更新这个prop,然后将子组件的渲染函数放到update生命周期中。然后给设置一个flag, 仅仅在第一次update 阶段才生效
然后监听 sizeChange 事件。
说一说鉴权功能
cookie-session
只要用户不禁用 cookie 就ok, 如果禁用cookie的话 就不行了
sso 给顶级域名设置cookie
JWT(JSON WEB TOKEN)
服务器返回一个包含用户信息和认证方式的token, 用户存在cookie中,然后在请求的时候带上,服务器再进行验证即可,这样 服务器就不需要存sessionId了
查询-渲染组件是怎么做的
<template>
<div>
<slot name="table" :list="list"></slot>
<!-- 作用域插槽,将父组件的数据传递给子组件 -->
<pagination
:total="total"
:pageSize="pageSize"
@preClick="handlePageChange"
@nextClick="handlePageChange"
@pageChange="handlePageChange"
@pageSizeChange="handlePageSizeChange"
></pagination>
</div>
</template>
<script>
const obj = {
params: '需要进行查询的参数信息',
reqSource // 请求地址
}
export default defineComponent({
name:"component",
props: [obj, paginationProps, reqSource],
setup() {
const useTable = async obj => {
const list = await getList(obj.params, obj.reqSource);
watch(() => [obj.page, obj.pageSize], ([old1,new1],[old2,new2]) => {
handlePageChange();
handlePageSizeChange();
});
return {
list
}
};
return {
list
}
}
});
</script>
<style>
</style>
excel 是怎么导出的
https://www.cnblogs.com/liuxianan/p/js-excel.html
http://blog.haoji.me/js-download.html#JS-dan-chu-xia-zai-dui-hua-kuang
JS要实现下载功能,一般都是这么几个过程:生成下载的URL,动态创建一个A标签,并将其href指向生成的URL,然后触发A标签的单击事件,这样就会弹出下载对话框,从而实现了一个下载的功能。
function openDownloadDialog(url, saveName)
{
if(typeof url == 'object' && url instanceof Blob)
{
url = URL.createObjectURL(url); // 创建blob地址
}
var aLink = document.createElement('a');
aLink.href = url;
aLink.download = saveName || ''; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
var event;
if(window.MouseEvent) event = new MouseEvent('click');
else
{
event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
}
aLink.dispatchEvent(event);
}
自定义loader 是怎么做的
router懒加载的loader
因为我们做的那个B端的页面有很多的路径,每个人做的模块各不相同,所以所关心的点也有所不同,为了提高首次进入的加载速度,会让用户自定义一个 router.config 的文件,写上自己工作所用的路由,然后webpack 在加载的时候,会去读取这个文件,生成最新的router文件,vue就去加载这个最新的router文件就可以了
一是为了应用隔离,二是为了提高加载速度
router中 index.ts
这里读取各个模块的文件就很费时间
const context = require.context('./', true, /\.ts$/);
let routerList = [];
context.keys().forEach(key => {
if (key !== './index.ts') {
routerList = routerList.concat(context(key).default);
}
});
export default routerList;
config.module.rules.push({
test: /\.ts$/,
loader: path.join(__dirname, 'conf/lib/lazy-loader.js'),
enforce: 'pre', // 优先处理
include: resolve('src/router/config/index.ts'),
options: {
// laze-loader需要改写的文件地址
baseUrl: resolve('src/router/config/index.ts'),
baseModule: [...getLazyModuleConfig() || []], // 支持配置层面设置,格式:'./auth'
},
});
module.exports = function (source) {} // 如何写loader,重要的是返回的source的内容是什么
常用组件加载的loader
因为这个应用中有很多的常用的组件,每次都要去加载的话会很麻烦,代码也会显得比较冗余。所以需要全局注册一些通用的组件。一个一个手动去注册又显得太麻烦
有没有一种方法,把需要进行全局注册的组件放在一个config 文件当中,然后去读取它,然后将其引入到main.ts 当中
答案就是自定义一个 loader,处理那个config文件,然后将处理的结果加入 main.ts 当中