虚拟化表格(Virtualized Table)性能优化

文章目录

  • 功能介绍
  • 一开始的代码
  • 领导让我们分析一下
  • 开始优化
  • 如何监听事件和传参?
  • 定位操作栏
  • 更加优化

功能介绍

菜鸟最近做的一个功能如下:

后端返回两个很大的数组,例如:数组a 1w条,数组b 2w条,然后要操作b的数据去a里面,然后操作a的去b里面,最后把修改后的数组a和数组b返回给后端!且这个操作,是可以撤销的,用户操作了,但是没保存,是可以直接叉了,就不改后端数据!且数据还是可以搜索的!

一开始的代码

菜鸟一开始其实也考虑到了性能问题,但是当时是测试环境,最多就几十条数据,用 el-table 完全够用,且当时用 Virtualized Table 虚拟化表格 来渲染的时候老是 eslint 报错,所以当时就没管了!

接下来是老的代码

<script setup>
import { Search } from '@element-plus/icons-vue'import { getExcelApi, saveReportInfoApi } from '@/network/analysisApi'const props = defineProps({dialogVisible: {type: Boolean,default: false},id: {type: Number,default: -1}
})const emit = defineEmits(['closeEvent'])// 关闭弹窗
function handleClose() {emit('closeEvent', false)
}
const dialogBox = ref()
function closeDialog() {dialogBox.value.resetFields()
}// 需要返回后端的数据
const subformData = {fileName: '',id: props.id,reportAPath: '',outputPath: ''
}
// 表数据
let reportA = ref([])
let reportB = ref([])
let oldreportA = []
let oldreportB = []
const loading = ref(true)
// 获取数据
getExcelApi(props.id).then((res) => {console.log(res)if (res.code == 200) {subformData.fileName = res.data.fileNamesubformData.reportAPath = res.data.reportAPathsubformData.outputPath = res.data.outputPathreportA.value = res.data.reportAreportB.value = res.data.reportBoldreportA = res.data.reportAoldreportB = res.data.reportBif (res.data.reportB.length <= 50 && res.data.reportA.length <= 50) {loading.value = false} else {setTimeout(() => {loading.value = false}, 5000)}} else {ElMessage({message: res.message,type: 'error'})}}).catch((err) => {console.log(err)})// 搜索
let searchVal = ref('')
const search = () => {reportA.value = oldreportA.filter(function (i) {return i.patientName.includes(searchVal.value)})reportB.value = oldreportB.filter(function (i) {return i.patientName.includes(searchVal.value)})
}// 表A减数据
const reduceFun = (e) => {let index = oldreportA.findIndex((item) =>item.id === e.row.id &&item.barcode === e.row.barcode &&item.patientName === e.row.patientName &&item.species === e.row.species)let data = oldreportA.splice(index, 1)oldreportB.splice(0, 0, data[0])reportA.value = oldreportA.filter(function (i) {return i.patientName.includes(searchVal.value)})reportB.value = oldreportB.filter(function (i) {return i.patientName.includes(searchVal.value)})
}// 表B加数据
const addFun = (e) => {let index = oldreportB.findIndex((item) =>item.id === e.row.id &&item.barcode === e.row.barcode &&item.patientName === e.row.patientName &&item.species === e.row.species)let data = oldreportB.splice(index, 1)oldreportA.splice(0, 0, data[0])reportA.value = oldreportA.filter(function (i) {return i.patientName.includes(searchVal.value)})reportB.value = oldreportB.filter(function (i) {return i.patientName.includes(searchVal.value)})
}// 提交表单
const submit = () => {subformData.reportA = oldreportAsubformData.reportB = oldreportBsaveReportInfoApi(subformData).then((res) => {console.log(res)if (res.code === 200) {ElMessage({message: '提交审核成功!',type: 'success'})handleClose()} else {ElMessage({message: res.message,type: 'error'})}}).catch((err) => {console.log(err)})
}// 定义table的表头
const columns = [{title: '测序批次',dataKey: 'batch',width: 300},{title: 'barcode',dataKey: 'barcode',width: 100},{title: '患者姓名',dataKey: 'patientName',width: 100},{title: '体系',dataKey: 'structure',width: 350},{title: '样本编号',dataKey: 'sampleNum',width: 150},{title: '报告编号',dataKey: 'reportNum',width: 150},{title: '样本类型',dataKey: 'sampleType',width: 150},{title: '提取Reads总数',dataKey: 'extractReads',width: 140},{title: '样本比对总reads',dataKey: 'sampleContrastReads',width: 150},// 内参检出情况// 分类{title: 'Species',dataKey: 'species',width: 300},{title: '物种中文名',dataKey: 'speciesCn',width: 250},{title: '物种比对Reads数',dataKey: 'speciesContrastReads',width: 150},// 样本检出靶标数// 特异靶标数{title: '综合可信度',dataKey: 'credibility',width: 150},{title: 'DNC的Reads数',dataKey: 'dncReads',width: 150},{title: '样本质控总reads',dataKey: 'qualityReads',width: 150},// DNC的靶标数{title: '同批最大reads数',dataKey: 'maxReads',width: 150},// 同批最高bc// 同批最高核酸编号{title: '物种类别',dataKey: 'speciesCategory',width: 150},{title: '定植情况',dataKey: 'planting',width: 400},{title: '结果解释',dataKey: 'resultExplain',width: 800},{title: '物种所在盘',dataKey: 'speciesDisk',width: 250},// 表中没有可能要修改{title: 'Genus',dataKey: 'genus',width: 150},{title: '属名',dataKey: 'genericName',width: 150},{title: '危害程度分类',dataKey: 'harm',width: 150},{title: '检出数/10000',dataKey: 'detectionNumber',width: 150},{title: '单样本Score',dataKey: 'sampleScore',width: 150}
]
</script><template><div><el-dialogtitle="结果筛选"ref="dialogBox":modelValue="dialogVisible":before-close="handleClose"@close="closeDialog"width="90%"top="30px":close-on-click-modal="false":destroy-on-close="true"><div style="display: flex; width: 300px"><el-input v-model="searchVal" placeholder="患者姓名" clearable></el-input><el-button style="margin-left: 50px" type="primary" :icon="Search" @click="search">搜索</el-button></div><hr /><p>表格A</p><div style="height: 300px"><el-tablev-loading="loading"element-loading-text="加载中...":data="reportA"style="width: 100%; height: 100%"><template v-for="(item, index) in columns" :key="index"><el-table-column :prop="item.dataKey" :label="item.title" :width="item.width" /></template><el-table-column fixed="right" label="操作" width="80" center><template #default="scope"><el-button type="primary" size="small" @click="reduceFun(scope)"> - </el-button></template></el-table-column></el-table></div><hr /><p>表格B</p><div style="height: 300px"><el-tablev-loading="loading"element-loading-text="加载中...":data="reportB"style="width: 100%; height: 100%"><template v-for="(item, index) in columns" :key="index"><el-table-column :prop="item.dataKey" :label="item.title" :width="item.width" /></template><el-table-column fixed="right" label="操作" width="80" center><template #default="scope"><el-button type="primary" size="small" @click="addFun(scope)"> + </el-button></template></el-table-column></el-table></div><template #footer><div><el-button type="primary" @click="submit">提交</el-button><el-button @click="handleClose">关闭</el-button></div></template></el-dialog></div>
</template>

