1、JS浮点数兼容处理
example:加法
function plus(num1, num2) {
const num1Digits = (num1.toString().split('.')[1] || '').length
const num2Digits = (num2.toString().split('.')[1] || '').length
const baseNum = Math.pow(10, Math.max(num1Digits, num2Digits))
return (times(num1, baseNum) + times(num2, baseNum)) / baseNum
}
example:乘法
function times(num1, num2) {
const num1String = num1.toString()
const num2String = num2.toString()
const num1Digits = (num1String.split('.')[1] || '').length
const num2Digits = (num2String.split('.')[1] || '').length
const baseNum = Math.pow(10, num1Digits + num2Digits)
return Number(num1String.replace('.', '')) * Number(num2String.replace('.', '')) / baseNum
}
2、基于Vue读取txt文件
2-1、beforeCreate 生命周期定义方法
beforeCreate () {
/**
* 读取文件(自定义函数)
* @param pms {@link Object}:参数:
* @param pms.encode {@link String}:编码格式:
* @return {@link String}:文本内容;
*/
FileReader.prototype.reading = function ({ encode } = pms) {
let bytes = new Uint8Array(this.result); //无符号整型数组
let text = new TextDecoder(encode || 'UTF-8').decode(bytes);
return text;
};
/* 重写readAsBinaryString函数 */
FileReader.prototype.readAsBinaryString = function (f) {
if (!this.onload) //如果this未重写onload函数,则创建一个公共处理方式
this.onload = e => { //在this.onload函数中,完成公共处理
let rs = this.reading();
console.log(rs);
};
this.readAsArrayBuffer(f); //内部会回调this.onload方法
};
}
2、read函数
read (fileRaw) {
let rd = new FileReader();
rd.onload = e => { //this.readAsArrayBuffer函数内,会回调this.onload函数。在这里处理结果
let content = rd.reading({ encode: 'UTF-8' })
};
rd.readAsBinaryString(f);
}
3、从一个标签页发送消息到另一个标签页
3-1、Add lsbridge.min.js to your page:
<script src="js/lsbridge.min.js"></script>
3-2、Send messages:
lsbridge.send('my-namespace', { message: 'Hello world!' });
3-3、Listen for messages:
lsbridge.subscribe('my-namespace', function(data) {
console.log(data); // prints: { message: 'Hello world!'}
});
3-4、Cancel listeners for specific namespace:
lsbridge.unsubscribe('my-namespace');
lsbridge.min.js
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define([], factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
root.lsbridge = factory();
}
}(this, function () {
/*
- Storing messages in localStorage.
- Clients subscribe to the changes and
they get notified if a new message arrives.
*/
var api = {};
api.isLSAvailable = (function () {
var mod = '_';
try {
localStorage.setItem(mod, mod);
localStorage.removeItem(mod);
return true;
} catch (e) {
return false;
}
})();
if (api.isLSAvailable) {
var interval = 100
, intervalForRemoval = 200
, ls = localStorage
, listeners = {}
, isLoopStarted = false
, buffer = {};
var loop = function () {
for (var namespace in listeners) {
var data = ls.getItem(namespace);
if (data && buffer[namespace] && buffer[namespace].indexOf(data) === -1) {
buffer[namespace].push(data);
try {
var parsed = JSON.parse(data);
if (parsed) data = parsed;
} catch (e) { }
for (var i = 0; i < listeners[namespace].length; i++) {
listeners[namespace][i](data);
}
if (!ls.getItem(namespace + '-removeit')) {
ls.setItem(namespace + '-removeit', '1');
(function (n) {
setTimeout(function () {
ls.removeItem(n);
ls.removeItem(n + '-removeit');
buffer[namespace] = [];
}, intervalForRemoval);
})(namespace);
}
} else if (!data) {
buffer[namespace] = [];
}
}
setTimeout(loop, interval);
return true;
};
api.send = function (namespace, data) {
var raw = '';
if (typeof data === 'function') { data = data(); }
if (typeof data === 'object') {
raw = JSON.stringify(data);
} else {
raw = data;
}
ls.setItem(namespace, raw);
};
api.subscribe = function (namespace, cb) {
if (!listeners[namespace]) {
listeners[namespace] = [];
buffer[namespace] = [];
}
listeners[namespace].push(cb);
if (!isLoopStarted) {
isLoopStarted = loop();
}
};
api.unsubscribe = function (namespace) {
if (listeners[namespace]) {
listeners[namespace] = [];
}
if (buffer[namespace]) {
buffer[namespace] = [];
}
};
api.getBuffer = function () {
return buffer;
}
} else {
api.send = api.subscribe = function () {
throw new Error('localStorage not supported.');
}
}
return api;
}));
4、基于Vue纯前端导出Excel
4-1、安装依赖(三个)
npm install file-saver xlsx -S
npm install script-loader -D // 加载script 需要
4-2、src目录下引入所需文件
/src 目录下新建 vendor文件夹,用于存放 Blob.js 和 Export2Excel.js 文件 后附这两个文件 注意:如果不叫 vendor 名字,则需要修改 Export2Excel.js 中的代码。
4-2-1 配置webpack,如果用的是cli-2搭建的项目
在 /build/webpack.base.config.js 的resolve 模块中添加一个别名
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
'vendor': path.resolve(__dirname, 'src/vendor') // 添加一个别名
}
}
4-2-2 配置webpack,如果用的是cli-3搭建的项目
在 vue.config.js 的resolve 模块中添加一个别名
const path = require('path')
function resolve(dir) {
return path.join(__dirname, dir)
}
module.exports = {
outputDir: 'fxop',
runtimeCompiler: true, // 包含编译器
publicPath: process.env.BASE_URL || './',
productionSourceMap: false,
transpileDependencies: ['element-ui-verify/dist', 'vue-echarts', 'resize-detector'],
chainWebpack: config => {
// 设置一些别名
config.resolve.alias.set('vendor', path.resolve(__dirname, 'src/vendor')).set('@', resolve('src'))
},
devServer: {
port: 8081,
proxy: {
'/': {
target: 'http://test.portal.ads.toponegames.mobi' /* 'http://172.16.2.174' 'http://192.168.64.1:8082' */,
ws: false,
changeOrigin: true
}
}
}
}
4-3、在vue中使用
<template>
<button @click="exportExcel">导出表格</button>
</template>
<script>
export default {
name: 'export',
data() {
return {
loading: false
};
},
methods: {
exportExcel() {
let sourceOriginAmount = [
{
goodsName: '苹果',
sourceCode: '123'
},
{
goodsName: '香蕉',
sourceCode: '234'
}
]; // 需要导出的数据,可以动态获取
this.loading = true; // 设置一个loading,生成Excel需要时间
import('@/vendor/Export2Excel.js').then(excel => { // 导入js模块
const tHeader = ['编号', '商品名称', '溯源码']; // 导出excel 的标题
const filterVal = ['index', 'goodsName', 'sourceCode']; // 每个标题对应的字段
const list = (sourceOriginAmount || []).map((item, key) => { // 通过 map 方法遍历,组装数据成上面的格式
return {
index: key + 1,
goodsName: item.goodsName,
sourceCode: item.key
};
});
if (list) {
const data = this.formatJson(filterVal, list); // 生成json数据
excel.export_json_to_excel({ // 调用excel方法生成表格
header: tHeader,
data,
filename: this.goodsName
});
} else {
alert('暂无无数据');
}
this.loading = false;
})
},
formatJson (filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => v[j]));
}
}
};
</script>
4-4 文件附录:
/* eslint-disable */
/* Blob.js
* A Blob implementation.
* 2014-05-27
*
* By Eli Grey, http://eligrey.com
* By Devin Samarin, https://github.com/eboyjr
* License: X11/MIT
* See LICENSE.md
*/
/*global self, unescape */
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
plusplus: true */
/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */
;(function(view) {
'use strict'
view.URL = view.URL || view.webkitURL
if (view.Blob && view.URL) {
try {
new Blob()
return
} catch (e) {}
}
// Internally we use a BlobBuilder implementation to base Blob off of
// in order to support older browsers that only have BlobBuilder
var BlobBuilder =
view.BlobBuilder ||
view.WebKitBlobBuilder ||
view.MozBlobBuilder ||
(function(view) {
var get_class = function(object) {
return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1]
},
FakeBlobBuilder = function BlobBuilder() {
this.data = []
},
FakeBlob = function Blob(data, type, encoding) {
this.data = data
this.size = data.length
this.type = type
this.encoding = encoding
},
FBB_proto = FakeBlobBuilder.prototype,
FB_proto = FakeBlob.prototype,
FileReaderSync = view.FileReaderSync,
FileException = function(type) {
this.code = this[(this.name = type)]
},
file_ex_codes = (
'NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR ' +
'NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR'
).split(' '),
file_ex_code = file_ex_codes.length,
real_URL = view.URL || view.webkitURL || view,
real_create_object_URL = real_URL.createObjectURL,
real_revoke_object_URL = real_URL.revokeObjectURL,
URL = real_URL,
btoa = view.btoa,
atob = view.atob,
ArrayBuffer = view.ArrayBuffer,
Uint8Array = view.Uint8Array
FakeBlob.fake = FB_proto.fake = true
while (file_ex_code--) {
FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1
}
if (!real_URL.createObjectURL) {
URL = view.URL = {}
}
URL.createObjectURL = function(blob) {
var type = blob.type,
data_URI_header
if (type === null) {
type = 'application/octet-stream'
}
if (blob instanceof FakeBlob) {
data_URI_header = 'data:' + type
if (blob.encoding === 'base64') {
return data_URI_header + ';base64,' + blob.data
} else if (blob.encoding === 'URI') {
return data_URI_header + ',' + decodeURIComponent(blob.data)
}
if (btoa) {
return data_URI_header + ';base64,' + btoa(blob.data)
} else {
return data_URI_header + ',' + encodeURIComponent(blob.data)
}
} else if (real_create_object_URL) {
return real_create_object_URL.call(real_URL, blob)
}
}
URL.revokeObjectURL = function(object_URL) {
if (object_URL.substring(0, 5) !== 'data:' && real_revoke_object_URL) {
real_revoke_object_URL.call(real_URL, object_URL)
}
}
FBB_proto.append = function(data /*, endings*/) {
var bb = this.data
// decode data to a binary string
if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
var str = '',
buf = new Uint8Array(data),
i = 0,
buf_len = buf.length
for (; i < buf_len; i++) {
str += String.fromCharCode(buf[i])
}
bb.push(str)
} else if (get_class(data) === 'Blob' || get_class(data) === 'File') {
if (FileReaderSync) {
var fr = new FileReaderSync()
bb.push(fr.readAsBinaryString(data))
} else {
// async FileReader won't work as BlobBuilder is sync
throw new FileException('NOT_READABLE_ERR')
}
} else if (data instanceof FakeBlob) {
if (data.encoding === 'base64' && atob) {
bb.push(atob(data.data))
} else if (data.encoding === 'URI') {
bb.push(decodeURIComponent(data.data))
} else if (data.encoding === 'raw') {
bb.push(data.data)
}
} else {
if (typeof data !== 'string') {
data += '' // convert unsupported types to strings
}
// decode UTF-16 to binary string
bb.push(unescape(encodeURIComponent(data)))
}
}
FBB_proto.getBlob = function(type) {
if (!arguments.length) {
type = null
}
return new FakeBlob(this.data.join(''), type, 'raw')
}
FBB_proto.toString = function() {
return '[object BlobBuilder]'
}
FB_proto.slice = function(start, end, type) {
var args = arguments.length
if (args < 3) {
type = null
}
return new FakeBlob(this.data.slice(start, args > 1 ? end : this.data.length), type, this.encoding)
}
FB_proto.toString = function() {
return '[object Blob]'
}
FB_proto.close = function() {
this.size = this.data.length = 0
}
return FakeBlobBuilder
})(view)
view.Blob = function Blob(blobParts, options) {
var type = options ? options.type || '' : ''
var builder = new BlobBuilder()
if (blobParts) {
for (var i = 0, len = blobParts.length; i < len; i++) {
builder.append(blobParts[i])
}
}
return builder.getBlob(type)
}
})((typeof self !== 'undefined' && self) || (typeof window !== 'undefined' && window) || this.content || this)
/* eslint-disable */
require('script-loader!file-saver')
require('script-loader!@/vendor/Blob')
import XLSX from 'xlsx'
function generateArray(table) {
var out = []
var rows = table.querySelectorAll('tr')
var ranges = []
for (var R = 0; R < rows.length; ++R) {
var outRow = []
var row = rows[R]
var columns = row.querySelectorAll('td')
for (var C = 0; C < columns.length; ++C) {
var cell = columns[C]
var colspan = cell.getAttribute('colspan')
var rowspan = cell.getAttribute('rowspan')
var cellValue = cell.innerText
if (cellValue !== '' && cellValue == +cellValue) cellValue = +cellValue
//Skip ranges
ranges.forEach(function(range) {
if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) {
for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null)
}
})
//Handle Row Span
if (rowspan || colspan) {
rowspan = rowspan || 1
colspan = colspan || 1
ranges.push({ s: { r: R, c: outRow.length }, e: { r: R + rowspan - 1, c: outRow.length + colspan - 1 } })
}
//Handle Value
outRow.push(cellValue !== '' ? cellValue : null)
//Handle Colspan
if (colspan) for (var k = 0; k < colspan - 1; ++k) outRow.push(null)
}
out.push(outRow)
}
return [out, ranges]
}
function datenum(v, date1904) {
if (date1904) v += 1462
var epoch = Date.parse(v)
return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000)
}
function sheet_from_array_of_arrays(data, opts) {
var ws = {}
var range = { s: { c: 10000000, r: 10000000 }, e: { c: 0, r: 0 } }
for (var R = 0; R != data.length; ++R) {
for (var C = 0; C != data[R].length; ++C) {
if (range.s.r > R) range.s.r = R
if (range.s.c > C) range.s.c = C
if (range.e.r < R) range.e.r = R
if (range.e.c < C) range.e.c = C
var cell = { v: data[R][C] }
if (cell.v == null) continue
var cell_ref = XLSX.utils.encode_cell({ c: C, r: R })
if (typeof cell.v === 'number') cell.t = 'n'
else if (typeof cell.v === 'boolean') cell.t = 'b'
else if (cell.v instanceof Date) {
cell.t = 'n'
cell.z = XLSX.SSF._table[14]
cell.v = datenum(cell.v)
} else cell.t = 's'
ws[cell_ref] = cell
}
}
if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range)
return ws
}
function Workbook() {
if (!(this instanceof Workbook)) return new Workbook()
this.SheetNames = []
this.Sheets = {}
}
function s2ab(s) {
var buf = new ArrayBuffer(s.length)
var view = new Uint8Array(buf)
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff
return buf
}
export function export_table_to_excel(id) {
var theTable = document.getElementById(id)
var oo = generateArray(theTable)
var ranges = oo[1]
/* original data */
var data = oo[0]
var ws_name = 'SheetJS'
var wb = new Workbook(),
ws = sheet_from_array_of_arrays(data)
/* add ranges to worksheet */
// ws['!cols'] = ['apple', 'banan'];
ws['!merges'] = ranges
/* add worksheet to workbook */
wb.SheetNames.push(ws_name)
wb.Sheets[ws_name] = ws
var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' })
saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), 'test.xlsx')
}
export function export_json_to_excel({ header, data, filename = 'excel-list', autoWidth = true } = {}) {
/* original data */
data = [...data]
data.unshift(header)
var ws_name = 'SheetJS'
var wb = new Workbook(),
ws = sheet_from_array_of_arrays(data)
if (autoWidth) {
/*设置worksheet每列的最大宽度*/
const colWidth = data.map(row =>
row.map(val => {
/*先判断是否为null/undefined*/
if (val == null) {
return { wch: 10 }
} else if (val.toString().charCodeAt(0) > 255) {
/*再判断是否为中文*/
return { wch: val.toString().length * 2 }
} else {
return { wch: val.toString().length }
}
})
)
/*以第一行为初始值*/
let result = colWidth[0]
for (let i = 1; i < colWidth.length; i++) {
for (let j = 0; j < colWidth[i].length; j++) {
if (result[j]['wch'] < colWidth[i][j]['wch']) {
result[j]['wch'] = colWidth[i][j]['wch']
}
}
}
ws['!cols'] = result
}
/* add worksheet to workbook */
wb.SheetNames.push(ws_name)
wb.Sheets[ws_name] = ws
var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' })
saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), filename + '.xlsx')
}
5、小程序log日志
可根据对应的小程序环境执行不同日志输出
develop
开发环境 可以看到log的行数
trial
体验版环境 可在小程序的开发调试,看到log
release
线上版环境 需要用户反馈日志,从后台拉取
5.1 log文件
let log = wx.getLogManager ? wx.getLogManager({ level: 1 }) : null
export default {
debug() {
if (!log) return
log.debug.apply(log, arguments)
},
info() {
if (!log) return
log.info.apply(log, arguments)
},
warn() {
if (!log) return
log.warn.apply(log, arguments)
}
}
console.log = (function (oriLogFunc) {
return logCommon(oriLogFunc, 'info')
})(console.log)
console.warn = (function (oriLogFunc) {
return logCommon(oriLogFunc, 'warn')
})(console.warn)
function logCommon(oriLogFunc, type) {
const _envVersion = uni.getAccountInfoSync()?.miniProgram?.envVersion
switch (_envVersion) {
case 'develop':
return oriLogFunc
break
case 'trial':
case 'release':
default:
return function (...arg) {
oriLogFunc.call(console, ...arg)
log[type](...arg)
}
}
}
5.2 在main.js文件中引入
import './log'
6、uni-app 小程序 上传文件方法
/**
* 小程序专用上传文件方法
* @param {string} filePath 要上传文件资源的路径 (本地路径)
* @param {Object} formData HTTP 请求中其他额外的 form data
* @return {Promise}
*/
function uploadFile(filePath, formData) {
return new Promise((resolve, reject) => {
wx.uploadFile({
url: `${domain}${commonPath}/upload-files/upload`,
// header: {
// Authorization: 'Bearer ' + uni.getStorageSync('token')
// },
filePath,
name: 'file',
formData,
success(res) {
resolve(res)
},
fail(err) {
reject(err)
}
})
})
}
7、H5错误捕获上报
// 通过 VueErrorHandler 捕获的错误
// `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
Vue.config.errorHandler = (err, vm, info) => {
// console.log('err, vm, info: ', err, vm, info);
const msg = `发生在 ${info}; 具体信息 ${err};组件data:${JSON.stringify(
vm.$data
)}`
uploadLog('VueErrorHandler', msg)
}
// Promise catch错误上报,需要在使用promise的地方显示调用.catch(),否则不会捕获错误
if (typeof Promise !== 'undefined') {
const _promiseCatch = Promise.prototype.catch
Promise.prototype.catch = function(foo) {
return _promiseCatch.call(this, catCatch(foo))
}
}
function catCatch(foo) {
return function(args) {
const msg = args.stack ? args.stack : args
foo && foo.call(this, args)
uploadLog('PromiseCatch', msg)
}
}
// 监听页面的 JS Error 并上报
window.addEventListener('error', function(ex) {
// 一般事件的参数中会包含pos信息。
// logger && logger.error(ex.error, ex);
const msg = `发生在 ${ex.filename}; 具体信息 ${ex.message};`
uploadLog('JsError', msg)
})
// 通过 unhandledrejection 捕获的错误
// 监听promise未处理的reject错误, 跨域情况下监控不到
window.addEventListener('unhandledrejection', function(e) {
// console.log('e: unhandledrejection', e);
uploadLog('unhandledrejection', e.reason)
})
/**
* 上报数据
* @param {String} source 错误数据源头
* @param {String} msg 错误信息
*/
export const uploadLog = (source, msg) => {
// 如果msg是Object对象,需要转成字符串
if (Object.prototype.toString.call(msg) === '[object Object]') {
msg = JSON.stringify(msg)
}
const url = location.href // 页面URL
const ua = navigator.userAgent // userAgent
const content = `H5日志 *** | userID: ${userID} | 错误源:${source} |\r\n --- | 错误信息:${msg} |\r\n --- | 访问URL:${url} |\r\n --- | UserAgent:${ua} |`
jsBridgeClient.printLog(content)
}
8、微信小程序反编译
使用步骤,资源在网盘
1、获取微信小程序加密包
电脑微信使用小程序,使用 everything 工具,输入.wxapkg 后缀名,然后点击修改时间倒叙排序(要提前删除小程序,重新进入登录,才能准确找到小程序加密包)

