0%

Shadow Dom

什么是 Shadow Dom

​ Shadow Dom:影子 Dom,可以理解为潜藏在背后的 DOM 结构,也就是我们无法直接控制操做的 DOM 结构。

Shadow Dom Open

图中的 #shadow-root 中包含的内容其实就是 Shadow-Dom

阅读全文 »

需求:PDF 转图片 -> base64 格式 -> 上传图片

PDF 转 base64 图片

参考:Using pdf.js in React

  • 安装 pdfjs-dist

    1
    npm install pdf-dist@2.0.943 --save
  • 项目当中引入

    1
    2
    3
    4
    import * as PDFJS from 'pdfjs-dist'
    import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry'
    // 解析需要
    PDFJS.GlobalWorkerOptions.workerSrc = pdfjsWorker

项目使用了 Antd 的 Upload 组件,

阅读全文 »

ES6-Promise

Promise 是异步编程的一种解决方案,比传统的解决方案回调函数和事件更合理和更强大

有了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。

一个 Promise 的当前状态必须为以下三种状态中的一种:等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected),状态的改变只能是单向的,且变化后不可在改变。

一个 Promise 必须提供一个 then 方法以访问其当前值、终值和据因。

阅读全文 »

问题记录

  1. 旧项目使用了 handsontable 出现样式问题,试图解决问题并给 handsontable 小版本升级一下(4、5年前的项目)
  2. 升级过程中出现新问题,原有的 promise.finally polyfill 在某些页面不起作用,正常保存 promise...then().finally is not a function

定位过程

  1. 首先目的是小版本升级一下 handsontable,并在此过程中解决样式问题,原先版本为 0.31.2, 4 年前发布,考虑升级至最小且有官方文档的 4.0.0 版本
  2. 升级前没有 promise.finally is not a function 问题
  3. 查看项目代码,发现有配置 babel-polyfill 且在 main.js 有实现 promise.finally() 方法的 polyfill
  4. 考虑可能是 polyfill 方法功能不足,使用 promise.prototype.finally 库代替,并正确引入项目,在出现 is not a function 的页面引入( require('promise.prototype.finally').shim() )
  5. 此时项目运行正常,但不久后出现新的问题:其他部分页面在刷新后仍有相同报错,依次引入可解决,但不可取
  6. 与此同时,提交后发布到测试环境时,出现问题,项目启动后报错 cannot find module es-abstract...,无法打开项目,但本地环境正常
  7. 经排查发现 webpackpromise.prototype.finally 都有引用到 es-abstract,猜测版本不兼容,降低版本后,项目正常启动
  8. 令外,项目的发版已配置环境自动安装依赖,且环境与管理工具为 node8 和 yarn,而本地环境为 node10,所以本地环境正常,测试环境报错
  9. 同步环境后,问题尚未解决,消失已久的 promise.finally is not a function 再次出现
  10. 总结可能导致出现问题的点
  • axios:
    项目使用 axios 处理网络请求,并增加拦截器;发现手动 new 的 promise 实例上有 polyfill 后的 finally 方法,而 this.$http.get 返回的 promise 对象上没有
  • 新版本的 handsontable 增加了与 promise 相关的处理
阅读全文 »

  1. 文件上传使用 XLSX 解析 Excel 文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    // 文件上传前钩子
    const onBeforeUpload = (file: RcFile, fileList: RcFile[]) => {
    console.log(file)
    setFileName(file.name)

    const fileSize = file.size / 1024 / 1024
    if (fileSize > 100) {
    message.error('文件不得超过 100MB!')
    return false
    }

    const fileType = file.name.split('.').reverse()[0]
    let fileReader = new FileReader()

    // 文本
    if (fileType === 'txt') {
    fileReader.readAsText(file)
    fileReader.onload = (res: any) => {
    // 获取内容
    const resStr = res.currentTarget.result.replace(/\r/g, '')
    const resArr = Array.from(new Set(resStr.split('\n'))) as string[]

    setPhoneNumArr(resArr)
    }
    }
    // excel
    if (fileType === 'xsl' || fileType === 'xlsx') {
    let workBook: any
    try {
    fileReader.readAsBinaryString(file)
    fileReader.onload = (res: any) => {
    // 获取内容
    const data = res.target.result
    // console.log(data)
    workBook = XLSX.read(data, {
    type: 'binary'
    })
    // let fromTo = ''
    let result: any[] = []
    for (var sheet in workBook.Sheets) {
    if (workBook.Sheets.hasOwnProperty(sheet)) {
    // fromTo = workBook.Sheets[sheet]['!ref']
    // console.log(fromTo)
    result = result.concat(XLSX.utils.sheet_to_json(workBook.Sheets[sheet]))
    // break; // 如果只取第一张表,就取消注释这行
    }
    }
    filterPhoneNumber(result)
    }
    } catch (e) {
    console.log(e)
    }
    }
    return false
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <Dragger
    action="/api/sms/send/sendFile"
    name="file"
    maxCount={1}
    accept={'.excel,.txt, .xls, .xlsx'}
    showUploadList={false}
    headers={{
    Authorization: `Bearer ${Cookies.get(tokenKey)}`,
    }}
    beforeUpload={onBeforeUpload}
    onChange={onChangeFile}
    onRemove={onRemoveFile}
    >
    <img className={styles.picIcon} src={picicon} alt="" />
    <p className="ant-upload-text">点击或将文件拖拽到这里上传</p>
    <p className="ant-upload-hint">支持文件Excel或TXT文档, 大小不超过100M</p>
    </Dragger>
  2. 从后端获取 blob 格式的二进制流,解析并下载

    1
    2
    3
    4
    5
    6
    export const exportTaskExcel = function (id: string) {
    return request.get('/api/exportExcel', {
    params: { id },
    responseType: 'blob',
    })
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    exportTaskExcel(id)
    .then((resp: any) => {
    console.log(resp)
    // 二进制转url打开下载
    if (resp.status === 200) {
    const url = window.URL.createObjectURL(resp.data)
    window.open(url)
    }
    })
    .catch((err) => {
    console.log(err)
    message.error(t(`${RPath}.下载失败`))
    })

图片、PDF 实现预览

1
2
<img :src="imgUrl " />
window.opean(this.imgUrl )

  • jsx 不只是模板语法的一种,jsx 作为 react 框架的一大特色,与其运行机制有千丝万缕的联系
  • jsx 是 JavaScript 的一种语法扩展工具,和模板语法很接近,但是充分具备 js 的能力
  • 浏览器不会像对 js 一样直接支持,而是需要通过 Babel 转化
  • Babel 是一种 JavaScript 编译工具,能够将 ES2015 以上的版本转化为向后兼容的 js 语法,适配低版本浏览器,另外还可以转化 jsx、typescript…

jsx 会被编译为 React.createElement(), React.createElement() 将会返回一个 React Element 对象

1
2
3
4
<div className="App">
<h1 className="app__title">Hello World</h1>
<p className="app__desc">React and JSX</p>
</div>

转换后

1
2
3
4
5
6
7
8
9
10
"use strict";

/*#__PURE__*/
React.createElement("div", {
className: "App"
}, /*#__PURE__*/React.createElement("h1", {
className: "app__title"
}, "Hello World"), /*#__PURE__*/React.createElement("p", {
className: "app__desc"
}, "React and JSX"));
阅读全文 »