但是这段代码在生产环境中就完全不够看了,生产环境不管是reportA还是reportB都是几千条左右,即使1秒就获取到了后端数据,但是 el-table 加载就要几秒钟,所以菜鸟直接写了一个5秒的定时器,等5秒后差不多渲染完了才把蒙层关闭(有点掩耳盗铃的感觉)!

重点是当菜鸟滚动列表的时候,那叫一个卡顿,且如果进行了移动数据的操作,那又会一卡一卡的,如果加上搜索,卡顿得让人难以想象!

领导让我们分析一下

卡成这样,用户肯定是受不了,所以领导就找我们分析原因!

菜鸟感觉前端数据量有点大,不如:用分页搜索并配合后端一起解决!但是很快被后端否决了,因为很麻烦,例如:

a查了10条,b查了10条,操作了b的一条去了a,那a点击第二页应该就是9-19条,而不是之前的10-20条,b也会变成1-11条(去掉操作的那一条),而不是1-10条了!

每一个操作都要向后端去请求,并告诉后端,数组a增加了哪一个、减少了哪一个、数组b增加了哪一个、减少了哪一个,交给后端去处理分页(并不改数组库)!

显然上面的这个思路得上千万条数据可能会使用的,菜鸟这个还不至于!

所以将思路定为前端性能优化,领导直接发话:这优化不了就该优化菜鸟我了!
在这里插入图片描述

