相信很多公司的前端开发人员都会选择使用vue+element-ui的形式来开发公司的管理后台系统,基于element-ui很丰富的组件生态,我们可以很快速的开发管理后台系统的页面(管理后台系统的页面也不复杂,大多都是分页查询类需求和增删改查)。但一个前端框架有优点,就必然会有一些缺点或bug存在,element-ui框架也不例外,甚至elementui框架的缺点或bug还很多,这里就不一一列举了,相信使用它的我们都心知肚明。
今天,本篇文章就针对element-ui的一个组件——select选择器进行一些改进,以达到我们实际的项目开发中想要实现的一个效果,或者说完善该组件的一些功能。当然了,还是在select选择器的基础上改进,不会对它的源代码做任何修改。
那么,具体做什么改进呢?就是我们文章标题所说的“select选择器多选时启用鼠标悬停折叠文字以tooltip显示具体所选值”。如果你没有做过这样的需求,或者没有听说过这样的效果,那你听起来可能会觉得有点绕,不过没关系,来张效果图你就知道了:
这种效果呢,element plus已经实现了,但它实现的效果不太好看,而且我们公司用的也不是element plus,而是element2,element2的select选择器又没有这样的实现,所以我就参考网上的大神们的资料自己用js写了一个这样的效果:
select多选时启用鼠标悬停折叠文字以tooltip显示具体所选值collapseTagsTooltip.js:
export default {
// 最多显示多少个tag
props: {
maxTagCount: {
type: Number,
default: 1
},
},
data() {
// 创建数字展示的tag
let countDom = document.createElement("span")
countDom.className = "jy-ui-collapse-tag"
return {
domSelectTags: null,
domSelect: null,
countDom,
toolTip: null,
toolTipArr: []
};
},
watch: {
'$attrs.value'(v) {
this.afterChange(v)
},
},
mounted() {
this.domSelect = this.$refs.select.$el
this.domSelectTags = this.domSelect.querySelector(".el-select__tags")
this.domSelectTags && this.domSelect.querySelector(".el-select__tags > span").after(this.countDom)
},
methods: {
querySelectorAll(txt) {
const selectRefs = this.$refs.select
if(!selectRefs) return []
const select = selectRefs.$el
if (!select) return []
return select.querySelectorAll(txt)
},
// vue 获取元素距离浏览器视口左侧的距离
offsetLeft(elements) {
let left = elements.offsetLeft
let parent = elements.offsetParent
while (parent != null) {
left += parent.offsetLeft
parent = parent.offsetParent
}
return left
},
// vue 获取元素距离浏览器视口顶部的距离
offsetTop(elements) {
let top = elements.offsetTop
let parent = elements.offsetParent
while (parent != null) {
top += parent.offsetTop
parent = parent.offsetParent
}
return top
},
// 获取当前元素所在的模块的第一个有滚动条的父元素
parentScroll(elements){
let dom = null
let parent = elements.parentNode
let flag = true
while (parent != null && flag) {
const style = this.isDOM(parent) ? this.getStyle(parent, 'overflow-y') : ''
if(style === 'auto' || style === 'scroll'){
dom = parent
flag = false
}
parent = parent.parentNode
}
return dom
},
// 根据className类获取祖先节点
getParent(elements, className){
let dom = null
let parent = elements.parentNode
let flag = true
while (parent != null && flag) {
const _className = this.isDOM(parent) ? parent.className : ''
if(_className.indexOf(className) > -1){
dom = parent
flag = false
}
parent = parent.parentNode
}
return dom
},
async afterChange(value) {
if (!this.domSelectTags) return
await this.$nextTick()
let awaitUntilNodeEqual = () => {
let { length } = this.querySelectorAll(".el-tag")
if (length != value.length) {
requestAnimationFrame(awaitUntilNodeEqual)
return;
}
if (length == 0) {
this.countDom.style.display = "none"
this.countDom.innerHTML = 0
}
this.handleInsideTags()
};
awaitUntilNodeEqual()
},
handleInsideTags() {
// 处理内部节点
let elTags = Array.from(this.querySelectorAll(".el-tag"))
// toolTip的内容
this.toolTipArr = []
elTags.forEach((elTag, index) => {
if (index >= this.maxTagCount) {
elTag.style.display = "none"
this.toolTipArr.push(elTag.innerText)
} else {
// 这里不用display = "inline-block",是因为display设置了inline-block后会导致用了align-items: center的样式会失效。
// display:flex已经block化了。
elTag.style.display = "flex"
}
});
let elCount = elTags.length
if (elCount > this.maxTagCount) {
this.countDom.innerHTML = `+${elCount - this.maxTagCount}`
this.countDom.style.display = "flex"
this.countDom.style.alignItems = "center"
} else {
this.countDom.style.display = "none"
this.countDom.innerHTML = 0
}
// 鼠标移入collapse-tags,即鼠标移入多选的数字标签时。
this.countDom.onmouseenter = self => this.mouseenter(self)
// 鼠标离开collapse-tags,即鼠标离开多选的数字标签时。
this.countDom.onmouseleave = () => this.mouseleave()
},
mouseenter({ target }){
// 微前端框架里需要被减去的宽度
let subtractWidth = 0
let subtractHeight = 0
let subTop = 0
if (window.__MICRO_APP_ENVIRONMENT__) {
// let alideNode = document.querySelector('body').querySelector('.d2-theme-container-aside')
subtractWidth = 0
subtractHeight = 0
subTop = 72
}
// 创建toolTip元素DOM
this.toolTip = document.createElement("div")
this.toolTip.className = "jy-ui-select-tooltip"
// 创建toolTip中内容的显示元素DOM
const toolTipContent = document.createElement("span")
toolTipContent.className = "jy-ui-select-tooltip-content"
toolTipContent.innerHTML = this.toolTipArr.join(',')
// 创建toolTip显示时所需的三角形元素DOM
const arrowBottom = document.createElement("span")
arrowBottom.className = "jy-ui-select-tooltip-arrow"
const arrowTop = document.createElement("span")
arrowTop.className = 'jy-ui-select-tooltip-arrow jy-ui-select-tooltip-arrow-top'
// 将toolTip中内容的显示元素DOM插入到toolTip元素中
this.toolTip.appendChild(toolTipContent)
// 将三角形元素插入到toolTip元素中
this.toolTip.appendChild(arrowBottom)
this.toolTip.appendChild(arrowTop)
// 将toolTip元素插入到body中
document.querySelector('body').appendChild(this.toolTip)
// target.offsetLeft - 当前鼠标移入的数字元素距离浏览器视口左侧的距离
const selectOffsetTop = this.offsetTop(this.domSelect) // 当前select元素距离浏览时视口顶部的距离
const targetOffsetLeft = this.offsetLeft(target) // 当前鼠标移入的数字元素距离浏览器视口左侧的距离
const slectOffsetHeight = this.domSelect.offsetHeight // slectOffsetHeight - 当前select元素的高度
const toolTipOffsetHeight = this.toolTip.offsetHeight // 当前所要显示的toolTip的高度
const toolTipOffsetWidth = this.toolTip.offsetWidth // toolTipOffsetWidth - 当前所要显示的toolTip的宽度
const targetOffsetWidth = target.offsetWidth // targetOffsetWidth - 当前鼠标移入的数字元素的宽度
// toolTip距离浏览器视口左侧的距离
let leftPos = targetOffsetLeft + (targetOffsetWidth / 2) - (toolTipOffsetWidth / 2)
// toolTip距离浏览器视口顶部的距离
let topPos = selectOffsetTop - toolTipOffsetHeight - 5
// 如果toolTip的上边被浏览器视口遮挡,则将toolTip放置在select的下边
if(topPos - subTop <= 0){
topPos = selectOffsetTop + slectOffsetHeight + 5
arrowBottom.style.display = 'none'
arrowTop.style.display = 'block'
}else{
arrowBottom.style.display = 'block'
arrowTop.style.display = 'none'
}
// 如果toolTip的左边被浏览器视口遮挡,则将toolTip的left置为2
if(leftPos <= 0){
leftPos = 2
let arrowLeftPos = targetOffsetLeft + (targetOffsetWidth / 2)
arrowLeftPos = Math.floor(arrowLeftPos) + 'px'
arrowBottom.style.left = arrowLeftPos
arrowTop.style.left = arrowLeftPos
}
// window.pageYOffset: safari获取scrollTop的方法
const bodyTop = document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset
const bodyHasScroll = this.getStyle(document.querySelector('body'), 'overflow') === 'hidden'
const floorBodyTop = Math.floor(bodyTop)
// 如果是被浏览器的滚动条滚到了视口的顶部,则将toolTip放置在select的下边。其中,bodyTop指的是网页滚动的距离
if(!bodyHasScroll && (floorBodyTop + toolTipOffsetHeight + 10 + subTop >= selectOffsetTop)){
topPos = selectOffsetTop + slectOffsetHeight + 5
arrowBottom.style.display = 'none'
arrowTop.style.display = 'block'
}else{
arrowBottom.style.display = 'block'
arrowTop.style.display = 'none'
}
const parentScroll = this.parentScroll(this.domSelect)
const parentScrollTop = parentScroll ? parentScroll.scrollTop : 0
const floorParentScrollTop = Math.floor(parentScrollTop)
// 弹框的高度缩小到一定程度时,也会出现滚动条,当这个滚动条滚动时,也会影响tooltip的位置。
// 用this.getParent(this.domSelect, 'el-dialog__wrapper')来获取el-dialog__wrapper,是因为弹窗关闭后,
// 会在body节点中依旧保留弹窗的节点dom,如果页面中打开的弹窗不止一个,此时要再获取el-dialog__wrapper的scrollTop就不知道要获取哪个弹窗的了。
const dialogWrapper = this.getParent(this.domSelect, 'el-dialog__wrapper')
const dialogWrapperScrollTop = dialogWrapper ? Math.floor(dialogWrapper.scrollTop) : 0
// 如果当前元素的父元素存在滚动条,且body元素的滚动条不存在,说明select组件有可能是在弹窗中且弹窗内可能会发生滚动。
if(parentScroll && bodyHasScroll){
topPos = topPos - floorParentScrollTop + floorBodyTop - dialogWrapperScrollTop
if(floorParentScrollTop + toolTipOffsetHeight + 10 + subTop + dialogWrapperScrollTop >= selectOffsetTop){
topPos = selectOffsetTop + slectOffsetHeight - floorParentScrollTop - dialogWrapperScrollTop + floorBodyTop + 5
arrowBottom.style.display = 'none'
arrowTop.style.display = 'block'
}else{
arrowBottom.style.display = 'block'
arrowTop.style.display = 'none'
}
}else if(parentScroll && !bodyHasScroll){
// 如果当前元素的父元素存在滚动条,且body元素的滚动条存在,说明select组件可能只是在页面中且其所在模块的某个父元素可能会发生滚动,
// 那么这个时候topPos的值其实已经包含了浏览器滚动条的滚动距离了,所以这里就不再加bodyTop了。
topPos = topPos - floorParentScrollTop
// 如果浏览器的滚动条和当前元素的某个父元素的滚动条发生了滚动且tooltip被顶部遮挡,则将toolTip放置在select的下边
if(floorBodyTop + floorParentScrollTop + toolTipOffsetHeight + 10 + subTop >= selectOffsetTop){
topPos = selectOffsetTop + slectOffsetHeight - floorParentScrollTop + 5
arrowBottom.style.display = 'none'
arrowTop.style.display = 'block'
}else{
arrowBottom.style.display = 'block'
arrowTop.style.display = 'none'
}
}
this.toolTip.style.display = 'block'
this.toolTip.style.left = Math.floor(leftPos) - subtractWidth + 'px'
this.toolTip.style.top = Math.floor(topPos) - subtractHeight + 'px'
// 如果toolTip的右边被浏览器视口遮挡,则将toolTip的left置为initial,right置为2
if(Math.floor(leftPos) + toolTipOffsetWidth >= document.body.offsetWidth){
this.toolTip.style.left = 'initial'
this.toolTip.style.right = '2px'
let arrowRightPos = document.body.offsetWidth - targetOffsetLeft - (targetOffsetWidth / 2) - 18
arrowRightPos = Math.floor(arrowRightPos) + 'px'
arrowBottom.style.left = 'initial'
arrowTop.style.left = 'initial'
arrowBottom.style.right = arrowRightPos
arrowTop.style.right = arrowRightPos
}
},
mouseleave(){
// 鼠标离开多选的数字标签时,删除插入到body中国的toolTip。
document.querySelector('body').removeChild(this.toolTip)
},
// 原生js获取元素的样式
getStyle(el, name){
if(window.getComputedStyle){
return String(getComputedStyle(el).getPropertyValue(name)).trim()
}else{
return el.currentStyle[name]
}
},
// 判断当前节点是否是dom节点,如果不判断的话,在使用getComputedStyle时,
// 会报Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.的错,因为getComputedStyle这个方法只能用在dom节点上。
isDOM(el) {
// 首先判断是否支持HTMLELement,如果支持,使用HTMLElement,如果不支持,通过判断DOM的特征,如果拥有这些特征说明就是ODM节点,特征使用的越多越准确
return (typeof HTMLElement === 'function')
? (el instanceof HTMLElement)
: (el && (typeof el === 'object') && (el.nodeType === 1) && (typeof el.nodeName === 'string'))
}
},
}
使用的时候,可能需要你基于element-ui单独封装一个select组件,然后你只需把这个文件引入到你封装的select组件中然后mixins一下就可以了。比如select.vue:
<template>
<el-select v-model="select" v-bind="{clearable, ...$attrs, collapseTags: false, 'collapse-tags': false}>
<el-option value="1" label="选项一" />
<el-option value="2" label="选项二" />
<el-option value="3" label="选项三" />
</el-select>
</template>
<script>
import collapseTagsTooltip from './collapseTagsTooltip'
export default {
mixins: [collapseTagsTooltip],
data(){
return {
select: []
}
}
}
</script>
写到这里,其实已经实现了本文所说的效果,但有几个地方需要注意:
1、我们在封装select组件时,要把select组件的 collapse-tags
属性置为false,且即使用户在使用select组件时传入了 collapse-tags
属性也不让他传入的那个属性起作用,为什么呢?其实,仔细看我们的实现逻辑就会知道,collapse-tags
属性为false时会把select多选后的所有选项都放在select框内,这个时候我们就可以获取到除了必须要展示出来的那几个选项之外的其他所有选项(这些其他选中的选项的value就要用tooltip来展示的),然后再把这些选项置为 display: none
,剩下的事情就是如何展示这些其他选项的问题了。试想一下,如果 collapse-tags
属性为true时会怎么样?element-ui的select选择器会把第一项展示在select框内,其余选中的节点的dom根本就不会出现在页面的源代码中,这个时候想获取除了选中的第一项的其他的选项,就比较麻烦了,也不是不可以实现,只是会很麻烦,因为你要用选中的key去循环匹配select下拉中与key一一对应的value。有人说这不就是一个双重循环嘛,是,循环一把拿到value没问题,可你有没有想过如果select的下拉数据源是通过远程搜索请求了接口获取的到呢?你要把每一次通过接口获取到的下拉数据源都保存到一个变量中,而且还得去重,去重之后再双重循环去获取到对应的value。有这么麻烦的步骤,直接将collapse-tags
属性置为false去获取剩下的那些选中的项,它不香吗?只是这样其实也有一个问题,比如接口一次性把两三千条下拉数据都吐给了前端,虽然前端可能只取了前100条展示了出来,可如果select组件有搜索的属性 filterable
,那么用户就可以通过搜索选中一两千条数据,此时可能就会造成select组件卡顿,因为什么呢?就是因为把 collapse-tags
属性置为了false,导致select组件中其实渲染了一两千个选中的dom节点。不过一下子选中一两千条数据的场景不多,如果你介意这样的问题,那你就把 collapse-tags
属性置为true,然后像之前说的那样去获取需要tooltip展示的数据。
2、我们这里也实现了select中最多展示几个选中项后其余的选中项以tooltip的方式展示,在使用时传入 maxTagCount
属性即可。
3、我们这里实现的效果并不会像element-ui的tooltip文字提示那样可以上下左右、左上左下、右上右下等等展示,只会根据浏览器的视口来上下展示。
4、我们这里实现的效果也可以用在弹窗中,比如弹窗中有select的多选效果,tooltip也是可以正常展示的,并且tooltip的top值会随着弹窗的纵向滚动条的滚动而变化。
5、我们这里实现的效果并不是基于element-ui的tooltip,因为它的tooltip没法用在我们的实现中,我是自己用js实现了一个tooltip。
6、我们这里实现的效果与element-ui的tooltip还不一样的地方是element-ui的tooltip在鼠标离开后会把tooltip的dom节点留在页面的源代码中,而我实现的则是鼠标离开后就在页面的源代码中销毁了tooltip的dom节点。想留下节点,会很麻烦,所以就没有实现。
7、我们这里实现的效果是鼠标悬停在折叠文字上才出现tooltip,并不像网上其他人那样实现的是鼠标悬停在select上就展示tooltip,因为他们是直接在select的外面套了一个element-ui的 el-tooltip
。
7、我们这里也实现了select中最多展示几个选中项后其余的选中项以tooltip的方式展示,在使用时传入 maxTagCount
属性即可。
作者:小坏
出处:http://tnnyang.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。
我们知道单细胞数据的激增和它的高维特征催生了针对单细胞数据的数据格式:Seurat对象、singlecellexperiment对象以及anndata对象。空间数据的出现为表达量数据带来了新的视角,一般它包含图像数据,空间坐标数据以及表达量数据。虽然以上三种数据格式可以轻松地把空间信息包装起来,但是为了凸显空间位置的重要性,人们开发了与单细胞的singlecellexperiment类似的SpatialCellExperiment用于空间数据管理与分析。当然,另一个R包:SpatialExperiment也在不断地完善中。那么,我们不禁要问为什么之前的单细胞数据格式可以轻松地包装空间数据,还要开发类似SpatialCellExperiment呢?我们知道,毕竟单细胞的是单细胞的,虽然在数据格式上可以很好地容纳,毕竟内核部分没有针对空间分析方法。比如,SpatialCellExperiment封装了sf提供了对空间数据分析的支持,这是一种编码空间向量数据的标准化方法。可用来实现一个SpatialPolygonExperiment类,包含精确的细胞亚群几何形状以及基因和文库元数据(meta
1.为什么要学习GoGo语言宣称为互联网时代的C语言,那她有那些特性值得我们必须学习呢:并行与分布式支持。除了我们日常熟悉的进程和线程,Go语言中提供了协程coroutine,从而简化了并行开发的难度。软件工程支持。这体现在很多方面,我觉得Go语言借鉴了Python的做法,通过代码风格规范进行强制统一,从而减少工程管理的难度。编程思想的变化。过去面向过程和面向对象是两大编程流派,Go语言则使用批判吸收的方法,融合众家之长,以更实用的目标作为语言发展的基调。2.Go语言简史Go语言的历史要从贝尔实验室开始说起,我们知道贝尔实验室计算科学研究中心的肯•汤普逊KenThompson和丹尼斯•里奇DennisRitchie开发了Unix系统以及开发系统所使用的C语言。在这之后他们还开发了Plan9操作系统。后来包括KenTompson在内的Plan9原班人马加入Google,在Google他们创立了Go语言。2007年9月之前Go语言是20%自由时间的实验项目,到了2008年5月Google发现Go语言的巨大潜力,开始全力支持这个项目。Go语言的第一个版本是2009年11月正式对外发布。Go语
初学Ruby,很多需要学习,现在开始尝试使用Ruby来写一个脚本,其中用到了很多文件相关的操作,这里阶段地整理一些。便于后续的再次查找。文件或目录是否存在1File.exist?('file_path')是否为文件1File.file?("file_path")是否为目录1File.directory?("file_path")从路径中获取文件名1 2 3 4 5 6 7File.basename('/tmp/adb.log')#=>"adb.log" #从上面结果中移除扩展名 File.basename('/tmp/adb.log','.log')#=>"adb" #或者 File.basename('/tmp/adb.log','.*')#=>"adb"列出目录下的全部子文件1 2#替换putschild为自己的操作 Dir['/tm
安装workerman参考:http://www.workerman.net/install下载workerman扩展包gitclonehttps://github.com/walkor/Workerman手册参考:http://doc3.workerman.net/一、WorkerMan代码规范1、 类采用首字母大写的驼峰式命名,类文件名称必须与文件内部类名相同,以便自动加载。2、 使用命名空间,命名空间名字与目录路径对应,并以开发者的项目根目录为基准3、 普通函数及变量名采用小写加下划线方式4、 类成员及类的方法采用首字母小写的驼峰形式5、 函数及类的参数采用小写加下划线方式二、Worker类属性说明名称类型说明$idInt当前worker进程的id编号,范围为0到$worker->count-1$countInt设置当前Worker实例启动多少个进程,不设置时默认为1$nameString设置当前Worker实例的名称,方便运行status命令时识别进程。不设置时默认为none$userString设置当前Worker实例以哪个用户运行。此属性只有当前用户为root时才能生
首先先引入一段小新闻,从中涉及到的一些知识点楼主会标出: 仅有“人均”是不够的 日前,发改委发展规划司司长徐林表示,我国人均GDP已达到6700多美元,属于中高收入国家的行列。目标是希望通过“十三五”的努力,用世界银行的标准接近高收入国家的行列。 统计数字常遭遇吐槽 赵丽:“我国人均GDP已达到6700多美元,属于中高收入国家的行列”的言论一出现,就遭到了许多人的“吐槽”,有不少网友表示“被中高收入”,拖了国家后腿。 许建立:其实,普通人对统计数据的“不适”已经不是第一次,这些年来“被平均”、“被幸福”等情况屡屡出现。如2012年,某大学发布的《中国民生发展报告2012》中提及,全国家庭的平均住房面积为116.4平方米。许多人看到后的第一反应即是不相信。 肖龙凤:这种感觉其实很好理解。对普通人而言,更多的是根据自身生活状况去印证、判断统计数据是否真实。如果他发现自己以及周围人的情况和数据有不小的出入,很自然就会产生疑问。① 人均数难以反映差异 赵丽:不过,统计数据和居民感受不一致,并不代表数据就不准确,这里面可能有一些别的因素。比如说,人均GDP和老百姓的人均实际收入是
前言本文的目的在于绘制练习,将被收录在FlutterUnit的绘制集录当中。另外在《Flutter语法基础-梦始之地》中有一章需要使用这个表盘,但并不想涉及过多的绘制知识,故而在此进行实现。效果如下,外圈是线条围成的表盘,内部有个小圆指示当前位置,中间显示信息文字。1.需求分析这里绘制的是秒表表盘,一圈是1分种,每秒有对应3格,也就是说一共有180格,每格间的夹角是2°。下面来看一下绘制过程中需要的参数,首先需要一个Duration对象,表示当前秒表的时间。另外,根据时间可以计算出小圆的角度。绘制时可以配置的参数,比如半径、刻度颜色、文字颜色、样式等。另外刻度的长短、粗细、小圆半径等更细致的参数可以根据半径进行计算得出。2.刻度绘制如下所示正方形是绘制区域,左侧刻度宽为scaleLineWidth,通过矩形区域的宽度和_kScaleWidthRate比例来确定。constdouble_kScaleWidthRate=0.4/10; finaldoublescaleLineWidth=size.width*_kScaleWidthRate;复制绘制刻度时使用直线,只要确定左右两点坐标即可
1.接口描述接口请求域名:tcb.tencentcloudapi.com。 销毁静态托管资源,该接口创建异步销毁任务,资源最终状态可从DestroyStaticStore接口查看 默认接口请求频率限制:20次/秒。 APIExplorer提供了在线调用、签名验证、SDK代码生成和快速检索接口等能力。您可查看每次调用的请求内容和返回结果以及自动生成SDK调用示例。 2.输入参数以下请求参数列表仅列出了接口请求参数和部分公共参数,完整公共参数列表见公共请求参数。 参数名称 必选 类型 描述 Action 是 String 公共参数,本接口取值:DestroyStaticStore。 Version 是 String 公共参数,本接口取值:2018-06-08。 Region 否 String 公共参数,本接口不需要传递此参数。 EnvId 是 String 环境ID CdnDomain 否 String cdn域名 3.输出参数 参数名称 类型 描述 Result String 条件任务结果(succ/fail) Reque
随着Qt6的发布,cmake也正式宣告接管qmake的工作了。 在之前的一篇博客里我介绍了如何使用cmake管理你的qt项目,不过有一点我没有讲,那就是对国际化(i18n)的处理。 今天我们就来介绍下如何使用cmake+clion配置管理一个包含了国际化支持的项目。 准备工作 你需要准备下面的工具 Qt5.13+(我使用的是Qt5.15.2) CLion2020.3+ GCC9.0+(最好支持c++17,最低要求是支持c++11) 其中GCC一般自己安装的Qt会有附带,否则在Windows上使用vs2019的编译器也是可以的。 在Linux上如果不想自己下载安装Qt的话也可以使用系统仓库打包好的: #ubuntu sudoapt-getinstallbuild-essentiallibglu1-mesa-devlibpulse-devlibglib2.0-dev sudoapt-get--no-install-recommendsinstalllibqt*5-devqt*5-devqml-module-qtquick-*qt*5-doc-html #Arch/Manjato su
TwoPaths TimeLimit:2000MS MemoryLimit:65536KB 64bitIOFormat:%I64d&%I64u Submit Status Description Asyouknow,Bob'sbrotherlivesinFlatland.InFlatlandthereare ncities,connectedbyn - 1two-wayroads.Thecitiesarenumberedfrom1to n.Youcangetfromonecitytoanothermovingalongtheroads. The«TwoPaths»company,whereBob'sbrotherworks,haswonatendertorepairtwopathsinFlatland.Apathisasequenceofdifferentcities,connectedsequentiallybyroads.Thecompanyisallowedtochoosebyitselfthepathstorep
这两款软件我都在用,要说时间最长感情最深的应该是腾讯QQ,1999年诞生的那年就在用QQ了! 不过感情归感情,个人看法归个人看法,不能用感情来判断。 正所谓外行看热闹,内行看门道。从事实上讲在使用这两款软件的时候,腾讯QQ是有不好的地方,奇虎360也不是没有做错的地方。说实话随着奇虎公司和腾讯公司的盈利随着时间推移再不断增加,他们都已经发展成为了两个比较大的平台,奇虎平台和腾讯平台。从本职工作来看一个是电脑安全、一个是即时通讯,从外行的角度看:一个属于“医学行业”、一个属于“通讯行业”,一个是为电脑看病的,一个是为人们在互联网上沟通的,这两家公司不应该有利益冲突产生矛盾呀,恰恰相反,他们的“触手”交错在了一起。 在经济学领域及经济法,我是个外行,所以腾讯是否属于垄断,让最高人民法院去判决。对于腾讯我就想弄清两点,请问国外即时通讯为何进不了中国市场或是无法在中国市场占有一席之地?这么多年过去了中国又为何没有第二家“QQ软件”诞生?好吧,全国人民只能用腾讯的QQ软件了,用其他的也没法和好友沟通。这就好比假设移动和电信不能互通电话、短信等其他业务,大部分消费者都在用移动的产品沟通,如果你选了
Android之文件搜索工具类/***@detail搜索sdcard文件*@param需要进行文件搜索的目录*@param过滤搜索文件类型*/privatevoidsearch(Filefile,String[]ext){if(file!=null){if(file.isDirectory()){File[]listFile=file.listFiles();if(listFile!=null){for(inti=0;i<listFile.length;i++){search(listFile[i],ext);}}}else{Stringfilename=file.getAbsolutePath();for(inti=0;i<ext.length;i++){if(filename.endsWith(ext[i])){list.add(filename);break;}}}}} Android之录音工具类 /***录音工具类**@authorrendongwei*/publicclassRecordUtil{privatestaticfinalintSAMPLE
我们经常需要在程序中判断一个字符是否为CJK(Chinese、Japanese、Korean)语言的字符。 例如,在Contacts里面程序需要判断联系人姓名的所属语言。 今天为大家介绍一种NameSplitter中使用的判断字符所属语言的方法。 以判断字符是否为中文为例。 首先,通过guessFullNameStyle函数来判断字符所属语言(使用UnicodeBlock来判断); publicstaticintguessFullNameStyle(Stringname){ if(name==null){ returnFullNameStyle.UNDEFINED; } intnameStyle=FullNameStyle.UNDEFINED; intlength=name.length(); intoffset=0; while(offset<length){ intcodePoint=Character.codePointAt(name,offset); if(Character.isLetter(codePoint)){ UnicodeBlockunicodeBlock
Description: WriteafunctioncalledvalidParenthesesthattakesastringofparentheses,anddeterminesiftheorderoftheparenthesesisvalid.validParenthesesshouldreturntrueifthestringisvalid,andfalseifit'sinvalid. Examples: console.log(validParentheses("()"));//true console.log(validParentheses(")(()))"));//false console.log(validParentheses("("));//false console.log(validParentheses("(())((()())())"));//true 复制 myanswer functionvalidParentheses(parens){ varn=0; for(vari=0;i<parens.length;i++){ if(parens[i
北哥在前文陆续总结了程序员成长所具备的核心能力,以及Java程序员成长过程中应学习的基础知识。在一个Java程序员工作3、5年之后,已经可以承担起大部分的核心开发工作,成长为团队中的高级开发人员。大部分工作中遇到的问题都已经可以自行解决。这个阶段很多同学会面临着新的成长困惑,到底接下来自己还需要在哪些方面继续提升?如何能够成长为团队里面的架构师呢? 市面上有很多分析和拆解架构师能力的书籍,例如《聊聊架构》《亿级流量网站架构核心技术》《大型网站技术架构:核心原理与案例分析》等,书中有一些相关的实战和理论知识分享。这些书籍如果有时间推荐大家去读一读。 今天北哥结合自己工作中的经验,也来浅谈一下如何做应用系统架构设计。 需要说明的是,架构师本身要求的是综合能力,架构也分为业务架构、应用系统架构、技术架构、数据架构等多个维度多个细分领域,但今天分享的关于架构的相关内容,更多还是侧重在服务端的应用系统架构。 01 指导思想 作为一个架构师,在做应用系统架构时,最好逐步沉淀自己的一套指导思想,指导思想用于在做架构设计过程中遇到困惑或遇事不决时的一个指引。我个人总结下来的经验有以下三点
QGroundControlSourceCodeLearningSeries-1 写在前面:这个系列将会以QGroundControlStableV3.5.1的源代码为基础进行学习。 由于QGroundControl的项目庞大,包含的文件较多,在涉及到src目录下的文件时,直接给出文件名,如main.cc,其他子模块或子文件夹的文件会给出具体路径(不含前缀src)。 本系列作者:Briuture。 main.cc 程序的入口文件main.cc,由于QGroundControl项目的目标是跨平台构建应用,在进入主函数前会根据不同构建环境的宏定义执行不同的行为。 在桌面(Win/Linux/Mac)平台上,该应用在运行前会检查是否有同一实例正在运行。检查的功能由RunGuard类完成,该类在文件RunGuard.cc文件中定义。并且仅在main函数开头的位置使用(桌面环境): #ifndef__mobile__ RunGuardguard("QGroundControlRunGuardKey"); if(!guard.tryToRun()){ return0; } #endif 复制
<project....> ............... <build> <finalName>包名</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>1.4.5.RELEASE</version> <configuration> <mainClass>主类路径</mainClass> <layo
#include<stdio.h> #defineN5 #defineM80 typedefstruct { charname[M]; charauthor[M]; }Book; intmain() { Bookx[N]={{"一九八四","乔治.奥威尔"}, {"美丽新世界","赫胥黎"}, {"昨日的世界","斯蒂芬.茨威格"}, {"万历十五年","黄仁宇"}, {"一只特立独行的猪","王小波"} }; inti; FILE*fp; fp=fopen("data1.txt","w"); if(fp==NULL) { printf("failtoopenfile\n"); return1; } for(i=0;i<N;++i) { fprintf(fp,"%-20s%-20s\n",x[i].name,x[i].author); printf("%-20s%-20s\n",x[i].name,x[i].author); } fclose(fp); return0; }复制 #include<stdio.h> #de
如何在PS里把证件照调正 1、打开PS软件,选择文件然后点击打开按钮。2、在打开的对话框中选择需要修正的身份证相片,点击打开按钮。3、打开该身份证相片以后选择钢笔工具,将身份证勾选出来。4、可以看到当前的身份证已经被勾选出来了。5、在PS中新建一个A4纸张大小的画布,将该勾选的身份证托移到画布上。6、然后点击菜单栏的视图,选择新建参考线。7、在出现的新建参考线对话框中选择垂直和水平,分别建立4条参考线。8、依据身份证的长宽尺寸将4条参考线的区域设置好以后,按键盘上的ctrl和T键,分别选择斜切,调整该图片至端正的状态。9、即可看到该图片经过处理以后已经端正了,左图为处理过的端正状态,右图是未处理的原图。 *********************************************************************************** 如何在photoshop中将身份证正反面做在一张上 1、首先我们打开桌面上的PSCC; 2、按快捷键Ctrl+N新建一个高度为297、宽度为210的图层; 3、按Ctrl+O快捷键打开我们已经拍好的(或者扫描好的)身份证
也是非常经典的一道题 比较简单的做法是: 设dp[i]i:以nums[i]作为一个子数组的,最长的上升子序列 则有 无后效性:i肯定不会影响i之前的。 子问题重叠:算i+1,i+2..n时,都需要dp[i] 最优子结构:for(intj=0;j<i;++j)if(nums[j]>nums[i])dp[i]=max(dp[i],dp[j]+1); intret=0; for(inti=0;i<n;++i){ scanf("%d",&nums[i]); for(intj=0;j<i;++j){ if(nums[j]<nums[i]){ dp[i]=max(dp[i],dp[j]+1); } } ret=max(dp[i]+1,ret); } printf("%d\n",ret); 复制 但是,当n>=100000时,很容易超时 所以需要更高级的算法 设dp[i]i:最长上升子序列长度等于i时,最后一个数字。当然,有可能会更新dp[i]的值。(取最小值) 则有 无后效性:i肯定不会影响i之前的。又因为数组的顺序,就算修改