1、复制内容到剪切板
private allCopy(list:any) { // 全部复制
let input = document.createElement('textarea')
// let input = document.createElement('input') // 复制单行时用input,要折行时用textarea
input.setAttribute('readonly', 'readonly') // 防止手机上弹出软键盘
const value = list.account + '\n' + list.password + '\n' + list.msg
input.value = value
document.body.appendChild(input)
input.select()
var res = document.execCommand('copy');
document.body.removeChild(input);
Toast('复制成功')
}
2、导出
// InvoiceApplyInteractor.infoExport 封装的promise方法
InvoiceApplyInteractor.infoExport(params).then((res:any) => {
console.info(res, 'res')
if (!res || res.code === 1) {
this.$message.error('导出接口错误!')
return
}
const blob = new Blob([res.data])
const contentDisposition = res.headers['content-disposition']
const pattern = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
const result = pattern.exec(contentDisposition)
const fileName = decodeURI(result[1]) // 使用decodeURI对名字进行解码
const downloadElement = document.createElement('a')
const href = window.URL.createObjectURL(blob) // 创建下载的链接
// console.info(href, 'href')
downloadElement.style.display = 'none'
downloadElement.href = href
// 下载后文件名
downloadElement.download = fileName
document.body.appendChild(downloadElement)
// 点击下载
downloadElement.click()
// 下载完成移除元素
document.body.removeChild(downloadElement)
// 释放掉blob对象
window.URL.revokeObjectURL(href)
})
// 在请求header.config中 加入 responseType: 'blob'
3、H5支付宝支付奇怪问题
const div = document.createElement('div')
div.innerHTML = res.data // 这个res.data 就是接口返回的form
document.body.appendChild(div)
// document.forms[0].setAttribute('target', '_blank') // 当在Sarfai浏览器时,加上这行带回会无法唤起。日了狗
document.forms[0].submit()
4、vant van-field禁止输入空格
// 直接加入formatter属性
:formatter="formatter"
private formatter(val:string) { // 不让输入空格
return val.replace(/\s+/g, '')
}
5、H5页面引入微信分享
- 问题1、分享的路径域名需要在公众平台配置安全域名;
- 问题2、vue中不能使用.push() 跳转至需要分享的页面,使用window.location.href = url
private async wxInit() {
const url = window.location.href
const { data } = await SignUpInteractor.wxInit({ // 这是个请求后端接口
url: url
})
console.log(data)
if (data.code === 0) {
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: data.data.appId, // 必填,公众号的唯一标识
timestamp: data.data.timestamp, // 必填,生成签名的时间戳
nonceStr: data.data.nonceStr, // 必填,生成签名的随机串
signature: data.data.signature, // 必填,签名
jsApiList: [
'updateTimelineShareData',
'updateAppMessageShareData',
'hideMenuItems'
] // 必填,需要使用的JS接口列表
})
wx.checkJsApi({
jsApiList: ['updateTimelineShareData', 'updateAppMessageShareData'], // 需要检测的JS接口列表,所有JS接口列表见附录2,
success: function(res:any) {
console.log(res)
// 以键值对的形式返回,可用的api值true,不可用为false
// 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
}
})
} else {
Toast('微信sdk初始化失败')
}
}
private async wxReady() {
const _this = this
wx.ready (function () {
console.log('shifouzhixingready')
//分享微信朋友圈
wx.updateTimelineShareData({
imgUrl : '',
link : _this.shareLink,
title : _this.headerInfo.title,
success : function () { // 分享成功可以做相应的数据处理
Toast('分享朋友圈成功!')
}
})
//分享给朋友
wx.updateAppMessageShareData({
title: _this.headerInfo.title, // 分享标题
desc: '这是一个' + _this.headerInfo.title, // 分享描述
link: _this.shareLink,
imgUrl: '', // 分享图标
success: function () {
Toast('分享成功!')
}
})
wx.hideMenuItems({
menuList: [] // 要隐藏的菜单项,只能隐藏“传播类”和“保护类”按钮,所有menu项见附录3
})
})
}
6、app内嵌入h5微信支付
- 问题1、正常encodeURIComponent redirect_url回调地址后,如果需要拼接的参数较多可能会有参数丢失的情况,解决方法:可将参数都放到一个对象里转成字符串(这样差不多就行),但是我这加上了base64编码。回调回来时解析base64然后取值判断即可。
- 问题2、一般情况请听从官方文档,不要使用H5微信支付内嵌到app,在安卓情况下,系统自带的回退hirstory.back()会造成跳转至唤起支付(也可能是我太菜,没有捋清楚跳转逻辑)
7、关于使用React antDesign 做后台管理系统遇到的问题
——当前开发版和build后的test上渲染标签样式及交互效果不同。在各种找原因后,发现是因为没有锁定版本的问题,然后项目中.gitignore忽略了package-lock.json的提交。 日了
8、阿拉伯数字转汉字(这是copy大佬的代码,blog.csdn.net/TKP666/arti…)
export function toChinesNum(num) { // 阿拉伯数字转汉字
let changeNum = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
let unit = ['', '十', '百', '千', '万']
num = parseInt(num)
let getWan = (temp) => {
let strArr = temp.toString().split('').reverse()
let newNum = ''
let newArr = []
strArr.forEach((item, index) => {
newArr.unshift(item === '0' ? changeNum[item] : changeNum[item] + unit[index])
})
let numArr = []
newArr.forEach((m, n) => {
if (m !== '零') numArr.push(n)
})
if (newArr.length > 1) {
newArr.forEach((m, n) => {
if (newArr[newArr.length - 1] === '零') {
if (n <= numArr[numArr.length - 1]) {
newNum += m
}
} else {
newNum += m
}
})
} else {
newNum = newArr[0]
}
return newNum
}
let overWan = Math.floor(num / 10000)
let noWan = num % 10000
if (noWan.toString().length < 4) {
noWan = '0' + noWan
}
return overWan ? getWan(overWan) + '万' + getWan(noWan) : getWan(num)
}
9、将秒数转成时分秒
export function formatSeconds(value=0) { // 将秒数转成时分秒
var secondTime = parseInt(value);// 秒
var minuteTime = 0;// 分
var hourTime = 0;// 小时
if(secondTime > 60) {//如果秒数大于60,将秒数转换成整数
//获取分钟,除以60取整数,得到整数分钟
minuteTime = parseInt(secondTime / 60);
//获取秒数,秒数取余,得到整数秒数
secondTime = parseInt(secondTime % 60);
//如果分钟大于60,将分钟转换成小时
if(minuteTime > 60) {
//获取小时,获取分钟除以60,得到整数小时
hourTime = parseInt(minuteTime / 60);
//获取小时后取余的分,获取分钟除以60取余的分
minuteTime = parseInt(minuteTime % 60);
}
}
var result = {
hour: parseInt(hourTime),
minute: parseInt(minuteTime),
second: parseInt(secondTime),
seconds: value
}
return result;
}
10、elementUI树节点选择转成 按照 省市区 排列的二维数组中文
入参选择的数据: [[2,50,51],[2,50,52],[2,53,54],[2,53,55],[56,74,75],[56,74,76]]
入参tree书结构数据 部分:
[{"id":2,"dataName":"江西省行政区域","option":"赣州市","isUsed":1,"label":0,"comment":"","parent":"1","childrenIds":"3,4,5,6,7,8,11,14,15,16,17,20,23,26,29,32,35,38,41,44,47,50,53","createdBy":"admin","createdAt":1667791569000,"updatedBy":"admin","updatedAt":1667791573000,"children":[
{"id":3,"dataName":"江西省行政区域","option":"赣州经济技术开发区(国家级)","isUsed":1,"label":1,"comment":"","parent":"2","childrenIds":"","createdBy":"admin","createdAt":1667791569000,"updatedBy":"admin","updatedAt":1667791569000,"children":[]},{"id":4,"dataName":"江西省行政区域","option":"赣州高新技术产业开发区(国家级)","isUsed":1,"label":1,"comment":"","parent":"2","childrenIds":"","createdBy":"admin","createdAt":1667791569000,"updatedBy":"admin","updatedAt":1667791569000,"children":[]}]}]
输出:[["赣州市","南昌市"],["宁都县","石城县","进贤县"],["宁都工业园","宁都县开发区外","石城产业园","石城县开发区外","江西进贤经济开发区","进贤县开发区外"]]
const tkitreeConfirmText = (data: Array<any>) => { // 将选择value转成label
filterLabel.value = []
const T = cloneDeep(treeWrap(filterOptions.value))
const A = dataMapWrap(data)
const a: Array<string[]> = []
for (let i = 0; i < A.length; i++) {
a[i] = []
}
// let a: any = new Array(Array(A.length), () => Array()) // 此处不要用这个,会因为指针问题导致数据被替换
A.forEach((f: Array<number>, i: number) => {
T.forEach(item => {
if (f.indexOf(item.id) !== -1) {
a[i].push(item.option)
}
})
})
filterLabel.value = a
}
const dataMapWrap = function (data: Array<number[]>) {
let aLen: number = 0
data?.forEach((len) => {
if (len.length > aLen) { aLen = len.length }
})
// let a: Array<number[]> = new Array(aLen).fill([])
const a: Array<number[]> = []
for (let i = 0; i < aLen; i++) {
a[i] = []
}
// console.log(a)
// let a: Array<number[]> = [[], [], []]
data.forEach((first) => {
for (let i = 0; i < first.length; i++) {
if (first[i] && a[i].indexOf(first[i]) === -1) {
a[i].push(first[i])
}
}
})
return a
}
const treeWrap = function (dataTree: any[], newTree: any[] = []) { // 将树结构整成一级
dataTree.forEach((tree) => {
const ct = JSON.parse(JSON.stringify(tree))
delete ct.children
newTree.push(ct)
if (tree.children.length) { treeWrap(tree.children, newTree) }
})
return newTree
}
11、Element ui-plus Tree节点获取半选节点及回显问题
// 我这里是动态的tree
// getHalfCheckedKeys()获取半选的父节点 getCheckedKeys()获取选中节点
const groupList = treeArrRefs.value[currentNodeKey.value + list.groupKey]?.getCheckedKeys().concat(treeArrRefs.value[currentNodeKey.value + list.groupKey]?.getHalfCheckedKeys())
// 回显时遍历返回携带父节点数据,先获取节点node,再使用setChecked设置。直接setCheckedKeys()会使半选父节点也处于勾选状态
list.forEach(i => {
const node = treeArrRefs.value[currentNodeKey.value + list.groupKey]?.getNode(i);
treeArrRefs.value[currentNodeKey.value + list.groupKey]?.setChecked(node, true);
})
12、前端实现发版后页面弹出提示
大致思路就是创建web worker线程循环请求项目版本号作对比。
1、定义初始方法
const fs = require('fs')
const path = require('path')
export function GenerateVersionFile(options) {
return {
name: 'vite-plugin-generate-version',
load() {
if (options && options.isGenerate) {
this.options = {
versionFileName: 'generate_version.json', // json 版本文件名称
keyName: 'UPDATE_VERSION', // json key 值
}
this.version = `${Date.now()}.0.0`
const filePath = path.resolve(__dirname, '../public', this.options.versionFileName) // __dirname当前执行的文件的根目录路径
// 生成文件
fs.writeFileSync(filePath, `{"${this.options.keyName}": "${this.version}"}`)
}
},
}
}
2、在vite.config.ts中引入使用
import { GenerateVersionFile } from './scripts/vite-plugin-generate-version.js'
const viteConfig = defineConfig((mode: ConfigEnv) => {
const env = loadEnv(mode.mode, process.cwd())
return {
plugins: [
GenerateVersionFile({ isGenerate: env.VITE_ENV !== 'localhost' }),
VueDevTools(),
vue(),
vueSetupExtend(),
viteCompression(),
],
...
}
})
export default viteConfig
3、在项目public文件夹中创建worker.js
const UPDATE_VERSION = 'UPDATE_VERSION'
function to(promise, errorExt = '读取文件错误!') {
return promise
.then(data => [null, data])
.catch(err => {
if (errorExt) {
const parsedError = Object.assign({}, err, errorExt)
return [parsedError, undefined]
}
return [err, undefined]
})
}
const fetchUpdateVersionFile = () => {
return new Promise((resolve, reject) => {
// 注意:文件请求路径 /generate_version.json,是相对于在 public 文件下的 index.html 的位置而言的,/generate_version.json 代表 generate_version.json 文件与 index.html 文件夹同目录。
fetch('/generate_version.json')
.then(res => {
return res.json()
})
.then(json => {
resolve(json)
})
.catch(err => {
reject(err)
})
})
}
self.onmessage = function ({ data }) {
fetchUpdateVersionFile().then(
res => {
if (!res[UPDATE_VERSION]) return
const inter = setInterval(async () => {
const [err, res] = await to(fetchUpdateVersionFile())
if (err) return
const currentVersion = data[UPDATE_VERSION]
if (res[UPDATE_VERSION] !== currentVersion) {
self.postMessage({ message: '版本更新了', isUpdate: true, version: res[UPDATE_VERSION] })
clearInterval(inter)
}
}, 1000 * 60)
},
err => {
console.log('更新版本:', err)
},
)
}
self.onerror = function (err) {
console.log(err)
}
4、在public中创建版本json文件generate_version.json
{ "UPDATE_VERSION": "1702610347668.0.0" }