开始优化

既然分到自己头上了,那就只能干了!奥里给!

菜鸟想起来了之前的 Virtualized Table 虚拟化表格 ,当时使用确实会报错,但是把那个报错的代码删除,确实反应很快,只是当时没有深究如何解决报错,想着偷懒去了,现在就硬上了!

所以代码改成了这样:

<script setup>
import { Search } from '@element-plus/icons-vue'import { getExcelApi, saveReportInfoApi } from '@/network/analysisApi'const props = defineProps({dialogVisible: {type: Boolean,default: false},id: {type: Number,default: -1}
})const emit = defineEmits(['closeEvent'])// 关闭弹窗
function handleClose() {emit('closeEvent', false)
}
const dialogBox = ref()
function closeDialog() {dialogBox.value.resetFields()
}// 需要返回后端的数据
const subformData = {fileName: '',id: props.id,reportAPath: '',outputPath: ''
}
// 表数据
let reportA = ref([])
let reportB = ref([])
// 保存表头 --》 操作columns
let reportATitle = []
let reportBTitle = []
const columnsA = ref([])
const columnsB = ref([])
// 用于提交的数据
let oldreportA = []
let oldreportB = []
// 加载
const loading = ref(true)
// 获取数据
getExcelApi(props.id).then((res) => {console.log(res)if (res.code == 200) {subformData.fileName = res.data.fileNamesubformData.reportAPath = res.data.reportAPathsubformData.outputPath = res.data.outputPathreportA.value = res.data.reportAconst tempA = reportA.value[0]for (let i in tempA) {console.log(i)if (i == 'id') continuereportATitle.push(i)}for (let i in reportATitle) {columnsA.value.push({title: reportATitle[i],key: reportATitle[i],dataKey: reportATitle[i],width: reportATitle[i] === '结果解释' || reportATitle[i] === '描述' ? 1200 : 200})}columnsA.value.push({key: 'operations',title: '操作',cellRenderer: () => (<><ElButton type="primary" size="small">-</ElButton></>),width: 80,align: 'center'})reportB.value = res.data.reportBconst tempB = reportB.value[0]for (let i in tempB) {if (i == 'id') continuereportBTitle.push(i)}for (let i in reportBTitle) {columnsB.value.push({title: reportBTitle[i],key: reportBTitle[i],dataKey: reportBTitle[i],width: reportBTitle[i] === '结果解释' || reportBTitle[i] === '描述' ? 1200 : 200})}columnsB.value.push({key: 'operations',title: '操作',cellRenderer: () => (<><ElButton type="primary" size="small">+</ElButton></>),width: 80,align: 'center'})oldreportA = res.data.reportAoldreportB = res.data.reportBloading.value = false} else {ElMessage({message: res.message,type: 'error'})}}).catch((err) => {console.log(err)})// 搜索
let searchVal = ref('')
const search = () => {reportA.value = oldreportA.filter(function (i) {return i['患者姓名'].includes(searchVal.value)})reportB.value = oldreportB.filter(function (i) {return i['患者姓名'].includes(searchVal.value)})
}const uniqueItem = ['id', 'Barcode', '患者姓名', 'Species']
// 表A减数据
const reduceFun = (e) => {console.log(e)let index = oldreportA.findIndex((item) => {console.log(item)let num = 0for (let i of uniqueItem) {if (item[i] === e[i]) {num++}}return num === 4})let data = oldreportA.splice(index, 1)oldreportB.splice(0, 0, data[0])reportA.value = oldreportA.filter(function (i) {return i['患者姓名'].includes(searchVal.value)})reportB.value = oldreportB.filter(function (i) {return i['患者姓名'].includes(searchVal.value)})
}// 表B加数据
const addFun = (e) => {console.log(e)let index = oldreportB.findIndex((item) => {console.log(item)let num = 0for (let i of uniqueItem) {if (item[i] === e[i]) {num++}}return num === 4})let data = oldreportB.splice(index, 1)oldreportA.splice(0, 0, data[0])reportA.value = oldreportA.filter(function (i) {return i['患者姓名'].includes(searchVal.value)})reportB.value = oldreportB.filter(function (i) {return i['患者姓名'].includes(searchVal.value)})
}// 提交表单
const submit = () => {subformData.reportA = oldreportAsubformData.reportB = oldreportBsaveReportInfoApi(subformData).then((res) => {console.log(res)if (res.code === 200) {ElMessage({message: '提交审核成功!',type: 'success'})handleClose()} else {ElMessage({message: res.message,type: 'error'})}}).catch((err) => {console.log(err)})
}
</script><template><div><el-dialogtitle="结果筛选"ref="dialogBox":modelValue="dialogVisible":before-close="handleClose"@close="closeDialog"width="90%"top="30px":close-on-click-modal="false":destroy-on-close="true"><div style="display: flex; width: 300px"><el-input v-model="searchVal" placeholder="患者姓名" clearable></el-input><el-button style="margin-left: 50px" type="primary" :icon="Search" @click="search">搜索</el-button></div><hr /><p>表格A</p><div style="height: 300px"><el-auto-resizer><template #default="{ height, width }"><el-table-v2 :columns="columnsA" :data="reportA" :width="width" :height="height" fixed><template #overlay v-if="loading"><divclass="el-loading-mask"style="display: flex; align-items: center; justify-content: center"><el-icon class="is-loading"><i-ep-loading /></el-icon></div></template></el-table-v2></template></el-auto-resizer></div><hr /><p>表格B</p><div style="height: 300px"><el-auto-resizer><template #default="{ height, width }"><el-table-v2 :columns="columnsB" :data="reportB" :width="width" :height="height" fixed><template #overlay v-if="loading"><divclass="el-loading-mask"style="display: flex; align-items: center; justify-content: center"><el-icon class="is-loading"><i-ep-loading /></el-icon></div></template></el-table-v2></template></el-auto-resizer></div><template #footer><div><el-button type="primary" @click="submit">提交</el-button><el-button @click="handleClose">关闭</el-button></div></template></el-dialog></div>
</template>

