当前位置: 首页 > news >正文

excel表格在线编辑(开源版)

文章目录

  • 前言
  • 一、Luckysheet
    • vue3+vite 例子
    • `如有启发,可点赞收藏哟~`


前言

本文记录好用的开源在线表格
具体如图显示
在这里插入图片描述
另外记录下更名后的univer~,如下图(有兴趣可自行详细了解)
univer
在这里插入图片描述
在这里插入图片描述

  • 在线思维导图
    在这里插入图片描述

一、Luckysheet

参考gitee
一款纯前端类似excel的在线表格,功能强大、配置简单、完全开源。

vue3+vite 例子

vue3+vite

  • 引入样式及脚本
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/css/pluginsCss.css" /><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/plugins.css" /><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/luckysheet/dist/css/luckysheet.css" /><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/luckysheet/dist/assets/iconfont/iconfont.css" /><script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/js/plugin.js"></script><script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/luckysheet.umd.js"></script>
  • 安装所需依赖(exceljsfile-saverluckyexcel
npm i exceljs file-saver luckyexcel -S
  • 新建 components/excel.vue
<template><div style="position: absolute; top: 0"><input id="uploadBtn" type="file" @change="loadExcel" /><span>Or Load remote xlsx file:</span><select v-model="selected" @change="selectExcel"><option disabled value="">Choose</option><option v-for="option in options" :key="option.text" :value="option.value">{{ option.text }}</option></select><a href="javascript:void(0)" @click="downloadExcel">Download source xlsx file</a></div><div id="luckysheet"></div><div v-show="isMaskShow" id="tip">Downloading</div>
</template><script setup>
import { ref, onMounted } from 'vue'
import { exportExcel } from './export'
import LuckyExcel from 'luckyexcel'const isMaskShow = ref(false)
const selected = ref('')
const jsonData = ref({})
const options = ref([{ text: 'Money Manager.xlsx', value: 'https://minio.cnbabylon.com/public/luckysheet/money-manager-2.xlsx' },{text: 'Activity costs tracker.xlsx',value: 'https://minio.cnbabylon.com/public/luckysheet/Activity%20costs%20tracker.xlsx'},{text: 'House cleaning checklist.xlsx',value: 'https://minio.cnbabylon.com/public/luckysheet/House%20cleaning%20checklist.xlsx'},{text: 'Student assignment planner.xlsx',value: 'https://minio.cnbabylon.com/public/luckysheet/Student%20assignment%20planner.xlsx'},{text: 'Credit card tracker.xlsx',value: 'https://minio.cnbabylon.com/public/luckysheet/Credit%20card%20tracker.xlsx'},{ text: 'Blue timesheet.xlsx', value: 'https://minio.cnbabylon.com/public/luckysheet/Blue%20timesheet.xlsx' },{text: 'Student calendar (Mon).xlsx',value: 'https://minio.cnbabylon.com/public/luckysheet/Student%20calendar%20%28Mon%29.xlsx'},{text: 'Blue mileage and expense report.xlsx',value: 'https://minio.cnbabylon.com/public/luckysheet/Blue%20mileage%20and%20expense%20report.xlsx'}
])const loadExcel = (evt) => {const files = evt.target.filesif (files == null || files.length == 0) {alert('No files wait for import')return}let name = files[0].namelet suffixArr = name.split('.'),suffix = suffixArr[suffixArr.length - 1]if (suffix != 'xlsx') {alert('Currently only supports the import of xlsx files')return}LuckyExcel.transformExcelToLucky(files[0], function (exportJson, luckysheetfile) {if (exportJson.sheets == null || exportJson.sheets.length == 0) {alert('Failed to read the content of the excel file, currently does not support xls files!')return}console.log('exportJson', exportJson)jsonData.value = exportJsonwindow.luckysheet.destroy()window.luckysheet.create({container: 'luckysheet', //luckysheet is the container idshowinfobar: false,data: exportJson.sheets,title: exportJson.info.name,userInfo: exportJson.info.name.creator})})
}
const selectExcel = (evt) => {const value = selected.valueconst name = evt.target.options[evt.target.selectedIndex].innerTextif (value == '') {return}isMaskShow.value = trueLuckyExcel.transformExcelToLuckyByUrl(value, name, (exportJson, luckysheetfile) => {if (exportJson.sheets == null || exportJson.sheets.length == 0) {alert('Failed to read the content of the excel file, currently does not support xls files!')return}console.log('exportJson', exportJson)jsonData.value = exportJsonisMaskShow.value = falsewindow.luckysheet.destroy()window.luckysheet.create({container: 'luckysheet', //luckysheet is the container idshowinfobar: false,data: exportJson.sheets,title: exportJson.info.name,userInfo: exportJson.info.name.creator})})
}
const downloadExcel = () => {// const value = selected.value;;//// if(value.length==0){//     alert("Please select a demo file");//     return;// }//// var elemIF = document.getElementById("Lucky-download-frame");// if(elemIF==null){//     elemIF = document.createElement("iframe");//     elemIF.style.display = "none";//     elemIF.id = "Lucky-download-frame";//     document.body.appendChild(elemIF);// }// elemIF.src = value;exportExcel(luckysheet.getAllSheets(), '下载')
}// !!! create luckysheet after mounted
onMounted(() => {luckysheet.create({container: 'luckysheet'})
})
</script><style  scoped>
#luckysheet {margin: 0px;padding: 0px;position: absolute;width: 100%;left: 0px;top: 30px;bottom: 0px;
}#uploadBtn {font-size: 16px;
}#tip {position: absolute;z-index: 1000000;left: 0px;top: 0px;bottom: 0px;right: 0px;background: rgba(255, 255, 255, 0.8);text-align: center;font-size: 40px;align-items: center;justify-content: center;display: flex;
}
</style>
  • 新建 exports.js
// import { createCellPos } from './translateNumToLetter'
import Excel from 'exceljs'import FileSaver from 'file-saver'const exportExcel = function(luckysheet, value) {// 参数为luckysheet.getluckysheetfile()获取的对象// 1.创建工作簿,可以为工作簿添加属性const workbook = new Excel.Workbook()// 2.创建表格,第二个参数可以配置创建什么样的工作表if (Object.prototype.toString.call(luckysheet) === '[object Object]') {luckysheet = [luckysheet]}luckysheet.forEach(function(table) {if (table.data.length === 0) return  true// ws.getCell('B2').fill = fills.const worksheet = workbook.addWorksheet(table.name)const merge = (table.config && table.config.merge) || {}const borderInfo = (table.config && table.config.borderInfo) || {}// 3.设置单元格合并,设置单元格边框,设置单元格样式,设置值setStyleAndValue(table.data, worksheet)setMerge(merge, worksheet)setBorder(borderInfo, worksheet)return true})// return// 4.写入 bufferconst buffer = workbook.xlsx.writeBuffer().then(data => {// console.log('data', data)const blob = new Blob([data], {type: 'application/vnd.ms-excel;charset=utf-8'})console.log("导出成功!")FileSaver.saveAs(blob, `${value}.xlsx`)})return buffer
}var setMerge = function(luckyMerge = {}, worksheet) {const mergearr = Object.values(luckyMerge)mergearr.forEach(function(elem) {// elem格式:{r: 0, c: 0, rs: 1, cs: 2}// 按开始行,开始列,结束行,结束列合并(相当于 K10:M12)worksheet.mergeCells(elem.r + 1,elem.c + 1,elem.r + elem.rs,elem.c + elem.cs)})
}var setBorder = function(luckyBorderInfo, worksheet) {if (!Array.isArray(luckyBorderInfo)) return// console.log('luckyBorderInfo', luckyBorderInfo)luckyBorderInfo.forEach(function(elem) {// 现在只兼容到borderType 为range的情况// console.log('ele', elem)if (elem.rangeType === 'range') {let border = borderConvert(elem.borderType, elem.style, elem.color)let rang = elem.range[0]// console.log('range', rang)let row = rang.rowlet column = rang.columnfor (let i = row[0] + 1; i < row[1] + 2; i++) {for (let y = column[0] + 1; y < column[1] + 2; y++) {worksheet.getCell(i, y).border = border}}}if (elem.rangeType === 'cell') {// col_index: 2// row_index: 1// b: {//   color: '#d0d4e3'//   style: 1// }const { col_index, row_index } = elem.valueconst borderData = Object.assign({}, elem.value)delete borderData.col_indexdelete borderData.row_indexlet border = addborderToCell(borderData, row_index, col_index)// console.log('bordre', border, borderData)worksheet.getCell(row_index + 1, col_index + 1).border = border}// console.log(rang.column_focus + 1, rang.row_focus + 1)// worksheet.getCell(rang.row_focus + 1, rang.column_focus + 1).border = border})
}
var setStyleAndValue = function(cellArr, worksheet) {if (!Array.isArray(cellArr)) returncellArr.forEach(function(row, rowid) {row.every(function(cell, columnid) {if (!cell) return truelet fill = fillConvert(cell.bg)let font = fontConvert(cell.ff,cell.fc,cell.bl,cell.it,cell.fs,cell.cl,cell.ul)let alignment = alignmentConvert(cell.vt, cell.ht, cell.tb, cell.tr)let value = ''if (cell.f) {value = { formula: cell.f, result: cell.v }} else if (!cell.v && cell.ct && cell.ct.s) {// xls转为xlsx之后,内部存在不同的格式,都会进到富文本里,即值不存在与cell.v,而是存在于cell.ct.s之后// value = cell.ct.s[0].vcell.ct.s.forEach(arr => {value += arr.v})} else {value = cell.v}//  style 填入到_value中可以实现填充色let letter = createCellPos(columnid)let target = worksheet.getCell(letter + (rowid + 1))// console.log('1233', letter + (rowid + 1))for (const key in fill) {target.fill = fillbreak}target.font = fonttarget.alignment = alignmenttarget.value = valuereturn true})})
}var fillConvert = function(bg) {if (!bg) {return {}}// const bgc = bg.replace('#', '')let fill = {type: 'pattern',pattern: 'solid',fgColor: { argb: bg.replace('#', '') }}return fill
}var fontConvert = function(ff = 0,fc = '#000000',bl = 0,it = 0,fs = 10,cl = 0,ul = 0
) {// luckysheet:ff(样式), fc(颜色), bl(粗体), it(斜体), fs(大小), cl(删除线), ul(下划线)const luckyToExcel = {0: '微软雅黑',1: '宋体(Song)',2: '黑体(ST Heiti)',3: '楷体(ST Kaiti)',4: '仿宋(ST FangSong)',5: '新宋体(ST Song)',6: '华文新魏',7: '华文行楷',8: '华文隶书',9: 'Arial',10: 'Times New Roman ',11: 'Tahoma ',12: 'Verdana',num2bl: function(num) {return num === 0 ? false : true}}// 出现Bug,导入的时候ff为luckyToExcel的vallet font = {name: typeof ff === 'number' ? luckyToExcel[ff] : ff,family: 1,size: fs,color: { argb: fc.replace('#', '') },bold: luckyToExcel.num2bl(bl),italic: luckyToExcel.num2bl(it),underline: luckyToExcel.num2bl(ul),strike: luckyToExcel.num2bl(cl)}return font
}var alignmentConvert = function(vt = 'default',ht = 'default',tb = 'default',tr = 'default'
) {// luckysheet:vt(垂直), ht(水平), tb(换行), tr(旋转)const luckyToExcel = {vertical: {0: 'middle',1: 'top',2: 'bottom',default: 'top'},horizontal: {0: 'center',1: 'left',2: 'right',default: 'left'},wrapText: {0: false,1: false,2: true,default: false},textRotation: {0: 0,1: 45,2: -45,3: 'vertical',4: 90,5: -90,default: 0}}let alignment = {vertical: luckyToExcel.vertical[vt],horizontal: luckyToExcel.horizontal[ht],wrapText: luckyToExcel.wrapText[tb],textRotation: luckyToExcel.textRotation[tr]}return alignment
}var borderConvert = function(borderType, style = 1, color = '#000') {// 对应luckysheet的config中borderinfo的的参数if (!borderType) {return {}}const luckyToExcel = {type: {'border-all': 'all','border-top': 'top','border-right': 'right','border-bottom': 'bottom','border-left': 'left'},style: {0: 'none',1: 'thin',2: 'hair',3: 'dotted',4: 'dashDot', // 'Dashed',5: 'dashDot',6: 'dashDotDot',7: 'double',8: 'medium',9: 'mediumDashed',10: 'mediumDashDot',11: 'mediumDashDotDot',12: 'slantDashDot',13: 'thick'}}let template = {style: luckyToExcel.style[style],color: { argb: color.replace('#', '') }}let border = {}if (luckyToExcel.type[borderType] === 'all') {border['top'] = templateborder['right'] = templateborder['bottom'] = templateborder['left'] = template} else {border[luckyToExcel.type[borderType]] = template}// console.log('border', border)return border
}function addborderToCell(borders, row_index, col_index) {let border = {}const luckyExcel = {type: {l: 'left',r: 'right',b: 'bottom',t: 'top'},style: {0: 'none',1: 'thin',2: 'hair',3: 'dotted',4: 'dashDot', // 'Dashed',5: 'dashDot',6: 'dashDotDot',7: 'double',8: 'medium',9: 'mediumDashed',10: 'mediumDashDot',11: 'mediumDashDotDot',12: 'slantDashDot',13: 'thick'}}// console.log('borders', borders)for (const bor in borders) {// console.log(bor)if (borders[bor].color.indexOf('rgb') === -1) {border[luckyExcel.type[bor]] = {style: luckyExcel.style[borders[bor].style],color: { argb: borders[bor].color.replace('#', '') }}} else {border[luckyExcel.type[bor]] = {style: luckyExcel.style[borders[bor].style],color: { argb: borders[bor].color }}}}return border
}function createCellPos(n) {let ordA = 'A'.charCodeAt(0)let ordZ = 'Z'.charCodeAt(0)let len = ordZ - ordA + 1let s = ''while (n >= 0) {s = String.fromCharCode((n % len) + ordA) + sn = Math.floor(n / len) - 1}return s
}export {exportExcel
}

运行后预览显示,可导入,下载
在这里插入图片描述


如有启发,可点赞收藏哟~

相关文章:

excel表格在线编辑(开源版)

文章目录 前言一、Luckysheetvue3vite 例子如有启发&#xff0c;可点赞收藏哟~ 前言 本文记录好用的开源在线表格 具体如图显示 另外记录下更名后的univer~&#xff0c;如下图&#xff08;有兴趣可自行详细了解&#xff09; univer 在线思维导图 一、Luckysheet 参考git…...

17.字符串处理函数——字符串比较函数

文章目录 前言一、题目描述 二、解题 程序运行代码 总结 前言 本系列为字符串处理函数编程题&#xff0c;点滴成长&#xff0c;一起逆袭。 一、题目描述 二、解题 程序运行代码 #include<stdio.h> #include<string.h> int main() {char *str1 "hello wo…...

【面试HOT200】二叉树——深度优先搜索篇

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招面试的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于【CodeTopHot200】进行的&#xff0c;每个知识点的修正和深入主要参…...

价值投资选股的方法

价值投资法是一种长期投资策略&#xff0c;其核心思想是寻找被市场低估的股票&#xff0c;即股票的市场价格低于其内在价值。这种策略认为&#xff0c;投资者应该关注公司的基本面&#xff0c;如盈利能力、成长潜力、财务状况等&#xff0c;而不是短期的市场波动。以下是价值投…...

java中如何将mysql里面的数据取出来然后通过stream流的方式进行数据处理代码实例?

在 Java 中使用 Stream 流的方式从 MySQL 数据库中取出数据并进行处理&#xff0c;你可以通过 JDBC&#xff08;Java Database Connectivity&#xff09;来实现。下面是一个简单的代码示例&#xff1a; import java.sql.*; import java.util.stream.Stream; public class MySQ…...

C++服务器 支持http、tcp protobuf、websocket,linux开源框架 零依赖轻松编译部署 Reactor

开源地址: https://github.com/crust-hub/tubekit/tree/main Github:https://github.com/gaowanlu 诚招有兴趣的小伙伴加入开发维护 Tubekit The C TCP server framework based on the Reactor model continues to implement POSIX thread pool, Epoll, non blocking IO, obj…...

1688API接口系列,1688开放平台接口使用方案(商品详情数据+搜索商品列表+商家订单类)

1688商品详情接口是指1688平台提供的API接口&#xff0c;用于获取商品详情信息。通过该接口&#xff0c;您可以获取到商品的详细信息&#xff0c;包括商品标题、价格、库存、描述、图片等。 要使用1688商品详情接口&#xff0c;您需要先申请1688的API权限&#xff0c;并获取ac…...

CentOS服务器网页版Rstudio-server及R包批量安装最佳实践

CentOS服务器安装网页版Rstudio-server及R包批量安装 以下为CentOS 7/8的Rstudio-server安装、配置和R包安装操作 1. 软件包安装 Centos 7安装 # 下载安装包&#xff0c;大小115.14 MB wget -c https://download2.rstudio.org/server/centos7/x86_64/rstudio-server-rhel-…...

centos7内核升级(k8s基础篇)

1.查看系统内核版本信息 uname -r 2.升级内核 2.1更新yum源仓库 yum -y update更新完成后&#xff0c;启用 ELRepo 仓库并安装ELRepo仓库的yum源 ELRepo 仓库是基于社区的用于企业级 Linux 仓库&#xff0c;提供对 RedHat Enterprise (RHEL) 和 其他基于 RHEL的 Linux 发行…...

数据结构与算法设计分析——NP完全理论

目录 一、P类问题与NP类问题的定义二、常见的NP类问题&#xff08;一&#xff09;旅行商问题&#xff08;TSP&#xff09;&#xff08;二&#xff09;哈密尔顿回路问题&#xff08;三&#xff09;判断回路问题&#xff08;四&#xff09;图的着色问题&#xff08;五&#xff09…...

AGNES层次聚类

已知数据集D中有9个数据点&#xff0c;分别是(1,2)&#xff0c;(2&#xff0c;3)&#xff0c;(2,1), (3,1),(2,4),(3,5),(4,3),(1,5),(4,2)。要求&#xff1a; (1)采用层次聚类的聚集算法进行聚类&#xff0c;k2。 (2)距离计算采用欧几里得距离。 (3)簇之间的距离采用单链接方…...

HCIP —— 双点重发布 + 路由策略 实验

目录 实验拓扑&#xff1a; 实验要求&#xff1a; 实验配置&#xff1a; 1.配置IP地址 2.配置动态路由协议 —— RIP 、 OSPF R1 RIP R4 OSPF R2 配置RIP、OSPF 双向重发布 R3配置RIP、OSPF 双向重发布 3.查询路由表学习情况 4.使用路由策略控制选路 R2 R3 5.检…...

Python标准库:datetime模块【侯小啾python领航班系列(二十五)】

Python标准库:datetime模块【侯小啾python领航班系列(二十五)】 大家好,我是博主侯小啾, 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ…...

新版idea如何开启多台JVM虚拟机

1.看看自己的项目 2.可能开始的时候啥也没有&#xff0c;就点Run Configuration Type 3.再点击Edit Configurations... 4.点击号添加SpringBoot 5.主类选择一下&#xff0c;一般就一个&#xff0c;点他选了就行。 6.然后点击Modify Options 选择添加add VM Options 7.点击appl…...

软件工程单选多选补充

2. 4. 5. 6. 7. 8. 9. 10. 12。 13....

6-66.时间

本题要求输入小时、分钟和秒数&#xff0c;并将其输出。针对时间表示中出现的异常进行处理。例如小时数不应超过23&#xff0c;分钟不应超过59&#xff0c;秒数不应超过59。此外&#xff0c;以上三个变量均应大于等于0。 输入样例&#xff1a; 在这里给出三组输入。例如&…...

面试多线程八股文十问十答第一期

面试多线程八股文十问十答第一期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1.ThreadLocal如何实现线程安全 Java的ThreadLocal是一个线程本地变量&#xff0…...

Mybatis 操作续集(结合上文)

当我们增加一个数据之后,如果我们想要获取它的 Id 进行别的操作,我们该如何获取 Id 呢? 用那个Options package com.example.mybatisdemo.mapper;import com.example.mybatisdemo.model.UserInfo; import org.apache.ibatis.annotations.*;import java.util.List;Mapper pub…...

JVM基础篇:垃圾回收

目录 1.前言 1.1C/C的内存管理 1.2Java的内存管理 2.方法区的回收 3.堆回收 3.1引用计数法和可达性分析法 3.2五种对象引用 强引用 软引用 弱引用 虚引用 终结器引用 3.3垃圾回收算法评价标准 ①吞吐量 ②最大暂停时间 ③堆使用效率 3.4垃圾回收算法 ①标记清…...

蓝桥杯ACwing习题

题目 &#xff1a;https://www.acwing.com/problem/content/4409/ 解析 &#xff1a;根据题目我们可以知道 问的是方案数 那么首先就想到了 dp 仔细想一下 发现类似于蒙德里安的梦想那道状态压缩的题 &#xff0c; 所以我们先考虑怎么定义 f[i][j] f[i][j] 表示的是 已经放了…...

vue发送请求携带token,拼接url地址下载文件

封装请求 &#xff0c;该请求为普通的get请求 该请求返回值为&#xff1a; 请求成功之后拼接URL地址下载文件 代码块 downTemplateRequest(activeKeys.value).then((res) > {let url http://47.169.168.99:18888/media/${res.data.name};var elink document.createElemen…...

【PTA-C语言】编程练习3 - 循环结构Ⅱ

如果代码存在问题&#xff0c;麻烦大家指正 ~ ~有帮助麻烦点个赞 ~ ~ 编程练习3 - 循环结构&#xff08;9~15&#xff09; 7-9 特殊a串数列求和&#xff08;分数 15&#xff09;7-10 穷举法搬运砖块问题&#xff08;分数 15&#xff09;7-11 数字金字塔&#xff08;分数 15&…...

Google Chrome 下载 (离线版)

1 访问网址 Google Chrome 网络浏览器 2 点击 下载Chrome 3 直接运行 ChromeStandaloneSetup64.exe 其他&#xff1a; ####################### 谷歌浏览器 (Google Chrome) 最新版离线安装包下载 https://www.iplaysoft.com/tools/chrome/#google_vignette Google Chrome …...

2023年GopherChina大会-核心PPT资料下载

一、峰会简介 自 Go 语言诞生以来&#xff0c;中国便是其应用最早和最广的国家之一&#xff0c;根据 Jetbrains 在 2021 年初做的调查报告&#xff0c;总体来说目前大概有 110 万专业的开发者 选择 Go 作为其主要开发语言。就其全球分布而言, 居住在亚洲的开发者最多&#xff…...

从源代码出发,Jenkins 任务排队时间过长问题的解决过程

最近开发了一个部署相关的工具&#xff0c;使用 Jenkins 来构建应用。Jenkins 的任务从模板中创建而来。每次部署时&#xff0c;通过 Jenkins API 来触发构建任务。在线上运行时发现&#xff0c;通过 API 触发的 Jenkins 任务总是会时不时在队列中等待较长的时间。某些情况下的…...

openssl 生成CA及相关证书

实验环境&#xff1a;ubuntu18.04-desktop 获取openssl.cnf配置文件 # 这个返回的路径&#xff0c;不一定被使用了&#xff08;经测试&#xff0c;ubuntu18下的openssl似乎未加载任何配置文件&#xff09; openssl version -d生成私钥文件(pem) # 生成私钥 # genrsa&#xf…...

App测试之App日志收集及adb常用命令

文章目录 前言一、adb是什么1.APP测试收集手机日志常用的工具2.adb下载与安装3.ADT/SDK/ADB是什么4.adb连接真机 二、adb常用命令三、android系统日志文件1.logcat日志文件2.logcat日志文件分析 四、分析crash & ANR 日志1.发生crash如何分析2.发生ANR如何分析 总结扩展&am…...

【Java面试——并发基础、并发关键字】

3.1 并发基础 Java 并发 - 理论基础Java 并发 - 线程基础 多线程的出现是要解决什么问题的? 本质什么? CPU、内存、I/O 设备的速度是有极大差异的&#xff0c;为了合理利用 CPU 的高性能&#xff0c;平衡这三者的速度差异&#xff0c;计算机体系结构、操作系统、编译程序都…...

如何使用 Java 在Excel中创建下拉列表

下拉列表&#xff08;下拉框&#xff09;可以确保用户仅从预先给定的选项中进行选择&#xff0c;这样不仅能减少数据输入错误&#xff0c;还能节省时间提高效率。在MS Excel中&#xff0c;我们可以通过 “数据验证” 提供的选项来创建下拉列表&#xff0c;但如果要在Java程序中…...

Python安装步骤介绍

本文将介绍Python安装的详细步骤如下&#xff1a; 下载 python安装 python配置环境变量&#xff08;安装时勾选配置环境变量的则无需此步骤&#xff09; 一、python下载 官网&#xff1a;Download Python | Python.org 根据电脑位数下载所需的版本 二、Python安装 1.打开安…...