Work Notes

87 阅读4分钟

各种例子

 

字符串操作

统计多种字符串

cloud.tencent.com/developer/a…

 

blog.csdn.net/weixin_4241…

 

JS符号【问号点(?.)和双问号(??)的用法】

blog.csdn.net/qq_45677671…

 

数组去空+去重

 

js方法去除数组中的空值

 

splice方法

 


/*

          方法一:splice方法

          缺点:不适用字符串中包含空格

          如:array = [1, 2, 3, ' '],调用该方法,结果:[1, 2, 3, ' ']

        */

        var array = [1, 2, 3, '']

        console.log(trimSpace(array)); //打印结果: [1, 2, 3]

 

        function trimSpace(array) {

            for (var i = 0; i < array.length; i++) {

                if (array[i] == "" || array[i] == null || typeof (array[i]) == "undefined") {

                    array.splice(i, 1);

                    i = i - 1;

                }

            }

            return array;

        }

 

1234567891011121314151617

 

filter方法

 


// 方法二:filter方法 [推荐写法]

    var arr = ['A', '', 'B', null, undefined, 'C', '  '];

    var r = arr.filter((s) => {

    return s && s.trim();     // 注:IE9(不包含IE9)以下的版本没有trim()方法

    });

    console.log(r);  //打印结果: ["A", "B", "C"]

 

去重

...new Set(array)

 

保留小数位:不显示的时候,默认值为0了,本应该为1的【解决方案:】


<gmd-form-model-item v-if="formData.createType == 1" label="结果展示方式" prop="valueType">

  <gmd-form-model-item style="display:inline-block;margin:0;width: 100px;">

    <gmd-select v-model="formData.valueType">

      <gmd-select-option :value="1">整数</gmd-select-option>

      <gmd-select-option :value="2">小数</gmd-select-option>

      <gmd-select-option :value="3">百分数</gmd-select-option>

    </gmd-select>

  </gmd-form-model-item>

  <gmd-form-model-item

    v-if="formData.valueType !== 1"

    label="保留小数位"

    prop="dataDigits"

    :label-col="{span:8}"

    style="display:inline-block;margin:0;width: calc(100% - 100px);"

  >

    <gmd-input-number

      v-model="formData.dataDigits"

      :disabled="formData.valueType === 1"

      :min="1"

      :max="9"

    />

    <!--            @keydown.native="handleBackspace"-->

  </gmd-form-model-item>

</gmd-form-model-item>


watch: {

  async 'formData.dataDigits'(v) {

    if (!v) {

      await this.$nextTick()

      this.formData.dataDigits = 1

    }

  },

},

 

多重判断简化【写个配置表】


if (this.formData.analysisMethod) {

  // 设分析维度验证:【数据类型--分析方法】配置表

  const config = {

    2: [2, 3, 4, 5],

    3: [2, 5],

    4: [2, 5],

  }

  if (config[row.type]?.includes(this.formData.analysisMethod)) {

    return this.$message.error('当前分析方法不支持此数据类型')

  }

} else {

  return this.$message.warning('请先补充分析方法')

}

 


<gmd-select

  :disabled="formData.createType == 1"

  v-model="formData.analysisMethod"

  placeholder="请选择分析方法(单选)"

  class="indexsSelect"

>

  <gmd-select-option

    v-for="fc in configs.fcList"

    :key="fc.value"

    :value="fc.value"

    :disabled="analysisConfig[fc.value] && analysisConfig[fc.value].includes(formData.dataType)"

  >{{ fc.name }}</gmd-select-option>

</gmd-select>

 

data() {

    return {

        analysisConfig: {

          2: [2, 3, 4],

          3: [2],

          4: [2],

          5: [2, 3, 4],

        }

    }

}

 

keycode键值码表

HTML

 

用户名:

 

密码:

 

JavaScript:

 

JumpByEnter(UserPwd) 函数功能:输入完用户名按回车,焦点转向密码输入框

 

IsEnterKeyPress()功能:输入完密码并按回车,则登录

 