果然不出所料,还是报错:

Parsing error: Unexpected token <

在这里插入图片描述

这里菜鸟直接反手 ChatGPT,问了一个:

在这里插入图片描述

然后菜鸟就知道了,原来是jsx搞的鬼,知道了原因,解决就很快了,直接反手再来一发 ChatGPT :

在这里插入图片描述
在这里插入图片描述
然后配置一下 .eslintrc.cjs
在这里插入图片描述
配置好了之后发现没有报错,项目可以运行,自信满满点到这个界面,发现还是报错:
在这里插入图片描述
问了ChatGPT 发现是要在script标签上加个lang="jsx"

在这里插入图片描述

完美解决!

如何监听事件和传参?

这样渲染倒是上去了,但是jsx菜鸟不会呀,咋监听按钮的点击事件?咋传参数?

菜鸟只能一个一个尝试了!菜鸟想着都是 element 应该传值是一样的吧,所以变成了这样!

columnsA.value.push({key: 'operations',title: '操作',cellRenderer: (row) => (<><ElButton type="primary" size="small" @click="addFun(row)">-</ElButton></>),width: 80,align: 'center'
})

但是直接报错

在这里插入图片描述

继续问 GPT:

在这里插入图片描述

然后菜鸟写成了这样

columnsA.value.push({key: 'operations',title: '操作',cellRenderer: (row) => (<><ElButton type="primary" size="small" onClick="addFun(row)">-</ElButton></>),width: 80,align: 'center'
})

