# 2019年11月技术日常
# 2019/11/28 周四
# class的staic属性
由于目前class只支持static方法,static属性目前还处于试验性功能(stage-3)阶段,如果不装babel,无法兼容chrome https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes/Class_elements
Class A {
static a = 1;
}
// 改为
A.a = 1;
兼容性相关 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes
# 2019/11/27 周三
# input输入监听
onchange事件只有失去焦点时才会触发,oninput值改变了会触发
# vue watch深度监听
如果watch监听对象属性值的改变,需要用到deep: true, 这种情况对象内部的变化虽然可以监听到,但不能监听到具体改动,watch的newval 和val 一致,有些情况可以考虑使用computed属性
vue watch监听数据,新老值一样? (opens new window)
# 2019/11/26 周二
# git 创建新分支提交到origin
在本地 pc-v2 分支基础上,新建一个分支 pc-v2-zuo,没有推送的远程。
git branch —set-upstream-to=origin/pc-v2-zuo pc-v2-zuo
# 提示如下
#if you are planning on basing your work on an upstream branch that already exists at the remote, you may need to run "git feach" to retrieve it
# 如果您打算基于远程已经存在的上游分支工作,则可能需要运行“ git feach”来检索它
# if you are planning to push out a new local branch that will track its remote counterpart, you may want to use "git push -u" to set the upstream config as you push
# 如果您打算推出一个新的本地分支来跟踪其远程副本,则可能需要在推送时使用“ git push -u”设置上游配置
# 先push
git push origin pc-v2-zuo:pc-v2-zuo
# 再将当前分支关联到远程分支
git branch —set-upstream-to=origin/pc-v2-zuo pc-v2-zuo
问题:如果我从 pc-v2 的基础上创建的新分支,并创建了远程分支。当 pc-v2 改动时,在新的分支 pc-v2-zuo 上 git pull 是否可以拉取到 pc-v2 的最新改动,是否只能在本地 pc-v2 上 git pull 然后在本地 pc-v2-zuo 上 git merge pc-v2 才行 ?
# 2019/11/25 周一
# package-lock.json问题
任何更新 node_modules 和 / 或 package.json 依赖的命令npm install,npm rm,npm update都会自动同步现有的package-lock.json文件。
- package-lock.json会锁定安装时包的版本号,且需要上传到git,以保证其他人在npm install时大家的依赖能保证一致。
自npm 5.0版本发布以来,npm i的规则发生了三次变化。
1、npm 5.0.x 版本,不管package.json怎么变,npm i 时都会根据lock文件下载package-lock.json file not updated after package.json file is changed · Issue #16866 · npm/npm 这个 issue 控诉了这个问题,明明手动改了package.json,为啥不给我升级包!然后就导致了5.1.0的问题...
2、5.1.0版本后 npm install 会无视lock文件 去下载最新的npm 然后有人提了这个issue why is package-lock being ignored? · Issue #17979 · npm/npm 控诉这个问题,最后演变成5.4.2版本后的规则。
3、5.4.2版本后 如果改了package.json,且package.json和lock文件不同,那么执行
npm i
时npm会根据package中的版本号以及语义含义去下载最新的包,并更新至lock。如果两者是同一状态,那么执行npm i
都会根据lock下载,不会理会package实际包的版本是否有新。
参考:
npm install 生成的package-lock.json是什么文件?有什么用? (opens new window)
package-lock.json的作用 (opens new window)
NPM package-locks 中文 (opens new window)
NPM package-locks 英文 (opens new window)
# 2019/11/22 周五
# v-if 里面不能使用filters
过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示。
# 2019/11/21 周四
# 服务端渲染优点
- 利于SEO,搜索引擎无法渲染js
- 更安全,不暴露请求的接口到外部
- 首屏渲染速度快
# 画比1px还细的线或border
一般使用transform缩小0.5倍来实现,如果是border先将元素放大2倍,再缩小0.5倍,放大缩小后还是以放大的空间来占位,使用positon:absolute脱离标准文档流,就不会有两倍的占位了。
/* 比1px还细的线 */
.thinline {
height: 1px;width:100%;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
background:#ccc;
}
# 部分安卓机型scale后border显示不全的问题
解决方法是将样式用style写在内联样式里,刚开始不相信写成内联样式就可以解决这个问题,但实践后发现确实可以解决这个问题。
# flex布局align-self使用场景
一般flex布局后,item子项某一个高度比较高,其他子项的高度也会是高度最高的子项高度。设置border时会特别明显。如果需要让item高度适应内容,就可以使用 align-self: flex-start。
https://www.yuque.com/guoqzuo/piylht/kg7660#45717a91
# 2019/11/19 周二
# progressEvent.total为0的问题
AJAX 进度信息progressEvent.lengthComputable false
let {loaded = 0, total = 0, lengthComputable } = this.progressEvent
// 对于 progressEvent.lengthComputable 为false的接口,total属性会无效
// 参考:https://developer.mozilla.org/en-US/docs/Web/API/ProgressEvent/lengthComputable
if (lengthComputable) {
if (total === 0) return ''
this.progressText = `下载中: ${this.formatFileSize(loaded)} / ${this.formatFileSize(total)}`
// 数据百分比,进度 1 - pendingPercent
this.percentage = this.pendingPercent * 100 + Math.ceil((loaded / total)*(1 - this.pendingPercent) * 100)
} else {
// 资源无法计算size, total无效的情况
this.progressText = '下载中: ${this.formatFileSize(loaded)}'
// 进度无法精准计算,只能模拟,没触发一次onprogress时间,进度增加10%,加到90%就停止
if (this.percentage <= 80) {
this.percentage += 10
}
}
formatFileSize(value) {
let sizeArr = [
{ sizeStr: 'B', index: 10 },
{ sizeStr: 'KB', index: 20 },
{ sizeStr: 'MB', index: 30 },
{ sizeStr: 'GB', index: 40 },
{ sizeStr: 'TB', index: 50 },
]
for (let i = 0, len = sizeArr.length; i < len; i++) {
if (value < 2 ** sizeArr[i].index) {
let newVal = value / 2 ** (sizeArr[i].index - 10)
newVal = Number.isInteger(newVal) ? newVal : newVal.toFixed(2)
return `${newVal}${sizeArr[i].sizeStr}`
}
}
return 'too large > 1025 T'
}
# leetcode 26题/88题
https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/submissions/
https://leetcode-cn.com/problems/merge-sorted-array/submissions/
解题demo
https://github.com/zuoxiaobai/fenote/tree/master/src/leetcode/task
# 2019/11/15 周五
# space-between与 space-around
flex布局justify-content属性值区别
- space-between 最左、最右item贴合左侧或右侧边框,item与item之间间距相等。
- space-around 每个item 左右方向的margin相等。两个item中间的间距会比较大
# css及html代码风格规范
Bootstrap 编码规范:编写灵活、稳定、高质量的 HTML 和 CSS 代码的规范。https://codeguide.bootcss.com/
不管有多少人共同参与同一项目,一定要确保每一行代码都像是同一个人编写的。
# jsdoc注释规范
参考: https://www.jianshu.com/p/46519b0499c3
# 什么是yarn
https://yarn.bootcss.com/
Yarn 是一个快速、可靠、安全的依赖管理工具。是 NPM 的替代品。
今天看看了ts实战指南这本书,里面是这样介绍Yarn的:
Yarn [jɑːn] 是facebook,google等公司共同开发的一款新的js包管理工具,并没有试图完全取代npm,Yarn同样是从npm获取包。存在的目的是:解决团队使用npm面临的少数问题,如版本锁定,并行安装、文案输出等
macos安装Yarn方法
brew install yarn
Yarn基本用法
# 初始化一个新项目
yarn init
# 添加依赖包
yarn add [package]
yarn add [package]@[version]
yarn add [package]@[tag]
# 添加到不同依赖类别
yarn add [package] --dev
yarn add [package] --peer
yarn add [package] --optional
# 更新依赖包
yarn upgrade [package]
yarn upgrade [package]@[version]
yarn upgrade [package]@[tag]
# 移除依赖包
yarn remove [package]
# 安装项目的全部依赖
yarn 或者 yarn install
# 2019/11/14 周四
# Number.prototype.toLocaleString()
返回千分位逗号分隔的字符串.
// MDN文档: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString
var number = 12123
number.toLocaleString() // "12,123"
number.toLocaleString('en', {style:'currency', currency:'USD'}) // "$12,123.00"
number.toLocaleString('cn', {style:'currency', currency:'CNY'}) // "¥12,123.00"
# 状态管理的使用场景
之前可能是很少写非常复杂的联动逻辑,发现如果多组件需要取很多公共数据做检验联动时,状态管理是非常有必要的。这是一个很好的使用场景。如果场景不是很复杂,那就没必要使用状态管理。想到之前看vuex官方文档时的一句话: Flux libraries are like glasses: you’ll know when you need them.(Flux 架构就像眼镜:您自会知道什么时候需要它。) https://vuex.vuejs.org/
# 2019/11/13 周三
# Mac zip压缩加密
zip -e 目标文件名.zip 需要加密的zip文件
# 输入上面的命令后,会提示输入两次密码
更多zip命令相关用法,可以在控制台使用 man zip 查看文档
# 2019/11/12 周二
# vscode git插件 GitLens
vscode插件名称: "GitLens -- Git supercharged",安装后点击某一行代码,都会显示最近的git提交记录,非常好的一个git插件
# toFixed() 对number取整或保留指定小数位
/**
* Number.prototype.toFixed()
* The toFixed() method formats a number using fixed-point notation.
* https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed
*
* 使用方法:
* numObj.toFixed(digits)
* @params { Integer } digits 可选 保留精度,为空时,默认为0,即取整
* @returns { String } 返回转换后的字符串
*/
var a = 1.235
a.toFixed() // "1"
typeof a.toFixed() // "string"
a.toFixed(2) // "1.23"
重点来了,tofixed()需要注意的地方:
- 四舍五入不精确的问题,类似于 0.1 + 0.2 === 0.3 不成立
var a = 0.15
var b = 0.25
a.toFixed(1) // "0.1" 注意这里四舍五入异常
b.toFixed(1) // "0.3" 这里四舍五入又是成功的
// 如果希望精准的保留1位小数可以 Math.round(a*10) / 10, 如果是两位 100,n位 Math.pow(10, n)
Number.prototype.myToFixed = function (num) {
// 在原型方法注入 myToFixed函数,这里怎么获取当前的值呢?可以使用this
// 注意 this 是一个Number对象
// var a = Number(2) // 2 typeof a 为 "number"
// var b = new Number(2) // Number{2} typeof b 为 "object"
// 获取值需要使用 b.valueOf() // 2
// 如果没有传参数
if (num === undefined) {
return Math.round(this.valueOf())
}
// 如果有传参,且为整数
if (Number.isInteger(num)) {
var tempCount = Math.pow(10, num)
var tempNum = Math.round(this.valueOf() * tempCount) / tempCount
// 这一步其实已经就可以了。但对于保留整数后面两位小数来说,会有bug
// var a = 2
// a.myToFixed(2) => 2 而不是 2.00
// 需要再转换下
return tempNum.toFixed(num)
} else {
throw new Error('参数必须是number类型,且必须是整数')
}
}
- 负数的运算符优先级问题
-2.12.toFixed(1) // -2.1 注意返回的字符串,被 - 操作后就是number了
(-2.12).toFixed(1) // "-2.1"
# 2019/11/11 周一
# 移动端屏幕尺寸相关
# 什么是devops
参考: https://www.zhihu.com/question/58702398/answer/235777073
DevOps 是 Development(开发)和 Operations(运维) 的组合词
目前学术界和从业人员还没有为 "DevOps" 建立唯一的定义
DevOps可以改变 运营、开发、测试人员在开发和交付过程中协作的方式。
网易云认为:DevOps 强调的是高效组织团队之间如何通过自动化的工具协作和沟通来完成软件的生命周期管理,从而更快、更频繁地交付更稳定的软件
DevOps 的出现是由于软件行业日益清晰地认识到,为了按时交付软件产品和服务,开发部门和运维部门必须紧密合作。
企业为什么需要DevOps,DevOps有什么依赖?网易云认为:
- 为了抓住商业机会,业务需要快速迭代,不断试错,因此,企业需要依赖拥有持续交付的能力,这些不仅包括技术需求还包括产品的需求,如何能拥有持续交付的能力,大而全的架构因为效率低下,显然是不合适的。于是演变出微服务架构来满足需求,通过把系统划分出一个个独立的个体,每个个体服务的设计依赖需要通过12 要素的原则来规范完成。
- 系统被分成了几十个甚至几百个服务组件,则需要借助DevOps 才能很好地满足业务协作和发布等流程。
- DevOps 的有效实施需要依赖一定的土壤,即敏捷的基础设施服务,现实只有云计算的模式才能满足整体要求。
DevOps 希望做到的是软件产品交付过程中IT工具链的打通,使得各个团队减少时间损耗,更加高效地协同工作。
# 什么是 serverless
字面意思是无服务器,小程序云开发就是一种
- 发展过程: 物理设备 => 虚拟机 => 容器 => serverless(只需关注业务逻辑,不需要关心服务器资源等)
- 减少人力成本7-8人开发 => 2-3人
- 弹性伸缩,所需耗时: 虚拟机(小时级) => 容器(分钟级) => serverless(毫秒级)
- 故障恢复方面优势
- serverless 支持语言:nodejs,java,go,php,python
- 注意:强依赖某个平台及其开放的服务
- 云函数 Serverless Cloud Function https://cloud.tencent.com/product/scf
# CI/CD/CO
CI持续集成 => CD持续交付 => CO持续运营
# Docker与K8S集群
# Docker容器
容器是虚拟机的一个发展,相对传统的虚拟机,容器的优点:
特性 | 虚拟机 | 容器 |
---|---|---|
隔离级别 | 操作系统级 | 进程级 |
隔离策略 | Hypervisor | CGroups |
系统资源 | 5-15% | 0-5% |
启动时间 | 分钟级 | 秒级 |
镜像存储 | GB-TB | KB-MB |
集群规模 | 上百 | 上万 |
高可用策略 | 备份、容灾、迁移 | 弹性、负载、动态 |
# K8S集群
K8S是基于容器的集群管理平台,它的全称,是kubernetes。
- Kubernetes这个单词来自于希腊语,含义是舵手或领航员。K8S是它的缩写,用“8”字替代了“ubernete”这8个字符。
- 和Docker不同,K8S的创造者,是众人皆知的行业巨头——Google。K8S是2014年6月由Google公司正式公布出来并宣布开源的。
- 一个K8S系统,通常称为一个K8S集群(Cluster)。这个集群主要包括两个部分:
- 一个Master节点(主节点)主要负责管理和控制
- API Server 是整个系统的对外借款,供客户端何其他组件调用,相当于营业厅
- Scheduler 负责对集群内的资源进行调度,相当于调度室
- Controller manager负责管理控制器,相当于大总管
- 一群Node节点(计算节点)Node节点是工作负载节点,里面是具体的容器
- Docker 用来创建容器
- kubelet 主要负责监视指派到它所在Node上的Pod,包括创建、修改、监控、删除等
- kebu-proxy 主要负责为Pod对象提供代理
- Fluentd 主要负责日志收集、存储与查询
- kube-dns(可选)
- Pod, Pod是Kubernetes最基本的操作单元。一个Pod代表着集群中运行的一个进程,它内部封装了一个或多个紧密相关的容器。除了Pod之外,K8S还有一个Service的概念,一个Service可以看作一组提供相同服务的Pod的对外访问接口。
- 一个Master节点(主节点)主要负责管理和控制
# 2019/11/09 周六
# 原生JS自定义prompt组件
旧的jsp项目,需要用到prompt功能,但需要优化下UI,整体导入elementUI不合适,就自己用原生JS写了个。样式、div结构,直接从elementUI message-box审查元素里面抽离,相关点击事件,校验,自己封装,具体代码位置: https://github.com/zuoxiaobai/fedemo/blob/master/src/DebugDemo/prompt/index.html
/**
* 向window挂载 elcustomPrompt 函数,代替系统的prompt
* window.elCustomPrompt IE9+
* 从 element UI中抽出messagebox样式结构
*/
(function() {
/**
* @description elementUI风格自定义propmt封装
* @param { String } title 标题propmt第一个参数
* @param { String } placeholder input的placeholder
* @param { Function } validateFunc 动态校验值函数
* - 点击确认后,执行的函数,参数为当前值,
* - return格式:
* { result: true, msg: '成功'}
* { result: false, msg: '自定义错误信息' }
* 考虑到阻塞程序向下执行,兼容性问题,不使用promise,使用回调函数。
* @param { Function } callback 获取到值后的回调
*/
function elCustomPrompt(title, placeholder, validateFunc, callback) {
console.log('show elCustomPrompt')
var deleteImgUrl = 'delete.png' // 16 * 16
var errMsg = '' // 错误信息
// 创建dom并挂载
var domStr = '<!--遮罩--><div class="v-modal" tabindex="0" style="z-index:2054;"></div><!--弹窗_start--><div id="elCustomPromptMain" tabindex="-1" role="dialog" class="el-message-box__wrapper" style="z-index:2055;"><!--消息盒子_Start--><div class="el-message-box" id="elCustomPromptMessageBox"><!--顶部title以及关闭按钮--><div class="el-message-box__header"><div class="el-message-box__title"><span>'+title+'</span></div><button type="button" aria-label="Close" class="el-message-box__headerbtn" id="elCustomPromptCloseBtn"><img src="'+deleteImgUrl+'" style="width:16px;height:16px"></button></div><!--内容--><div class="el-message-box__content"><div class="el-message-box__input"><div class="el-input"><input type="text" id="elCustomPromptInput" autocomplete="off" placeholder="'+placeholder+'" class="el-input__inner"></div><div class="el-message-box__errormsg" id="elCustomPromptErrMsgDiv" style="visibility:hidden;">'+errMsg+'</div></div></div><!--底部按钮--><div class="el-message-box__btns"><button type="button" class="el-button el-button--default el-button--small" id="elCustomPromptCancelBtn"><span>取消</span></button><button type="button" class="el-button el-button--default el-button--small el-button--primary" id="elCustomPromptOkBtn" disabled="disabled"><span>确定</span></button></div></div><!--消息盒子_end--></div><!--弹窗_end-->'
var div = document.createElement('div')
div.setAttribute('id', 'elCustomPromptDiv')
div.innerHTML = domStr
document.body.appendChild(div)
// 移除弹窗框
function removeDiv() {
document.body.removeChild(div)
}
// 绑定事件
var elCustomPromptErrMsgDiv = document.getElementById('elCustomPromptErrMsgDiv'),
elCustomPromptCloseBtn = document.getElementById('elCustomPromptCloseBtn'),
elCustomPromptCancelBtn = document.getElementById('elCustomPromptCancelBtn'),
elCustomPromptOkBtn = document.getElementById('elCustomPromptOkBtn'),
elCustomPromptInput = document.getElementById('elCustomPromptInput'),
elCustomPromptMain = document.getElementById('elCustomPromptMain')
elCustomPromptMessageBox = document.getElementById('elCustomPromptMessageBox')
// 关闭弹窗、取消事件
elCustomPromptCloseBtn.onclick = function() {
removeDiv()
}
elCustomPromptCancelBtn.onclick = function() {
removeDiv()
}
// 点击确定后的操作
elCustomPromptOkBtn.onclick = function() {
console.log('点击了确定')
// 再次校验
let tempResult = validateFunc(elCustomPromptInput.value)
if (!tempResult.result) {
elCustomPromptErrMsgDiv.style.visibility = 'visible'
elCustomPromptErrMsgDiv.innerHTML = tempResult.msg
elCustomPromptOkBtn.setAttribute('disabled', 'disabled')
return
}
// 关闭 弹窗,调用callback
removeDiv()
callback(elCustomPromptInput.value)
}
// 输入事件
elCustomPromptInput.oninput = function(e) {
console.log(elCustomPromptInput.value)
// 校验并显示信息
var tempResult = validateFunc(elCustomPromptInput.value)
console.log(tempResult)
if (tempResult.result) {
console.log('成功')
// 校验成功
elCustomPromptErrMsgDiv.style.visibility = 'hidden'
elCustomPromptErrMsgDiv.innerHTML = ''
elCustomPromptOkBtn.removeAttribute('disabled')
} else {
// 校验失败
console.log('失败')
elCustomPromptErrMsgDiv.style.visibility = 'visible'
elCustomPromptErrMsgDiv.innerHTML = tempResult.msg
elCustomPromptOkBtn.setAttribute('disabled', 'disabled')
}
}
// 空白位置点击关闭弹窗
elCustomPromptMain.onclick = function() {
removeDiv()
}
elCustomPromptMessageBox.onclick = function(e) {
event.stopPropagation()
}
}
window.elCustomPrompt = elCustomPrompt
})()
# 点击外部关闭div
一句话总结:用一个父元素(铺满屏幕,绝对布局)包裹该div(绝对布局,水平垂直居中,固定宽高),父元素监听点击事件后移除div,子元素div监听点击后阻止事件冒泡。这样就实现了,点击外部关闭div,点击内部区域不关不div。测试代码:
<body>
<button id="clickme">点击我弹窗对话框</button>
<script>
function showPopup(event) {
let tempHtml = `
<!-- 遮罩 -->
<div class="mask" style="position:absolute;z-index:25555;top:0;bottom:0;width:100%;background:#888;opacity:0.5"></div>
<!-- 内容区域-->
<div id="popup-content-container" class="content-container" style="position:absolute;z-index:25556;top:0;bottom:0;width:100%">
<div id="popup-content-main" class="content-main" style="position:absolute;top:50%;left:50%; transform: translate(-50%, -50%); width:300px;height:200px;background:#fff;border:1px solid #ddd;">
我是弹窗盒子
<button id="closebtn">关闭</button>
</div>
</div>
`
// 创建div
let div = document.createElement('div')
div.setAttribute('id', 'popup-div')
div.innerHTML = tempHtml
// 挂载到dom
document.body.appendChild(div)
// 事件监听
// 关闭弹窗
document.getElementById('closebtn').onclick = function(e) {
document.body.removeChild(div) // 移除元素
}
// 点击外部关闭div 关键代码
document.getElementById('popup-content-container').onclick = function(e) {
document.body.removeChild(div) // 移除元素
}
document.getElementById('popup-content-main').onclick = function(e) {
e.stopPropagation()
}
}
// 简单的弹窗框封装,只为测试点击外部关闭div
document.getElementById('clickme').onclick = (event) => {
showPopup(event)
}
</script>
</body>
# 非箭头函数作为参数时this问题
复习下JS高程3里面将的函数做参数时this的问题,除了bind,也可以使用闭包
var a = 5
function callback() {
console.log('-- callback this', this, this.a, '--')
}
function validate() {
console.log('-- validate this', this, this.a, '--')
}
function showPrompt(title, validate, callback) {
validate()
callback()
}
showPrompt('1', validate, callback) // 5 5
showPrompt('1', validate.bind({a: 2}), callback.bind({a: 1})) // 2 1
或者
var a = 5
var callback = {
a: 1,
handler() {
console.log(this, this.a)
}
}
var validate = {
a: 2,
handler() {
console.log(this, this.a)
}
}
function showPrompt(title, validate, callback) {
validate()
callback()
}
showPrompt('1', validate.handler, callback.handler) // 5 5
showPrompt('1', validate.handler.bind(validate), callback.handler.bind(callback)) // 2 1
使用箭头函数
var a = 5
var callback = {
a: 1,
handler: () => {
console.log(this, this.a)
}
}
var validate = {
a: 2,
handler: () => {
console.log(this, this.a)
}
}
function showPrompt(title, validate, callback) {
validate()
callback()
}
showPrompt('1', validate.handler, callback.handler) // 5 5
showPrompt('1', validate.handler.bind(validate), callback.handler.bind(callback)) // 5 5
# CSS优先级,防止外部样式污染组件
一句话总结:如果不想用!important,那最前面加id,来提高优先级
这复习下之前看HTML权威指南css部分及CSS权威指南里css优先级的问题 https://www.yuque.com/guoqzuo/piylht/dg9u82#4944cc9c
如果两条定义于同一层次的样式都能应用于同一个元素。且都包含同样的属性值,就需要根据特殊性来决定到底使用哪种。 a. 样式的选择器中id值的数目(#) b. 选择器中其他属性和伪类的数目(.class等属性) c. 选择器中元素名和伪元素数目(元素名等)
a的特殊性最高,b其次,c最低。按a-b-c来表示。比如如果a值相等,才会去比较b。1-0-0的特殊性比0-5-5高。在 CSS权特威指南 中,有4位,最高位为内嵌(Inline)样式设置的样式。关于特殊性,建议看CSS权威指南,个人认为比这里要好理解一点。如果层级一样,谁后定义的,优先级就越高。
# 函数命名:validate和verify的区别
参考: https://zhidao.baidu.com/question/486470512.html
- validate 指要付出一段程序化的核实过程。从事物的多个方面来说的,具有充分证据,且已实施,从多个方面论证。
- verify 是一般的检验,检查,倾向于一个动作, 从事情或事物的一个方面来说的,具有证据,且已实施,但只从一个方面实施;
- confirm 则是确认,是从主观判断来说的,可能有一些证据,但未实施
- 其实区别只是在于证实的强度:confirm < verify < validate
# 2019/11/08 周五
# background-repeat与background-position冲突
当设置是background-repeat在y轴重复背景时,background-position设置的顶部开始具体会无效
# position:absolute元素高度自适应
业务场景:
<!--
页面布局:
顶部背景图 // 非透明
中间主内容 // 中间内容也有背景,内容里的title需要有一部分放到top背景区域
底部背景图
-->
<div class="container">
<!-- 顶部背景区域 -->
<section class="top"></section>
<!-- 中间主要内容-->
<section class="main">
<div class="main-title" id="autoHeightTitle">我是标题</div>
<div id="autoMarginTop">产品信息</div>
</section>
<!-- 顶部背景区域-->
<section class="bottom"></section>
</div>
最开始的思路:直接将main-title 设置margin-top: -20px,但这样会导致中间主内容整体上移,覆盖顶部部分内容,然后想到使用background-position属性将中间部分内容背景顶部开始位置设置20px左右,这样margin上去后,部分内容使用的就会是顶部的背景。但中间部分内容又设置了backgroud-repeat属性,导致background-position设置失效。
换个思路,将main-title再用一层div包裹,外层div position设置为relative, main-title设置为position:absolute,这样 top:-20px 即可实现需求,但问题来了。标题如果过长,会分行显示(可能是2行,3行,4行),这样会覆盖下面的产品信息。所以需要知道标题的高度。但标题是position:absolute的,已经脱离的文档流,无法对现有文档布局造成影响。
貌似没有css的解决方法,只能通过dom,计算title高度,然后将产品信息设置对应的margin-top
document.getElementById('autoMarginTop').style.marginTop = document.getElementById('autoHeightTitle').clientHeight - relatvie包裹元素高度 + 'px'
刚了解到了一个解决方法:标题使用 position:relative; top:-10px 就可以了
# 2019/11/07 周四
# svn使用命令拉取更新
svn update
git与svn常用命令对比: https://blog.csdn.net/scythe666/article/details/51941622
svnadmin create ------------------------------> git init
svn co ------------------------------> git clone
svn update ------------------------------> git pull
svn add ------------------------------> git add
svn commit ------------------------------> git add, git commit
svn status ------------------------------> git status
svn switch <branch> ------------------------> git checkout <branch>
svn merge <branch> ------------------------> git merge <branch>
svn revert <file> ------------------------------> git checkout <file>
# 浏览器的断点调试功能使用场景
如果需要看别人的代码,运行异常,业务逻辑复杂的情况,可以加个console.log,打印的log位置,点击文件,进入,就可以在对应的文件下断点了。然后一步步执行,就可以确定问题所在。调试其他人写的复杂逻辑必备,这种情况靠console.log看太麻烦,特别是改动不方便实时更新调试的情况效果更好。
# 使用idea build ant
之前用eclipse build ant ,将war deploy到tomcat的webapps会很慢,后面换成 idea后会很快。
# 2019/11/05 周二
# html2canvas
测试demo地址: https://github.com/zuoxiaobai/fedemo/blob/master/src/DebugDemo/html2canvas/index.html
<!-- 核心代码 -->
<head>
<title>Document</title>
<script src="html2canvas.js"></script>
</head>
<body>
<div id="test" style="background-image: url('bg.jpg');height:707px;width:500px;color: #fff;">
<div style="padding-top:250px;padding-left:100px;">
<h1>邀请函</h1>
<div style="width: 200px;
word-break: break-word;">
你好,邀请你xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
</div>
<p>
--- guoqzuo
</p>
</div>
</div>
<script>
let testElement = document.getElementById('test')
html2canvas(testElement).then(function(canvas) {
console.log(canvas)
let img = new Image()
img.src = canvas.toDataURL()
img.onload = function() {
document.body.appendChild(img);
}
});
</script>
</body>
# JSP注释与普通HTML注释区别
参考:https://www.cnblogs.com/qlqwjy/p/7681035.html
<!-- 这里面的注释在查看页面源代码时,依旧可以看到,另外页面加载时这里面注释的内容仍旧会编译 -->
<%-- JSP中的注释,这里面的内容在查看页面源代码时,看不到这里面注释书写的内容 --%>
所以涉及业务的建议使用<%-- --%>注释,文字描述性的建议使用<!-- -->注释。
# 编写可维护的JS
- 不要做太多骚操作, 尽量可维护,可迭代。不然乍一看写的很NB,再深入看,发现真的比较难维护, 这是不好的。
- 最怕一知半解,以为封装的很好,其实可能还弄复杂了。聪明很重要,如果不聪明,最好找个聪明的人商量、code review,感觉自己智商捉急。
# 更改jsp项目后缓存问题
修改了某个js,重新编译到tomcat的webapps目录下,发现改动一直没有生效。以为改错了,进入编译后的文件目录,检查文件是有改动的,就想到应该是有缓存,浏览器加载过该js文件就缓存了。清下浏览器缓存,改动生效
# 图片格式区别以及webp
jpg、png、bmp、gif图片格式区别,什么是webp?
参考:https://baijiahao.baidu.com/s?id=1599728202992947939&wfr=spider&for=pc
# webp
参考:https://baike.baidu.com/item/webp%E6%A0%BC%E5%BC%8F/4077671?fr=aladdin,https://www.jianshu.com/p/73ca9e8b986a
- 一种同时提供了有损压缩与无损压缩(可逆压缩)的图片文件格式
- 比png更小
- 2010年发布,目标减少文件大小,且达到JPEG格式相同的图片质量,希望可以减少图片在网络上的发送时间
- 由Google在购买On2 Technologies后发展出来,以BSD授权条款发布
# jpeg/jpg (Joint Photographic Experts Group)
- jpeg和jpg格式一样,没有区别。
- 兼容性高、传输速度快,内容小,大部分数码相机都能拍JPEG
- 有损压缩方案,压缩会降低细节和质量
# tiff/tif (Tagged Image File Format)
- 位图,工业标准格式,印刷
# png (Portable Network Graphics)
- 可移植网络图形格式
- 设计目的是试图代替gif何tiff文件格式。
- 支持压缩不失真,透明背景、渐变图像
- 非常适合在网络上使用。但不足以用作印刷
- 能够相容半透明、透明图像,文档比JPEG大
# gif (Graphics Interchange Format)
- gif分为静态和动态两种
- 动态的gif图片是由多张图片保存为一个图片,形成动画效果
- 文档小、非常适合在网络上使用。包容颜色太少
# bmp (Bitmap)
- 位图,文件较大,参考:https://zhidao.baidu.com/question/24130156.html
# vscode插件live server
在html文件编辑区域,右键 => open With live server,可以开启http服务,不需要自己搭建node服务或nginx
# 版本号中的rc是什么意思
参考:什么是 Alpha、Beta、RC、Release版 https://www.cnblogs.com/lanmiao/articles/2184282.html
- Alpha版: 此版本表示该软件在此阶段主要是以实现软件功能为主,通常只在软件开发者内部交流,一般而言,该版本软件的Bug较多,需要继续修改。
- Beta版: 该版本相对于α版已有了很大的改进,消除了严重的错误,但还是存在着一些缺陷,需要经过多次测试来进一步消除,此版本主要的修改对像是软件的UI。
- RC版: 该版本已经相当成熟了,基本上不存在导致错误的BUG,与即将发行的正式版相差无几。
- Release版: 该版本意味“最终版本”,在前面版本的一系列测试版之后,终归会有一个正式版本,是最终交付用户使用的一个版本。该版本有时也称为标准版。一般情况下,Release不会以单词形式出现在软件封面上,取而代之的是符号(R)。
// html2canvas Releases note
v1.0.0-rc.5
v1.0.0-rc.4
…
v1.0.0-rc.0
v1.0.0-alpha.12
…
v1.0.0-alpha.1
v0.5.0-beta4
v0.5.0-beta3
0.5.0-alpha1
v0.4.1 - 7.9.2013
v0.3.3 - 2.3.2012
v0.3.2 - 20.2.2012
0.3.1
v0.3.0 - 7.9.2011
# 2019/11/04 周一
# 路由传参与keep-alive
<keep-alive>
<router-view v-if="$route.meta.iskeepAlive" :key="routeKey">
</keep-alive>
<router-view v-if="!$route.meta.iskeepAlive" :key="routeKey">
# 仅开发环境能看到的路由
let routes = []
// 路由信息仅开发环境可见
if (process.env.NODE_ENV === 'development') {
routes = [
{
path: ‘/xxxx’,
component: () => import(‘xxx’)
}
]
}
export default routes
# mac显示文件扩展名
点击屏幕下方第一个图标:访达(Finder) => 屏幕左上方苹果logo右侧 点击 访达(Finder) => 偏好设置 => 高级 => 勾选显示所有文件扩展名
# 2019/11/01 周五
# JSP相关
- comcat 不用安装,直接到tomcat官网下载core文件,zip 压缩后就直接可以用,bin目录下的文件默认没有可执行权限,需要使用chmod +x bin/* 来修改权限,使用./startup.sh启动tomcat服务,使用./shuntdown.sh来关闭tomcat服务,默认开启端口为8080,可以通过访问 127.0.0.1:8080 看是否有tomcat显示,来判断服务是否已开启。默认访问的是webapps里面的项目,拷贝war包到webapps目录,如果tomcat服务开启,会自动解压缩。config配置文件一般会放到class目录下。
- eclipse 可以配置ant build,debug选项。
# 直接用get方法下载文件
// 没有下载进度,页面不会跳转,没什么反应
var a = '<a display="none" id="download" href="下载链接?拼接参数"><a>'
$("html").append(a)
document.getElementById('download').click()
$('#download').remove()
# 文件下载进度依赖
文件下载进度里会有一个total, loaded字段,total字段依赖于后端response响应头里的Content-length
# README.md文档的重要性
写的逻辑或项目搭建情况,遇到的坑,思路,一定要有markdown,这样后面他人维护会很好维护。不至于耗费大量时间去整理业务逻辑(搬砖),建议存到当前目录的readme.md或者统一存放到docs目录里