function JumpByEnter(NextElement){\

     var lKeyCode = (navigator.appname=="Netscape")?event.which:window.event.keyCode; //event.keyCode按的建的代码,13表示回车\

     if ( lKeyCode == 13 ){

 

    NextElement.focus();\

     }

 

function IsEnterKeyPress(){\

     var lKeyCode = (navigator.appname=="Netscape")?event.which:event.keyCode;\

     if ( lKeyCode == 13 ){\

       Login();\

     }\

     else\

       return false;\

   }

 

irfirefox2.0中不支持 window.event.keyCode,

 

但是我们可以用event.which代替。但是为了使其能更具有普遍的兼容性,最好用event.keyCode|| event.which.

 

Keycode对照表

 

| 字母和数字键的键码值(keyCode) |    |    |    |    |    |    |    |

| ------------------- | -- | -- | -- | -- | -- | -- | -- |

| 按键                  | 键码 | 按键 | 键码 | 按键 | 键码 | 按键 | 键码 |

| A                   | 65 | J  | 74 | S  | 83 | 1  | 49 |

| B                   | 66 | K  | 75 | T  | 84 | 2  | 50 |

| C                   | 67 | L  | 76 | U  | 85 | 3  | 51 |

| D                   | 68 | M  | 77 | V  | 86 | 4  | 52 |

| E                   | 69 | N  | 78 | W  | 87 | 5  | 53 |

| F                   | 70 | O  | 79 | X  | 88 | 6  | 54 |

| G                   | 71 | P  | 80 | Y  | 89 | 7  | 55 |

| H                   | 72 | Q  | 81 | Z  | 90 | 8  | 56 |

| I                   | 73 | R  | 82 | 0  | 48 | 9  | 57 |

 

  

 

| 数字键盘上的键的键码值(keyCode) | 功能键键码值(keyCode) |       |     |    |     |     |     |

| -------------------- | --------------- | ----- | --- | -- | --- | --- | --- |

| 按键                   | 键码              | 按键    | 键码  | 按键 | 键码  | 按键  | 键码  |

| 0                    | 96              | 8     | 104 | F1 | 112 | F7  | 118 |

| 1                    | 97              | 9     | 105 | F2 | 113 | F8  | 119 |

| 2                    | 98              | *     | 106 | F3 | 114 | F9  | 120 |

| 3                    | 99              | +     | 107 | F4 | 115 | F10 | 121 |

| 4                    | 100             | Enter | 108 | F5 | 116 | F11 | 122 |

| 5                    | 101             | -     | 109 | F6 | 117 | F12 | 123 |

| 6                    | 102             | .     | 110 |    |     |     |     |

| 7                    | 103             | /     | 111 |    |     |     |     |

 

  

 

| 控制键键码值(keyCode) |    |            |    |             |     |      |     |

| --------------- | -- | ---------- | -- | ----------- | --- | ---- | --- |

| 按键              | 键码 | 按键         | 键码 | 按键          | 键码  | 按键   | 键码  |

| BackSpace       | 8  | Esc        | 27 | Right Arrow | 39  | -_   | 189 |

| Tab             | 9  | Spacebar   | 32 | Dw Arrow    | 40  | .>   | 190 |

| Clear           | 12 | Page Up    | 33 | Insert      | 45  | /?   | 191 |

| Enter           | 13 | Page Down  | 34 | Delete      | 46  | `~   | 192 |

| Shift           | 16 | End        | 35 | Num Lock    | 144 | [{   | 219 |

| Control         | 17 | Home       | 36 | ;:          | 186 | | | 220 |

| Alt             | 18 | Left Arrow | 37 | =+          | 187 | ]}   | 221 |

| Cape Lock       | 20 | Up Arrow   | 38 | ,<          | 188 | '"   | 222 |

 

| 多媒体键码值(keyCode) |     |    |    |    |    |    |    |

| --------------- | --- | -- | -- | -- | -- | -- | -- |

| 按键              | 键码  | 按键 | 键码 | 按键 | 键码 | 按键 | 键码 |

| 音量加             | 175 |    |    |    |    |    |    |

| 音量减             | 174 |    |    |    |    |    |    |

| 停止              | 179 |    |    |    |    |    |    |

| 静音              | 173 |    |    |    |    |    |    |

| 浏览器             | 172 |    |    |    |    |    |    |

| 邮件              | 180 |    |    |    |    |    |    |

| 搜索              | 170 |    |    |    |    |    |    |

| 收藏              | 171

 

 

输入框禁止删除操作--键盘backspace


handleBackspace() {

  if (event.keyCode === 8) event.preventDefault()

},

 

关于div禁用点击事件

 

情景⼀:阻⽌外层div点击事件pointer-events: none;


<div class="out" style="pointer-events: none;">

<div class="in" onClick="inBlock()">这是我的提⽰框<br/>这是我的提⽰框<br/>这是我的提⽰框<br/>这是我的提⽰框<br/></div>

</div>

需要注意的是如果在外层div设置了禁⽌点击,则⾥层div的点击事件⽆效的

 

 

情景⼆:外层点击事件不受⾥⾯div影响

也就是说我只想点击透明部分隐藏我的遮罩层


<div class="out" onclick="outBlock()">

<div class="in">这是我的提⽰框<br/>这是我的提⽰框<br/>这是我的提⽰框<br/>这是我的提⽰框<br/></div>

</div>

这时候只需要在我的div中加⼀段代码,就能有效阻⽌内层点击事件对外层的影响

onClick="event.cancelBubble = true"onClick="event.stopPropagation();"

<div class="in" onClick="event.cancelBubble = true">这是我的提⽰框<br/>这是我的提⽰框<br/>这是我的提⽰框<br/>这是我的提⽰框<br/></div>

这两种⽅法都能够有效阻⽌事件的冒泡,区别⼤家可以看看其他博客。

 

 

情景三:若外层div与内层div都需要执⾏点击且不同事件

与情景⼆的情况相同,我们都需要阻⽌事件的进⼀步冒泡⾏为


<div class="out" onclick="outBlock()">

<div class="in" onClick="inBlock()">这是我的提⽰框<br/>这是我的提⽰框<br/>这是我的提⽰框<br/>这是我的提⽰框<br/></div>

</div>

<script>

var div1 = document.getElementsByClassName("out");

var div2 = document.getElementsByClassName("in");

function outBlock(){

div1[0].style.display = "none"

}

function inBlock(){

alert("这是⼀个内层点击");

//event.cancelBubble = true;

event.stopPropagation();

}

</script>

 

 

异步--async和await


async created() {

  this.getOpList()

  await this.getDatasourceList()  // 这里是await的方法,在这个方法里return能起到异步加载完再进行下一步操作

  if (this.$route.name === '编辑指标') {

    // 基础指标数据回显

    const detail = await this.getElementDetail(this.$route.params.id)

    this.formData = detail

    this.formData.showDesc = true

    if (detail.elementType === 1 && detail.createType !== 1) {

      this.datasource = this.datasourceList.find(data => data.code === detail.sourceNumber)

      this.eleDetail = detail

      this.table = detail.fieldDetailVo

      this.isAnalysis = (detail.fieldDetailVo.find(v => v.isAnalysis === 1)).fieldName

      this.formData.dataType = (detail.fieldDetailVo.find(v => v.isAnalysis === 1)).type

      let list = detail.fieldDetailVo.filter(v => v.queryList?.length)

      list.forEach(item => {

        this.filterV1BoList[item.fieldName] = item.queryList.map(v => {

          v.equation = String(v.equation)

          v.equationName = (this.opList.find(a => a.id === v.equation)).name

          return v

        })

        item.linkType = item.queryList[0].linkType

        this.getLogicText(item.fieldName)

      })

      this.formData.description = this.eleDetail.description

    }

    this.initOpenStatus = this.formData.openStatus

    if (detail.elementType === 2) {

      this.checkLowerLevel()

    }

  }

},

 

 

methods: {

    async getDatasourceList() {

      const res = await api.getDatasourceList()

      this.datasourceList = res

      return

    },

}

 

 

宏任务

$nexTick()

 

 

 

[GMD UI]  form表单 required 提示英文改中文

 

    最近发现 el-form 的 el-form-item 配置 required 之后 提示是英文,类似 “xxx is required”:

 

    ...

 

    即使是表单验证或是自定义校验规则,只要有在标签上设置的required,就会或是在 不经意间 出现英文提示。。。

 

    正确做法:

 

    去掉标签上设置的required;

    使用 rules 上的 required 设置:

    data() {

      return {

rules: {

  content: [

    { required: true, message: '请输入内容', trigger: 'blur' }

  ]

}

      }

    }

    即使是自定义校验规则也必须使用 rules 上的 required 设置,才可以实现 * ,自定义校验规则 的 判空验证 不能代替 required 设置!!!

    

    

crypto.js加密+解密

 


/** * AES加密 【前端】

* @param content 明文

* @param encryptKey 秘钥,必须为16个字符组成

* @return 密文

* @throws Exception */

 

安装:npm i crypto.js

 

引入:import CryptoJS from 'crypto-js'


// 加密

let aseKey = '2022tianxrda0620' // 秘钥必须为:8/16/32位

let encrypt = CryptoJS.AES.encrypt(this.model.reportContent, CryptoJS.enc.Utf8.parse(aseKey), {

  mode: CryptoJS.mode.ECB,

  padding: CryptoJS.pad.Pkcs7,

}).toString()

this.model.reportContent = encrypt

 

// 解密

let decrypt = CryptoJS.AES.decrypt(data.reportContent, CryptoJS.enc.Utf8.parse(aseKey), {

  mode: CryptoJS.mode.ECB,

  padding: CryptoJS.pad.Pkcs7,

}).toString(CryptoJS.enc.Utf8)

data.reportContent = decrypt

 

 

 

场景:选择月报下拉框,多月多选,且每月只能选一项其余禁用;

 


<gmd-col :span="10">

  <gmd-form-model-item

    :label-col="{ span: 8 }"

    :wrapper-col="{ span: 16 }"

    label="选择月报名称"

    prop="monthReportName"

  >

    <gmd-select

      style="width:230px"

      v-model="model.monthReportName"

      placeholder="请选择测评月报"

      @change="handleSetReport"

      :mode="selectMode"

    >

      <gmd-select-option

        v-for="item in monthReportOptions"

        :key="item.id"

        :value="item.id"

        :disabled="handleDisabled(item)"

      >

        {{ item.monthName }}

      </gmd-select-option>

    </gmd-select>

  </gmd-form-model-item>

</gmd-col>

 


handleDisabled(value) {

  const date = new Date(value.fetchedAt)

  const year = date.getFullYear()

  const month = date.getMonth() + 1

  let result = false

  if (this.selectMode === 'multiple') {

    this.model.monthReportName.forEach(val => {

      this.monthReportOptions.find(item => {

        if (item.id === val) {

          let y = new Date(item.fetchedAt).getFullYear()

          let m = new Date(item.fetchedAt).getMonth() + 1

          if (y === year && m === month && item.id !== value.id) {

            result = true

          }

        }

      })

    })

  }

  return result

},

 

 

导出功能

 

场景:页面的HTML内容导出word文档


async exportWord() {

  let titleStr = `<div data-v-9ceee822="" style="text-align: center;margin-bottom: 20px"><h1 data-v-9ceee822="" style="font-size: 18px;line-height: 28px;margin-bottom: 5px;color: #0D1C28">${this.data.title}</h1><span data-v-9ceee822="">报告类型:${this.reportTypes[this.data.reportType] || '-'}</span></div>`

  let params = {

    connent: titleStr + this.data.reportContent,

    fileName: this.data.title + '.doc',

  }

  const resData = await api.exportWord(params)

  let arr = []

  arr.push(resData.data)

  const url = window.URL.createObjectURL(new Blob(arr))

  const fileName = decodeURIComponent(resData.headers['content-disposition'].split(';')[1].split('=')[1])

  newWindowTo(url, fileName)

},

 

newWindowTo方法:


// 创建一个<a></a>标签,点击后新窗口打开,然后移除该标签

export function newWindowTo(url, fileName) {

  const alink = document.createElement('a')

  alink.setAttribute('href', url)

  alink.setAttribute('target', '_blank')

  if (fileName) alink.setAttribute('download', fileName || true)

  document.getElementsByTagName('body')[0].appendChild(alink)

  alink.click()

  alink.remove()

}

 

JS的decodeURIComponent()函数:decodeURIComponent() 函数可对 encodeURIComponent() 函数编码的 URI 进行解码。

 

 

 

 

场景:选择月报下拉框,多月多选且每月只能选一项其余禁用

 

【根据后台返回字段 fetchedAt: 2022-07-04】

 

 

image.png

 

 


<gmd-col :span="10">

  <gmd-form-model-item

    :label-col="{ span: 8 }"

    :wrapper-col="{ span: 16 }"

    label="选择月报名称"

    prop="monthId"

  >

    <gmd-select

      style="width: 230px"

      v-model="model.monthId"

      placeholder="请选择测评月报"

      @change="handleSetReport"

      :mode="selectMode"

      :disabled="isEditting"

    >

      <gmd-select-option

        v-for="item in monthReportOptions"

        :key="item.id"

        :value="item.id"

        :disabled="handleDisabled(item)"

      >

        {{ item.monthName }}

      </gmd-select-option>

    </gmd-select>

  </gmd-form-model-item>

</gmd-col>

 

 


 

handleDisabled(value) {

  const date = new Date(value.fetchedAt)

  const year = date.getFullYear()

  const month = date.getMonth() + 1

  let result = false

  if (this.selectMode === 'multiple') {

    this.model.monthId.forEach((val) => {

      this.monthReportOptions.find((item) => {

        if (item.id === val) {

          let y = new Date(item.fetchedAt).getFullYear()

          let m = new Date(item.fetchedAt).getMonth() + 1

          if (y === year && m === month && item.id !== value.id) {

            result = true

          }

        }

      })

    })

  }

  return result

},

 

 

 

生成随机几位小写字母


 

getEngNum() {

  let result = []

  for (let i = 0; i < 4; i++) {

    let ranNum = Math.ceil(Math.random() * 25)

    result.push(String.fromCharCode(65 + ranNum))

  }

 

  return result.join('').toLowerCase()

},

 

 

 

 

报错信息分析

 


vue报错Uncaught (in promise)    TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))

 

 

通常是因为:有个undefined的属性搞了散列【例如:let { data, count } = undefined

 

 

ES6特性--属性的散列


ES6特性:属性的散列:前端必会数据结构与算法系列之散列表(四)

 

https://juejin.cn/post/6885534619039596557#heading-2

 

 

根据年月份获取天数


getDaysInMonth(year, month) {

  // parseInt(number,type)这个函数后面如果不跟第2个参数来表示进制的话,默认是10进制。

  let nowmonth = parseInt(month, 10)

  let temp = new Date(year, nowmonth, 0)

  return temp.getDate()

},

MutationObserver监听DOM

插入在可以找到dom的时候【监听dom操作】

例一:

hanldeObserver() {
  if (this.isMonthReportContent) {
    // 选择需要观察变动的节点(获取到DOM)
    const oneMonthNode = document.getElementById('oneMonth')
    const moreMonthNode = document.getElementById('moreMonth')
    const targetNode = oneMonthNode ? oneMonthNode : moreMonthNode
    // 观察器的配置(需要观察什么变动)
    const config = { attributes: true, childList: true, subtree: true }
    // 当观察到变动时执行的回调函数
    const callback = () => {
      console.log('触发回调11111')
      this.model.finishType = 0
      this.jgyTips = '修改问题情况后, 只能选择监管员处理'
    }
    // 创建一个观察器实例并传入回调函数
    const observer = new MutationObserver(callback)
    // 以上述配置开始观察目标节点
    observer.observe(targetNode, config)
    // 之后,可停止观察
    // observer.disconnect()
  }
},

例二:

//  使用MutationObserver方法监听DOM元素【某个DOM元素的高度变化】
function handleObserver() {
  const queryBarRef = document.getElementById('query-bar')
  const observer = new MutationObserver((mutationsList) => {
    for (let mutation of mutationsList) {
      if (mutation.type === 'attributes') {
        console.log('Element height changed')
        // 在DOM元素高度变化时执行的逻辑
        if (queryBarRef.offsetHeight === 144) {
          tableHeight.value = 468
        } else {
          tableHeight.value = 380
        }
      }
    }
  })
  if (queryBarRef) {
    observer.observe(queryBarRef, { attributes: true })
  }
  return () => {
    if (queryBarRef) {
      observer.disconnect()
    }
  }
}

可编辑DIV【可编辑框】

例一:

// 插入自定义内容至可编辑div框  Easy版[适用简单页面场景]
// function insertAtCursorInEditor(dom, text) {
//   let sel, range
//   if (window.getSelection) {
//     sel = window.getSelection()
//     if (!dom.contains(sel?.anchorNode)) {
//       return false
//     }
//     if (sel.getRangeAt && sel.rangeCount) {
//       range = sel.getRangeAt(0)
//       range.deleteContents()
//       let el = document.createElement('div')
//       el.innerHTML = `<span contenteditable="false">${text}</span>`
//       let frag = document.createDocumentFragment(),
//         node,
//         lastNode
//       while ((node = el.firstChild)) {
//         lastNode = frag.appendChild(node)
//       }
//       range.insertNode(frag)
//       if (lastNode) {
//         range = range.cloneRange()
//         range.setStartAfter(lastNode)
//         range.collapse(true)
//         sel.removeAllRanges()
//         sel.addRange(range)
//       }
//     }
//   } else if (document.selection && document.selection.type !== 'Control') {
//     document.selection.createRange().pasteHTML(text)
//   }
//   return true
// }

例二:

// Complex复杂版[适用某项目] [插入自定义内容至可编辑div框]  
export function insertAtCursorInEditor(dom, text, isEditable = true) {  
if (window.getSelection) {  
if (!dom.savedRange) return false  
const newNode = document.createElement('span')  
newNode.contentEditable = isEditable  
newNode.innerHTML = text  
dom.savedRange.deleteContents()  
dom.savedRange.insertNode(newNode)  
dom.savedRange.setStartAfter(newNode)  
dom.savedRange.setEndAfter(newNode)  
const sel = window.getSelection()  
sel.removeAllRanges()  
sel.addRange(dom.savedRange)  
} else if (document.selection && document.selection.type !== 'Control') {  
document.selection.createRange().pasteHTML(text)  
}  
return true  
}

// 例:《算法框组件封装》
// 可编辑div框内置方法【存储焦点位置】 
const storeSelectionI = event => {  
const objId = event.target.id  
let [num1, num2] = getBothStrNum(objId)  
const secDigitObjAreaRef = document.getElementById(objId)  
const sel = window.getSelection()  
if (sel.rangeCount > 0) {  
secDigitObjAreaRef.savedRange = sel.getRangeAt(0)  
}  
firstTableData.value[sfEditModal.value.currentIndex].modelNumberArithmeticEditBo.secDigitList[num1].term.rulesTableData[  
num2  
].object = secDigitObjAreaRef.textContent  
}  

// 插入内容至可编辑div框
const secDigitObjAddText = (str, rowIndex, index, type) => {  
const secDigitObjAreaRef = document.getElementById(`sec${rowIndex}obj${index}`)  
secDigitObjAreaRef.focus()  
let text = type === 0 ? `{${str}}` : str  
const isEditable = type !== 0  
insertAtCursorInEditor(secDigitObjAreaRef, text, isEditable)  
firstTableData.value[sfEditModal.value.currentIndex].modelNumberArithmeticEditBo.secDigitList[rowIndex].term.rulesTableData[  
index  
].object = secDigitObjAreaRef.textContent  
}

 

一些封装好的快捷小方法

// 获取单数字字符串-->数字  
export function getAnStrNum(str) {  
return str.match(/\d+/g).join('')  
}  
  
// 获取双数字字符串-->对应数字  
export function getBothStrNum(str) {  
let [, , num1, , num2] = str.match(/^(\D*)(\d+)(\D*)(\d+)$/)  
return [num1, num2]  
}

// 判断【两个带','的字符串】str2基于str1是否有新增项
export function whetherNewStr(str1, str2) {  
let result = false  
const set1 = new Set(str1.split(','))  
const set2 = new Set(str2.split(','))  
const newItems = [...set2].filter(item => !set1.has(item))  
result = newItems.length > 0  
return result  
}

// 计算嵌套表格B相对于表格A的最终索引
const sumBLengthBeforeIndexA = (arrA, indexA, indexB) => {
  let sum = 0
  for (let i = 0; i < indexA; i++) {
    sum += arrA[i].term.rulesTableData.length
  }
  return sum + indexB
}

// 判断是否为空数据(含多种数据类型)
function isNullOrUndefined(value) {  
return value === null || value === undefined  
}  
function isEmptyString(value) {  
return typeof value === 'string' && value.trim() === ''  
}  
function isEmptyObject(value) {  
return Object.keys(value).length === 0 && value.constructor === Object  
}  
function isEmptyArray(value) {  
return Array.isArray(value) && value.length === 0  
}  
export const isEmpty = value => {  
return isNullOrUndefined(value) || isEmptyString(value) || isEmptyObject(value) || isEmptyArray(value)  
}

// 转换空数据为'---'(数据类型为数组)
export const transferEmptyData = table => {  
    table.map(item => {  
        Object.entries(item).forEach(([k, v]) => {  
            if (v === '' || v === null) item[k] = '---'  
        })  
    })  
    return table  
}

// 转换空数据为'---'(数据类型为对象)
export const transferEmptyObjData = data => {  
    Object.entries(data).forEach(([k, v]) => {  
        if (v === '' || v === null) data[k] = '---'  
    })  
    return data  
}

// 清空对象
export const emptyObjData = data => {
  Object.entries(data).forEach(([k, v]) => {
    data[k] = ''
  })
  return data
}

// 正则校验是否为日期时间格式
export const isDateTime = str => {  
    const reg = /^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})$/  
    return reg.test(str)  
}

导出/下载【使用window.open】

function handleDownload(id) {  
const baseUrl = window.location.origin  
const devUrl = import.meta.env.MODE === 'development' ? '/ythjgpt-eas' : '/ythjgpt-admin/admin/apis/ythjgpt-eas'  
// const url = location.origin + devUrl + `/file/manage/download?fileRecordId=${id}`  
const url = `${baseUrl}${devUrl}/file/manage/download?fileRecordId=${id}`  
window.open(url)  
}

Vue3--自定义Hooks

例:

export function usePagination(handleSearch) {  
const pagination = ref({  
current: 1,  
pageSize: 10,  
total: 0,  
showQuickJumper: true,  
pageSizeOptions: ['10', '20', '30', '40', '50'],  
showSizeChanger: true,  
showTotal: total => `共 ${total} 条数据`  
})  
function pageChange(pagination) {  
setPagination(pagination)  
handleSearch?.(false)  
}  
function setPagination(data) {  
const { current, pageSize, total } = data  
pagination.value.current = current  
pagination.value.pageSize = pageSize  
pagination.value.total = total  
}  
const showSizeChange = (current, pageSize) => {  
pagination.value.pageSize = pageSize  
}  
  
return {  
pagination,  
pageChange,  
showSizeChange  
}  
}