发现还是没有用,但是不报错了,果断 GPT:

在这里插入图片描述

最后代码成型:

<script lang="jsx" setup>
import { Search } from '@element-plus/icons-vue'import { getExcelApi, saveReportInfoApi } from '@/network/analysisApi'const props = defineProps({dialogVisible: {type: Boolean,default: false},id: {type: Number,default: -1}
})const emit = defineEmits(['closeEvent'])// 关闭弹窗
function handleClose() {emit('closeEvent', false)
}
const dialogBox = ref()
function closeDialog() {dialogBox.value.resetFields()
}// 需要返回后端的数据
const subformData = {fileName: '',id: props.id,reportAPath: '',outputPath: ''
}
// 表数据
let reportA = ref([])
let reportB = ref([])
// 保存表头 --》 操作columns
let reportATitle = []
let reportBTitle = []
const columnsA = ref([])
const columnsB = ref([])
// 用于提交的数据
let oldreportA = []
let oldreportB = []
// 加载
const loading = ref(true)
// 获取数据
getExcelApi(props.id).then((res) => {console.log(res)if (res.code == 200) {subformData.fileName = res.data.fileNamesubformData.reportAPath = res.data.reportAPathsubformData.outputPath = res.data.outputPathreportA.value = res.data.reportAconst tempA = reportA.value[0]for (let i in tempA) {console.log(i)if (i == 'id') continuereportATitle.push(i)}for (let i in reportATitle) {columnsA.value.push({title: reportATitle[i],key: reportATitle[i],dataKey: reportATitle[i],width: reportATitle[i] === '结果解释' || reportATitle[i] === '描述' ? 1200 : 200})}columnsA.value.push({key: 'operations',title: '操作',cellRenderer: (row) => (<><ElButton type="primary" size="small" onClick={() => reduceFun(row.rowData)}>-</ElButton></>),width: 80,align: 'center'})reportB.value = res.data.reportBconst tempB = reportB.value[0]for (let i in tempB) {if (i == 'id') continuereportBTitle.push(i)}for (let i in reportBTitle) {columnsB.value.push({title: reportBTitle[i],key: reportBTitle[i],dataKey: reportBTitle[i],width: reportBTitle[i] === '结果解释' || reportBTitle[i] === '描述' ? 1200 : 200})}columnsB.value.push({key: 'operations',title: '操作',cellRenderer: (row) => (<><ElButton type="primary" size="small" onClick={() => addFun(row.rowData)}>+</ElButton></>),width: 80,align: 'center'})oldreportA = res.data.reportAoldreportB = res.data.reportBloading.value = false} else {ElMessage({message: res.message,type: 'error'})}}).catch((err) => {console.log(err)})// 搜索
let searchVal = ref('')
const search = () => {reportA.value = oldreportA.filter(function (i) {return i['患者姓名'].includes(searchVal.value)})reportB.value = oldreportB.filter(function (i) {return i['患者姓名'].includes(searchVal.value)})
}const uniqueItem = ['id', 'Barcode', '患者姓名', 'Species']
// 表A减数据
const reduceFun = (e) => {console.log(e)let index = oldreportA.findIndex((item) => {console.log(item)let num = 0for (let i of uniqueItem) {if (item[i] === e[i]) {num++}}return num === 4})let data = oldreportA.splice(index, 1)oldreportB.splice(0, 0, data[0])reportA.value = oldreportA.filter(function (i) {return i['患者姓名'].includes(searchVal.value)})reportB.value = oldreportB.filter(function (i) {return i['患者姓名'].includes(searchVal.value)})
}// 表B加数据
const addFun = (e) => {console.log(e)let index = oldreportB.findIndex((item) => {console.log(item)let num = 0for (let i of uniqueItem) {if (item[i] === e[i]) {num++}}return num === 4})let data = oldreportB.splice(index, 1)oldreportA.splice(0, 0, data[0])reportA.value = oldreportA.filter(function (i) {return i['患者姓名'].includes(searchVal.value)})reportB.value = oldreportB.filter(function (i) {return i['患者姓名'].includes(searchVal.value)})
}// 提交表单
const submit = () => {subformData.reportA = oldreportAsubformData.reportB = oldreportBsaveReportInfoApi(subformData).then((res) => {console.log(res)if (res.code === 200) {ElMessage({message: '提交审核成功!',type: 'success'})handleClose()} else {ElMessage({message: res.message,type: 'error'})}}).catch((err) => {console.log(err)})
}
</script><template><div><el-dialogtitle="结果筛选"ref="dialogBox":modelValue="dialogVisible":before-close="handleClose"@close="closeDialog"width="90%"top="30px":close-on-click-modal="false":destroy-on-close="true"><div style="display: flex; width: 300px"><el-input v-model="searchVal" placeholder="患者姓名" clearable></el-input><el-button style="margin-left: 50px" type="primary" :icon="Search" @click="search">搜索</el-button></div><hr /><p>表格A</p><div style="height: 300px"><el-auto-resizer><template #default="{ height, width }"><el-table-v2 :columns="columnsA" :data="reportA" :width="width" :height="height" fixed><template #overlay v-if="loading"><divclass="el-loading-mask"style="display: flex; align-items: center; justify-content: center"><el-icon class="is-loading"><i-ep-loading /></el-icon></div></template></el-table-v2></template></el-auto-resizer></div><hr /><p>表格B</p><div style="height: 300px"><el-auto-resizer><template #default="{ height, width }"><el-table-v2 :columns="columnsB" :data="reportB" :width="width" :height="height" fixed><template #overlay v-if="loading"><divclass="el-loading-mask"style="display: flex; align-items: center; justify-content: center"><el-icon class="is-loading"><i-ep-loading /></el-icon></div></template></el-table-v2></template></el-auto-resizer></div><template #footer><div><el-button type="primary" @click="submit">提交</el-button><el-button @click="handleClose">关闭</el-button></div></template></el-dialog></div>
</template>

