把聚焦事件改为点击事件,然后判断禁用状态,如果是禁用状态就取消禁用并聚焦,如果已经聚焦则不做处理
没有足够的数据
hogo呀 回答了问题 · 2020-12-08
把聚焦事件改为点击事件,然后判断禁用状态,如果是禁用状态就取消禁用并聚焦,如果已经聚焦则不做处理
把聚焦事件改为点击事件,然后判断禁用状态,如果是禁用状态就取消禁用并聚焦,如果已经聚焦则不做处理
关注 5 回答 3
hogo呀 发布了文章 · 2020-12-08
主要用于规范自己平时提交代码的格式,避免凌乱难以追溯
类型
- 模块
- 内容
{
add :"新增",
update:"修改",
delete:"删除",
fix:"bug修复",
docs:"文档修改",
refctor:"重构",
perf:"性能优化"
}
主要用于规范自己平时提交代码的格式,避免凌乱难以追溯1.规范内容[x] 组成:类型 - 模块 - 内容[x] 示例:‘add-警报分析-列表增加排序功能’2.规范类型字典 {代码...} 3.规范补充类型不包含但不仅限于(add,update,delete)内容部分尽量不超过20个字符超过一个大的代...
赞 0 收藏 0 评论 0
hogo呀 发布了文章 · 2020-12-07
input或者textarea输入提交时校验是否内容是ipv4或者ipv6格式,多个ip用指定符号隔开
<input type="text" check-ip ng-model="ipValue"></input>
app.directive('checkIp', function () {
return {
restrict: 'A',
require: 'ngModel',
link(scope, ele, attrs, ctrl) {
function ipToArrayHandel(string) {
if (!string) return [];
let splitStr = ',';
let temp = string.trim().split(splitStr);
let result = temp.filter(str => str !== '')
.map(str => str.trim());
return result;
}
function ipValidator(ip) {
if (!ip) return false;
let reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])((\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){3}|(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){5})$/;
let regIpv6 = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/;
let temp = ipToArrayHandel(ip);
let passCheck = false;
//格式校验
for (let i = 0; i < temp.length; i++) {
passCheck = (reg.test(temp[i]) || regIpv6.test(temp[i]));
if (!passCheck) break;
}
//是否重复
passCheck = passCheck && (temp.length === _.uniq(temp).length);
return passCheck;
}
ctrl.$validators.checkIp = function (modelVal, viewVal) {
if(attrs['required']==undefined&&(!viewVal)){
return true
}else{
return ipValidator(viewVal);
}
}
}
}
});
<el-form-item label="ip:" :label-width="formLabelWidth" prop="ip" :rules="[{ required: true, validator:validateIps, trigger: 'blur' }]">
<el-input v-model="ipValue" autocomplete="off"></el-input>
</el-form-item>
validateIps(rule, value, callback) {
let reg = /^((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}$/;
let regIpv6 = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/;
let valdata = value.split(',');
let isCorrect = true;
if (valdata.length) {
for (let i = 0; i < valdata.length; i++) {
if (reg.test(valdata[i]) == false && regIpv6.test(valdata[i]) == false) {
isCorrect = false;
}
}
}
F
if (value == '') {
return callback(new Error('请输入iP地址'));
} else if (!isCorrect) {
callback(new Error('请输入正确对ip地址'));
} else {
callback()
}
}
查看原文场景input或者textarea输入提交时校验是否内容是ipv4或者ipv6格式,多个ip用指定符号隔开angularjs指令实现1.用法 {代码...} 2.源码 {代码...} vuejs指令实现1.用法 {代码...} 2.源码 {代码...}
赞 0 收藏 0 评论 0
hogo呀 发布了文章 · 2020-12-07
app.directive('checkDomainCommon', function () {
return {
restrict: 'A',
require: 'ngModel',
link(scope, ele, attrs, ctrl) {
ctrl.$validators.checkDomainCommon = function (modelVal) {
// reg为域名的正则的正则
let reg =/^[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][--a-zA-Z0-9]{0,62})+\.?/
if (attrs['required'] === undefined || attrs['required'] === false) {
return true
}
else if(!modelVal){
return false;
}else {
//加入输入类型判断,防止错误的将指令绑定在如number类型的输入框上
if(typeof modelVal !== 'string'){
console.error('the type of input value is not string,can not check domain format!');
return false;
}
// 系统中现有用逗号分隔的,和分号分隔的做兼容。都是英文符号
// 中横线隔开的是domain范围,也需要验证是否符合输入规范
let domainArr = attrs['separatorReg']? modelVal.split(new RegExp(attrs['separatorReg'])):modelVal.split(/,|;|-/);
let domain = "";
let isOk = false;
for (let i = 0; i < domainArr.length; i++) {
domain = domainArr[i];
if (reg.test(domain)) {
isOk = true;
} else {
// 只要一个不合符,未通过验证,直接break
isOk = false;
break;
}
}
return isOk;
}
}
}
}
});
import Vue from 'vue'
const domianReg = '';
// 注册一个全局自定义指令 `v-checkDomain`
Vue.directive('checkDomain', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el, binding, vNode) {
el.addEventListener('keyup', function (event) {
// 首先去除已有样式
//removeErrorStyle
// 判断是否是否必填
let isRequired = binding.value.required
if (isRequired) {
if (!el.value || el.value === '') {
//do something with error
}
}
// 判断正则
let regex = binding.value.regex
if (regex === 'IpRegex') {
if (!el.value.match(domainReg)) {
//do something with error
}
} else if (!el.value.match(regex)) {
//do something with error
}
})
}
})
// 注册一个全局自定义指令 `v-checkSubmit`
Vue.directive('checkSubmit', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el, binding, vNode) {
el.addEventListener('click', function (event) {
let elements = document.getElementsByClassName('v-check')
var evObj = document.createEvent('Event')
evObj.initEvent('keyup', true, true)
for (let element of elements) {
element.dispatchEvent(evObj)
}
let errorInputs = document.getElementsByClassName('errorClssDom');
if (errorInputs.length === 0) {
vNode.context.submit();
}
})
}
})
查看原文angularjs实现 {代码...} vue实现 {代码...}
赞 0 收藏 0 评论 0
hogo呀 发布了文章 · 2020-12-04
返回一个去重后的数组,每个值不包含在其他数组参数中。结果值的顺序是由第一个数组中的顺序确定。
_.difference([1,2,3],[3],[1,5])
//==>[2];
difference(array, values, iteratee, comparator) {
var index = -1,
includes = arrayIncludes,
isCommon = true,
length = array.length,
result = [],
valuesLength = values.length;
if (!length) {
return result;
}
if (iteratee) {
values = arrayMap(values, baseUnary(iteratee));
}
if (comparator) {
includes = arrayIncludesWith;
isCommon = false;
}
else if (values.length >= LARGE_ARRAY_SIZE) {
includes = cacheHas;
isCommon = false;
values = new SetCache(values);
}
outer:
while (++index < length) {
var value = array[index],
computed = iteratee ? iteratee(value) : value;
if (isCommon && computed === computed) {
var valuesIndex = valuesLength;
while (valuesIndex--) {
if (values[valuesIndex] === computed) {
continue outer;
}
}
result.push(value);
}
else if (!includes(values, computed, comparator)) {
result.push(value);
}
}
return result;
}
1.核心代码
outer:
while (++index < length) {
var value = array[index],
computed = iteratee ? iteratee(value) : value;
if (isCommon && computed === computed) {
var valuesIndex = valuesLength;
while (valuesIndex--) {
if (values[valuesIndex] === computed) {
continue outer;
}
}
result.push(value);
}
else if (!includes(values, computed, comparator)) {
result.push(value);
}
}
return result;
`思路:`将除array之外的数组参数合并去重,得到values,再使用includes方法,判断array中的元素是否存在于values中,若不存在即将value放进新数组result中,最后返回result。
假设有一需求,重点展示本月在本年没有出现过的新出现的天气类型:
difference(month12,month1,month2.....);
查看原文个人记忆lodash.js->Array->difference用法返回一个去重后的数组,每个值不包含在其他数组参数中。结果值的顺序是由第一个数组中的顺序确定。例子 {代码...} 源码理解 {代码...} 延申 {代码...}
赞 0 收藏 0 评论 0
hogo呀 发布了文章 · 2020-12-03
将数组拆分为等长的若干个新数组组成的二维数组,如果无法被分割成全部都等长的新数组,那么最后剩下的数组元素将组成最后一个数组。
_.chunk([1,2,3,4,5,6],3)
//==>[[1,2,3],[4,5,6]];
//3为等长的长度参数,取消参数则默认长度为1
function chunk(array, size, guard) {
if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) {
size = 1;
} else {
size = nativeMax(toInteger(size), 0);
}
var length = array ? array.length : 0;
if (!length || size < 1) {
return [];
}
var index = 0,
resIndex = 0,
result = Array(nativeCeil(length / size));
while (index < length) {
result[resIndex++] = baseSlice(array, index, (index += size));
}
return result;
}
`guard意思是守卫`
1.直接看核心代码
var index = 0,
resIndex = 0,
result = Array(nativeCeil(length / size));
while (index < length) {
result[resIndex++] = baseSlice(array, index, (index += size));
}
return result;
(a).初始化原数组下标index,新二维数组下标resIndex,新二维数组result,并占位
(b).无限循环剪切index开始,index+size结束的数组元素并填入result,直到末位
Ceil(length/size)从0开始向上取整,完美的得到了新数组的下标
取2数组前三组成新数组
return _.chunk(a,3).concat(_chunk(b,3));
查看原文lodash.js->Array->chunk用法将数组拆分为等长的若干个新数组组成的二维数组,如果无法被分割成全部都等长的新数组,那么最后剩下的数组元素将组成最后一个数组。例子 {代码...} 源码理解 {代码...} 延申 {代码...}
赞 0 收藏 0 评论 0
hogo呀 收藏了文章 · 2020-07-13
回 @bf 同学
本篇文章不是笔记也不是心得,而是关于一个问题的讨论,问题最初出现于https://segmentfault.com/q/1010000005630545?_ea=903562
由于 @bf 同学不方便加QQ/微信,而这个问题又比较大,在问答评论里不好描述清楚,so,趁着周末专门写了一篇文章来回应 @bf 同学
@bf 同学,提到了一个观点:对DOM的修改永远是异步的
当时就震惊到我了(可能技术不达标,少见多怪的缘故,哈哈)
说实话,干了好几年开发,第一次明确地听到有人这样说,根据自己看的书及一些javascript编程经验来说,起初我认为是错误的。
然后看了看 @bf 同学的回复,能自圆其说,还说的头头是道,所以我真的以为对DOM的修改永远是异步的是正确的。然后怀着震惊的心情(因为跟经验相违背),还写了一篇博客记录http://www.liyanshan.com/2016/06/09/%E5%AF%B9DOM%E7%9A%84%E4%BF%AE%E6%94%B9%E6%B0%B8%E8%BF%9C%E9%83%BD%E6%98%AF%E5%BC%82%E6%AD%A5%E7%9A%84/
经过这么些天的发酵和消化,觉得对这个观点又回到了最初的认识(即这个观点是错的)。
还请 @bf 同学跟我多多探讨 !
关于javascript修改dom是异步还是同步的问题:
先来看代码:
<ul>
<li id="i0"></li>
<li id="i1"></li>
<li id="i2"></li>
<li id="i3"></li>
<li id="i4"></li>
</ul>
<ul id="newEle"></ul>
<script>
for(var i = 0;i<5;i++){
var item = document.getElementById('i'+i);
item.innerHTML = i;
}
var newEle = document.getElementById('newEle');
for(i=0;i<5;i++){
var li = document.createElement("li");
li.innerHTML = i;
newEle.appendChild(li);
}
</script>
上述代码的结果完全就是同步的表现,如果是异步的话,毫无疑问,第一个ul下的li每个内容都应该是5,第二个也应该是5。
这是数学中的反证法。即一个命题,哪怕我找出一个特例(何况我能找出很多例子)能推翻这个命题,那么这个命题就不成立。
@bf 同学可能会说了,他也用反证法,比如script标签的加载,来证明DOM修改是异步的
但是这个特例的问题在于:
把下载的异步性当成了DOM修改的异步性
script标签加载是异步的,因为要走网络(比如走网络的ajax和图片下载等都是异步的,当然ajax也可以写成同步的),也就是说,浏览器开了一个线程下载要用的script,但是马上返回(交给HTTP请求线程就不管了,请求结束,请求线程会把结果放入事件队列里),接着执行或下载其他部分。其实这个问题我在引起这个讨论的问题上已经回答了(可能回答的没有那么清楚)。
然后又陆陆续续地看了一些书,查了一些资料,问了一些大牛,越来越坚信DOM修改是同步的
JavaScript异步编程第一章 - 异步的I/O函数(1.2.1)
这个也符合我最初跟 @bf 同学的解释:修改DOM是同步的,但是渲染是异步的。因为JavaScript引擎线程跟GUI渲染线程是互斥的,即我执行的时候,你就靠边站,我执行完你才能执行
详见我2014年写的一篇关于异步的文章(当时就是记录一下心得与笔记,也不会自己搭博客,也不会MD,所以请 @bf 同学凑合看)http://blog.sina.com.cn/s/blog_6fd55a970102v64x.html
在群里提问
这个其实就相当于回答了js是同步修改的。。因为这是三个异步函数!
而 @bf 同学在后面的回复中,提到了一篇文章https://leozdgao.me/why-dom-slow/,额,我看了看这篇文章,发现其实我今年年初就看过了,当时貌似是用浏览器重排和重绘
搜索到的。。
这篇文章主要是讲 重排和重绘及性能优化一类的知识。
@bf 同学可能受到这句话的影响:
一般情况下,浏览器的layout是lazy的,也就是说:在js脚本执行时,是不会去更新DOM的,任何对DOM的修改都会被暂存在一个队列中,在当前js的执行上下文完成执行后,会根据这个队列中的修改,进行一次layout。
这个其实说明不了修改DOM永远是异步的,这个是JavaScript引擎实现层面上的知识,是对js修改DOM的优化,它放入的队列其实不是事件队列
,如果放到了事件队列
中,才是异步的。。C++实现一个队列是何其简单啊!js实现队列更简单!只是实现层面的东西,对程序猿都是透明的。。所以没啥可说的。只能帮助我们理解重排和重绘的机制,而不能得出修改DOM永远是异步的结论。。
回 @bf 同学 本篇文章不是笔记也不是心得,而是关于一个问题的讨论,问题最初出现于[链接] 由于 @bf 同学不方便加QQ/微信,而这个问题又比较大,在问答评论里不好描述清楚,so,趁着周末专门写了一篇文章来回应 @bf 同学 @bf 同学,提到了一个观点:对DOM的修改永远...
hogo呀 回答了问题 · 2020-07-13
DOM结构的修改是同步完成的,dom的实际效果修改或者说渲染是异步的,个人认为是同步js代码执行完毕和异步队列执行之前的中间段进行更新
DOM结构的修改是同步完成的,dom的实际效果修改或者说渲染是异步的,个人认为是同步js代码执行完毕和异步队列执行之前的中间段进行更新
关注 6 回答 3
hogo呀 回答了问题 · 2020-05-14
请问你解决了吗,我也遇到相同的问题
请问你解决了吗,我也遇到相同的问题
关注 2 回答 2
查看全部 个人动态 →
(゚∀゚ )
暂时没有
注册于 2017-08-07
个人主页被 2.1k 人浏览
推荐关注