进入文件夹,打开 UnpackMiniApp.exe 文件,选择需要破解的微信小程序包(注意:需要在和 UnpackMiniApp.exe 同级目录下,新建立)

2、解析获取混淆源码
破解之后会有一个新的 wxapkg 文件(在 wxpack 目录里面),放入 wxappUnpacker 目录,执行命令 npm run pkg wx1b17fa6e767ff55f.wxapkg, 转换为混淆过后的源码

9、预解析SVGA文件
/**
* SVGA文件预解析,并存在DB中
*/
import { Downloader, Parser } from 'svga.lite'
import DB from 'svga.lite/db'
/**
* 解析SVGA文件
* @param {Array[String]} fileList svga文件路径
*/
function parseFile(fileList) {
let data = void 0
let db = void 0
try {
db = new DB()
} catch (error) {
console.error(error)
}
const downloader = new Downloader()
const parser = new Parser()
fileList.forEach(async item => {
let curData = void 0
if (db) {
curData = await db.find(item)
}
if (!curData) {
const fileData = await downloader.get(item)
data = await parser.do(fileData)
// 插入数据
db && (await db.insert(item, data))
}
})
}
10、常用正则库
/**
* 校验手机号码格式
* @param {String} phone 手机号码
*/
export const isPhone = (phone) => {
return /^1(3|4|5|6|7|8|9)\d{9}$/.test(phone);
};
/**
* 校验邮政编码格式
* @param {String} postalCode 邮政编码
*/
export const isPostalCode = (postalCode) => {
return /^[1-9][0-9]{5}$/.test(postalCode);
};
/**
* 校验邮件地址格式
* @param {String} email 邮件地址
*/
export const isEmail = (email) => {
return /\w@\w*\.\w/.test(email);
};
/**
* 检测字符串是否包含中文
* @param {String} str 字符串
*/
export const isIncludeChinese = (str) => {
return /.*[\u4e00-\u9fa5]+.*$/.test(str);
};
/**
* 校验身份证格式
* @param {String} str 身份证号码
*/
export const isIdCard = (str) => {
return /(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)/.test(str)
}
/**
* 检测银行卡号格式
* @param {String} str 银行卡号
*/
export const luhmCheck = (bankno) => {
var lastNum = bankno.substr(bankno.length - 1, 1); //取出最后一位(与luhm进行比较)
var first15Num = bankno.substr(0, bankno.length - 1); //前15或18位
var newArr = new Array();
for (var i = first15Num.length - 1; i > -1; i--) { //前15或18位倒序存进数组
newArr.push(first15Num.substr(i, 1));
}
var arrJiShu = new Array(); //奇数位*2的积 <9
var arrJiShu2 = new Array(); //奇数位*2的积 >9
var arrOuShu = new Array(); //偶数位数组
for (var j = 0; j < newArr.length; j++) {
if ((j + 1) % 2 == 1) { //奇数位
if (parseInt(newArr[j]) * 2 < 9) arrJiShu.push(parseInt(newArr[j]) * 2);
else arrJiShu2.push(parseInt(newArr[j]) * 2);
} else //偶数位
arrOuShu.push(newArr[j]);
}
var jishu_child1 = new Array(); //奇数位*2 >9 的分割之后的数组个位数
var jishu_child2 = new Array(); //奇数位*2 >9 的分割之后的数组十位数
for (var h = 0; h < arrJiShu2.length; h++) {
jishu_child1.push(parseInt(arrJiShu2[h]) % 10);
jishu_child2.push(parseInt(arrJiShu2[h]) / 10);
}
var sumJiShu = 0; //奇数位*2 < 9 的数组之和
var sumOuShu = 0; //偶数位数组之和
var sumJiShuChild1 = 0; //奇数位*2 >9 的分割之后的数组个位数之和
var sumJiShuChild2 = 0; //奇数位*2 >9 的分割之后的数组十位数之和
var sumTotal = 0;
for (var m = 0; m < arrJiShu.length; m++) {
sumJiShu = sumJiShu + parseInt(arrJiShu[m]);
}
for (var n = 0; n < arrOuShu.length; n++) {
sumOuShu = sumOuShu + parseInt(arrOuShu[n]);
}
for (var p = 0; p < jishu_child1.length; p++) {
sumJiShuChild1 = sumJiShuChild1 + parseInt(jishu_child1[p]);
sumJiShuChild2 = sumJiShuChild2 + parseInt(jishu_child2[p]);
}
//计算总和
sumTotal = parseInt(sumJiShu) + parseInt(sumOuShu) + parseInt(sumJiShuChild1) + parseInt(sumJiShuChild2);
//计算Luhm值
var k = parseInt(sumTotal) % 10 == 0 ? 10 : parseInt(sumTotal) % 10;
var luhm = 10 - k;
var my = false;
if (lastNum == luhm) { //Luhm验证通过
my = true;
} else { //银行卡号必须符合Luhm校验
my = false;
}
return my;
}
中国大陆个人身份证号验证 github参考地址
11、解析mpkg文件
基于Vu3实现,借助 jszip 库
<script setup>
import { ref } from 'vue'
import JSZip from 'jszip'
const version = ref('')
const packagePath = ref('')
const fileName = ref('')
const isLoading = ref(false)
const error = ref('')
const handleFileUpload = async (event) => {
const file = event.target.files[0]
if (!file) return
fileName.value = file.name
isLoading.value = true
error.value = ''
version.value = ''
packagePath.value = ''
try {
// 使用JSZip解析文件
const zip = new JSZip()
const zipContent = await zip.loadAsync(file)
console.log('zipContent =>', zipContent)
// 查找package.json和project.json文件
let packageJsonFile = null
let projectJsonFile = null
// 递归查找文件
const findFile = (obj, currentPath, targetFileName) => {
for (const [relativePath, entry] of Object.entries(obj)) {
const fullPath = currentPath ? `${currentPath}/${relativePath}` : relativePath
if (!entry.dir) {
if (relativePath === targetFileName || fullPath.endsWith(`/${targetFileName}`)) {
return entry
}
} else if (Object.keys(entry).length > 0) {
const found = findFile(entry, fullPath, targetFileName)
if (found) return found
}
}
return null
}
// 遍历zip文件内容查找package.json
for (const [relativePath, entry] of Object.entries(zipContent.files)) {
if (!entry.dir) {
if (relativePath === 'package.json' || relativePath.endsWith('/package.json')) {
packageJsonFile = entry
} else if (relativePath === 'project.json' || relativePath.endsWith('/project.json')) {
projectJsonFile = entry
}
// 如果两个文件都找到了,就可以停止遍历
if (packageJsonFile && projectJsonFile) break;
}
}
// 如果没有直接找到,尝试递归查找
if (!packageJsonFile) {
packageJsonFile = findFile(zipContent.files, '', 'package.json')
}
if (!projectJsonFile) {
projectJsonFile = findFile(zipContent.files, '', 'project.json')
}
// 解析package.json获取version
if (packageJsonFile) {
const packageJsonContent = await packageJsonFile.async('text')
const packageJson = JSON.parse(packageJsonContent)
if (packageJson.version) {
version.value = packageJson.version
} else {
console.warn('package.json中未找到version字段')
}
} else {
console.warn('未找到package.json文件')
}
// 解析project.json获取package_path
if (projectJsonFile) {
const projectJsonContent = await projectJsonFile.async('text')
const projectJson = JSON.parse(projectJsonContent)
if (projectJson.package_path) {
packagePath.value = projectJson.package_path
} else {
console.warn('project.json中未找到package_path字段')
}
} else {
console.warn('未找到project.json文件')
}
// 如果两个文件都没找到,抛出错误
if (!packageJsonFile && !projectJsonFile) {
throw new Error('未找到package.json和project.json文件')
}
// 如果两个字段都没找到,抛出错误
if (!version.value && !packagePath.value) {
throw new Error('未找到version和package_path字段')
}
} catch (err) {
error.value = `解析失败: ${err.message}`
console.error(err)
} finally {
isLoading.value = false
}
}
</script>
<template>
<div class="container">
<div class="upload-container">
<h2>上传MPKG文件</h2>
<div class="file-input">
<input
type="file"
accept=".mpkg"
@change="handleFileUpload"
id="file-upload"
:disabled="isLoading"
/>
<label for="file-upload" class="file-label">
{{ fileName || '选择文件' }}
</label>
</div>
<div v-if="isLoading" class="loading">
正在解析文件...
</div>
<div v-if="error" class="error">
{{ error }}
</div>
<div v-if="version || packagePath" class="result">
<h3>解析结果</h3>
<p>文件名: {{ fileName }}</p>
<p v-if="version">版本号: <strong>{{ version }}</strong></p>
<p v-if="packagePath">包路径: <strong>{{ packagePath }}</strong></p>
</div>
</div>
</div>
</template>
<style scoped>
.container {
max-width: 800px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
.upload-container {
margin-top: 2rem;
padding: 2rem 8rem;
border-radius: 8px;
background-color: #f9f9f9;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.file-input {
margin: 1.5rem 0;
}
input[type="file"] {
display: none;
}
.file-label {
display: inline-block;
padding: 10px 20px;
background-color: #42b883;
color: white;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
.file-label:hover {
background-color: #369a6e;
}
.loading {
margin: 1rem 0;
color: #666;
}
.error {
margin: 1rem 0;
color: #e74c3c;
}
.result {
margin-top: 1.5rem;
padding: 1rem;
background-color: #e8f5e9;
border-radius: 4px;
}
.result h3 {
margin-top: 0;
color: #2c3e50;
}
.result p {
margin: 0.5rem 0;
}
</style>
12、在线代码编辑+实时预览

实现原理
代码编辑器 页面上有一个代码编辑器(如 CodeMirror、Monaco Editor、CodeJar、Ace 等),用户可以在里面输入或修改 React 代码。
代码转译 用户写的 React 代码通常是 JSX 语法,浏览器不能直接运行。需要用 Babel(或 esbuild、SWC 等)在浏览器端把 JSX 转成普通 JavaScript。
沙盒/预览 把转译后的代码注入到一个 iframe 或 shadow DOM 里,作为“沙盒”环境运行,防止污染主页面。iframe 的内容会被动态更新,实时反映用户的代码修改。
<!-- 使用 codejar 等编辑器 + iframe -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<textarea id="editor" style="width: 400px; height: 100px">
function App() {
return <h1>Hello, world!</h1>
}
</textarea>
<iframe id="preview" style="width: 400px; height: 200px"></iframe>
<script>
const editor = document.getElementById("editor");
const preview = document.getElementById("preview");
function updatePreview() {
const code = editor.value;
// 转译 JSX
const compiled = Babel.transform(code, { presets: ["react"] }).code;
// 生成 iframe 内容
const html = `
<div id="root"></div>
<script src="https://unpkg.com/react@18/umd/react.development.js"><\/script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"><\/script>
<script>
${compiled}
ReactDOM.createRoot(document.getElementById('root')).render(React.createElement(App));
<\/script>
`;
preview.srcdoc = html;
}
editor.addEventListener("input", updatePreview);
updatePreview(); // 初始化
</script>