定位操作栏

但是这样了,菜鸟还是不满足,感觉一般这个操作都是要固定起来,而不是在最后一行看不见!

然后菜鸟又踩坑了,发现就是定位不了,最后对比官方网站找到原因,发现是需要从 element plus 里面引入 TableV2FixedDir

简化后的代码 (避免大家看很多,提出来这个部分了):

import { TableV2FixedDir } from 'element-plus'columnsB.value.push({key: 'operations',title: '操作',cellRenderer: (row) => (<><ElButton type="primary" size="small" onClick={() => addFun(row.rowData)}>+</ElButton></>),width: 80,align: 'center',fixed: TableV2FixedDir.RIGHT
})

更加优化

这个是菜鸟沸点底下的大佬给的思路:

在这里插入图片描述

所以这里把ref 换成 shallowRef

let reportA = shallowRef([])
let reportB = shallowRef([])

到此性能优化完成,可能对大佬来说真的很简单,但是菜鸟还是感觉有点成就感,毕竟性能提升了50倍以上!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/19848.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Orcad 输出有链接属性的PDF

安装adobe pdf安装Ghostscript修改C:\Cadence\SPB_16.6\tools\capture\tclscripts\capUtils\capPdfUtil.tcl ​ 设置默认打印机为 Adobe PDF ​ 将Ghostscript的路径修改正确 打开cadence Orcad &#xff0c;accessories->candece Tcl/Tk Utilities-> Utilities->PD…

从源头保障电力安全:输电线路动态增容与温度监测技术详解

在电力系统中&#xff0c;输电线路是电能传输的关键环节。然而&#xff0c;当导线温度过高时&#xff0c;会加速导线老化&#xff0c;降低绝缘性能&#xff0c;甚至引发短路、火灾等严重事故&#xff0c;对电网安全运行构成巨大威胁。近日&#xff0c;某地区因持续高温和用电负…

递归系列 简单(倒序输出一个正整数)

倒序输出一个正整数 时间限制: 1s 类别: 递归->简单 问题描述 例如给出正整数 n12345&#xff0c;希望以各位数的逆序形式输出&#xff0c;即输出54321。 递归思想&#xff1a;首先输出这个数的个位数&#xff0c;然后将个位丢掉&#xff0c;得到新的数&#xff0c;继续…

矩阵论在图像算法中的应用

摘要&#xff1a; 本文详细阐述了矩阵论在图像算法中的广泛应用。首先介绍了图像在计算机中的矩阵表示形式&#xff0c;然后从图像压缩、图像变换、图像特征提取与识别、图像恢复与重建等多个方面深入分析了矩阵论相关技术的作用原理和优势。通过对这些应用的探讨&#xff0c;展…

鸿蒙改变状态栏和安全区域颜色之 expandSafeArea

改变状态栏和安全区域颜色之 expandSafeArea 基于API12。 参考文档 直接设置build里边根元素的背景色之后&#xff0c;本想着是整个页面的颜色全变成相应的颜色&#xff0c;不过实际上状态栏跟地步安全区域是不受影响的。这个时候一般可能都会各种地方找API来设置状态栏跟安全…

Ubuntu Linux使用前准备动作_使用root登录图形化界面

Ubuntu默认是不允许使用 root 登录图形化界面的。这是出于安全考虑的设置。但如果有需要&#xff0c;可以通过以下步骤来实现使用 root 登录&#xff1a; 1、设置 root 密码 打开终端&#xff0c;使用当前的管理员账户登录系统。在终端中输入命令sudo passwd root&#xff0c…

交换排序——快速排序3 针对LeetCode某OJ的优化

交换排序——快速排序3 针对LeetCode某OJ的优化 快速排序的优化小区间优化三数取中三路划分优化 快速排序的优化 这篇优化围绕这个测试OJ展开。 912. 排序数组 - 力扣&#xff08;LeetCode&#xff09; 这个测试OJ在早期用快排还能过。但现在用快排不能过了。 因为这个OJ针…

【Vue笔记】基于vue3 + element-plus + el-dialog封装一个自定义的dialog弹出窗口组件

这篇文章,介绍一下如何使用vue3+element-plus中的el-dialog组件,自己封装一个通用的弹出窗口组件。运行效果如下所示: 目录 1.1、父子组件通信 1.2、自定义VDialog组件(【v-model】模式) 1.2.1、编写VDialog组件代码 1.2.2、使用VDialog组件 1.2.3、运行效果 1.3、自…

【支持向量机(SVM)】:算法原理及核函数

文章目录 1 SVM算法原理1.1 目标函数确定1.2 约束条件优化问题转换1.3 对偶问题转换1.4 确定超平面1.5 计算举例1.6 SVM原理小节 2 SVM核函数2.1 核函数的作用2.2 核函数分类2.3 高斯核函数2.3 高斯核函数API2.4 超参数 γ \gamma γ 1 SVM算法原理 1.1 目标函数确定 SVM思想…

【数据结构】树——链式存储二叉树的基础

写在前面 书接上文&#xff1a;【数据结构】树——顺序存储二叉树 本篇笔记主要讲解链式存储二叉树的主要思想、如何访问每个结点、结点之间的关联、如何递归查找每个结点&#xff0c;为后续更高级的树形结构打下基础。不了解树的小伙伴可以查看上文 文章目录 写在前面 一、链…

Java基于微信小程序+SSM的校园失物招领小程序

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

IDEA 2024.3 版本更新主要功能介绍

IDEA 2024.3 版本提供的新特性 IntelliJ IDEA 2024.3 的主要新特性&#xff1a; AI Assistant 增强 改进的代码补全和建议更智能的代码分析和重构建议Java 支持改进 支持 Java 21 的所有新特性改进的模式匹配和记录模式支持更好的虚拟线程调试体验开发工具改进 更新的 UI/UX 设…

Unity类银河战士恶魔城学习总结(P132 Merge skill tree with skill Manager 把技能树和冲刺技能相组合)

【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili 教程源地址&#xff1a;https://www.udemy.com/course/2d-rpg-alexdev/ 本章节实现了解锁技能后才可以使用技能&#xff0c;先完成了冲刺技能的锁定解锁 Dash_Skill.cs using System.Collections; using System…

linux 中mysql查看慢日志

1、到mysql容器&#xff0c;先登录到数据库&#xff0c;查看是否开启 mysql -h 127.0.0.1 -uroot -p SHOW VARIABLES LIKE slow_query_log; 2、如果没有开启&#xff0c;需要先开启 set global slow_query_log ON; 3、查看慢日志文件 SHOW VARIABLES LIKE slow_query_log…

奶龙IP联名异军突起:如何携手品牌营销共创双赢?

在快节奏的互联网消费时代&#xff0c;年轻消费群体对产品和品牌的要求越来越挑剔。因此在品牌年轻化的当下&#xff0c;一方面需要品牌自身形象也要不断追求时代感&#xff0c;另一方面品牌也需要不断引领消费者需求&#xff0c;提升竞争力和产品力。 奶龙作为近年来异军突起…

项目中排查bug的思路案例

bug描述&#xff1a;调用了删除的接口&#xff0c;执行成功了&#xff0c;也删掉了选中的数据&#xff0c;但是不执行删除后的处理操作&#xff0c;会报一个“系统未知错误&#xff0c;请反馈给管理员” 解决&#xff1a; 成功删掉了数据&#xff0c;但删除后的操作没有执行&a…

欧瑞博智能家居掀起风潮 助力新加坡智慧国2.0发展

&#xff08;狮城快讯&#xff09;在新加坡智慧国2.0计划的推动下&#xff0c;智能科技日益融入生活&#xff0c;智慧社区建设成为提升生活品质的关键。智能家居品牌ORVIBO凭借创新的AI技术和优质用户体验&#xff0c;迅速成为本地智能家居的领导者&#xff0c;从别墅、公寓到H…

【AI人脸整合包及教程】FaceFusion 3.0.0:AI人脸技术的新高度

一、引言 在当今数字化时代&#xff0c;AI技术不断发展并渗透到各个领域&#xff0c;其中AI人脸技术尤为引人注目。FaceFusion 3.0.0作为这一领域的代表性工具&#xff0c;正引领着新的潮流。 二、FaceFusion 3.0.0的功能特点 高度精确的人脸效果 FaceFusion 3.0.0利用先进的…

OLED透明屏在零售行业有哪些优势

OLED透明屏在零售行业具有诸多优势&#xff0c;这些优势使得它成为零售行业中一种创新且高效的展示工具。以下是对OLED透明屏在零售行业优势的详细分析&#xff1a; 1. 视觉吸引力与沉浸感 高透明度&#xff1a;OLED透明屏能够实现40%以上的透明度&#xff0c;使得屏幕后的物体…

win10 pip 永久镜像

打开文件夹&#xff0c;找到目录 &#xff1a;C:\Users\xxx\AppData\Roaming // xxx是你的用户名 如果看不到AppData文件夹&#xff0c;可以点击上方的查看 &#xff0c;勾选上隐藏的项目即可 然后再Roaming 目录下创建文件夹 pip 在pip文件夹下面创建 pip.ini 文件&#xf…