Coder Social home page Coder Social logo

blog's Introduction

@IT·平头哥联盟 {docsify-ignore-all}

  • 前端:html、css、javascript、canvas、小程序、react/vue等系列;
  • 测试:自动化、性能、接口系列;
  • 公众号honeyBadger8内推工作福利🔥
  • 资源912594095-[资源获取/交流群],文章对应示例源码的获取、小白入门前端/测试疑惑等。文章源码获取👈

@IT·平头哥联盟专注于分享前端、测试 等领域的积累,文章来源于(自己/群友)工作中积累的经验、填过的坑,希望能尽绵薄之力 助其他同学少走一些弯路;
-如果您有故事 我必备好小酒扫塌相迎,投稿请 [查看规则]!
-如果您是前端/测试小白、新人、或想了解这个领域,同样也欢迎加入我们,我们将倾尽全力,为您释疑解惑!

名字的由来

  • 蜜獾(huan),绰号 平头哥 被称为最无所畏惧的动物;
  • 它的个性:哥的一生不是在打架,就是在去打架的路上。管你是谁,生死看淡不服就干;
  • 当下社会过于浮躁和虚假,我们敬畏这种(人/动物),虽说[自古深情留不住,唯有套路得人心],但我们还是期望人与人之间,少一些欺骗/套路,多一点真诚,任何事都坦然面对,拥抱变化、不惧未来。
  • 重点:文章源码获取 👈 👈

最新内容

热门推荐

公众号 - 推荐👇

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8

专栏

前端/测试
CSDN技术社区
@IT·平头哥联盟-segmentfault专栏
@IT·平头哥联盟-知乎专栏
@IT·平头哥联盟-简书
@IT·平头哥联盟-头条号
掘金主页
开源**
博客园

欢迎持续关注,拼命编写中~😂

blog's People

Contributors

cchah avatar hejinze789 avatar meibin08 avatar p3t3r-z avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

blog's Issues

个税革新,你每年能省多少钱~

IT平头哥联盟程序员,首席填坑官∙苏南的专栏 前端css面试题?从入门到真实项目配置,首席填坑官∙苏南的专栏,前端开发面试题之CSS,纳税人赡养60岁(含)以上父母以及其他法定,赡养人的赡养支出,也就是说60岁以下的即不能享受到该专项扣除,小程序项目如何设置资源的防盗链?从入门到真实项目配置,首席填坑官∙苏南的专栏

  看大家这些天都在群里讨论,2019年1月1日起个税免征额调整政策之后,关于自己每月能拿多少钱的问题,大家都很疑惑,于是整理了一些资料,下面我们来看看如何操作以及具体能给自己带来多少收益呢?

专项扣除有哪些?

  • 赡养老人
  • 子女教育
  • 继续教育
  • 住房租金
  • 住房贷款利息
  • 大病医疗

主要有以上6项日常支出可以享受到专项扣除,接下来会详细讲一下每一项是如何操作的。

赡养老人

纳税人赡养60岁(含)以上父母以及其他法定,赡养人的赡养支出,也就是说60岁以下的即不能享受到该专项扣除。

定额扣除标准
• 独生子女--每月2000元的标准定额扣除

• 非独生子女--应与兄弟姐妹分摊(均摊、约定、指定分摊),每人分摊的额度不能超过每月1000元

备查资料:采取约定或指定分摊的,需留存分摊协议。

注意:分摊方式和额度确定后,一个纳税年度不变。

子女教育

很明显了,这个就是针对单身狗、以及那些不以结婚为目的去谈恋爱耍流氓的人。

纳税人子女

• 学前教育和学历教育支出;

• 定额扣除--标准:每个子女每年12000元(每月1000元);

• 可以由父母一方全额扣除,也可以父母分别扣除50%;

• 扣除方式确定后,一个纳税年度内不能变更。

解释一下:

~ 学前教育:子女年满3周岁的当月至小学入学前一月,也就是说子女上幼儿园的费用也能享受这一优惠了;

~ 学历教育:

  1) 义务教育(小学和初中教育);

  2) 高中阶段教育(普通高中/中等职业教育);

  3) 高等教育(大学专科、大学本科、硕士、研究生、博士研究生教育)- 全日制学历

备查资料

• 境内接受教育:不需要特别留存资料;

• 境外接受教育:境外学校录取通知书、留学签证等相关教育资料

继续教育

例外:如果子女已就业,且正在接受本科以下学历继续教育,可以由父母选择按照子女教育扣除,也可以由子女本人选择按照继续教育扣除。

定额扣除标准

• 1)学历(学位)继续教育:定额扣除标准:每月400元

• 2)职业资格继续教育:技能人员职业资格继续教育、专业技术人员职业资格继续教育 定额扣除标准每年3600元

• 备注:职业资格具体范围,以人力资源社会保障部公布的国家职业资格目录为准,同时个人兴趣爱好培训不再抵扣范围内

说明:

• 学历(学位)继续教育:入学的当月至教育结束的当月(<48个月);

• 职业资格继续教育:取得相关职业资格继续教育证书上载明的发证(批准)日期的所属年度。

备查资料:职业资格继续教育:技能人员、专业技术人员职业资格证书等

住房贷款利息

这个还是比较容易的理解的买房了,不是全款的就可以,每月有银行的流水证明,还是比较简单的;

定额扣除标准

• 纳税人本人或配偶使用商业银行或住房公积金个人住房贷款为本人或其配偶购买住房,发生的首套住房贷款利息支出

• 在偿还贷款期间 ,全款的是不是哭晕在厕所??哈哈~


说明:

• 贷款合同约定开始还款的当月至贷款全部归还或贷款合同终止的当月

• 扣除期限最长不得超过240个月。

备查资料:住房贷款合同,贷款还款支出凭证等 也就是前面说的银行还款流水。

注意:每月1000元,扣除期限最长不超过240个月,扣除人--夫妻双方约定,可由其中一方扣除,确定后,一个纳税年度内不得更改。

住房租金

其实这一项,个人觉得可能会导致房东涨房租,真正到最后钱可能落不到我们口袋里来……

定额扣除标准

• 直辖市、省会(首府)城市、计划单列市以及国务院确定的其他城市:每月1500元;

• 市辖区户籍人口超过100万人的城市:每月1100元;

• 市辖区户籍人口不超过100万人(含)的城市:每月800元。

谁来扣、扣谁的?:

1)夫妻双方主要工作城市相同:只能由一方扣除,且为签订租赁住房合同的承租人来扣除;

2)夫妻双方主要工作城市不同,且无房的,可按规定标准分别进行扣除。

备查资料:住房租赁合同或协议等。

注意:本人及配偶在主要工作的城市没有自有住房,已经实际发生了住房租金支出,本人及配偶在同一纳税年度内,没有享受住房贷款利息专项附加扣除政策。

大病医疗

生病感冒,这些是每个人都避免不了的,不得不说,这项真的实实在在帮大家省钱了,当然能不生病那自然是最好~

定额扣除标准

• 一个纳税年度内,在社会医疗保险管理信息系统记录的(包括医保目录范围内的自付部分和医保目录范围外的自费部分)

• 由个人负担超过15000元的医药费用支出部分,为大病医疗支出,可以按照每年80000元标准限额据实扣除。

备查资料:患者医药服务收费及医保报销相关票据原件或复印件,医疗保障部门出具的医药费用清单等。


注意:医保目录范围内的医药费用支出,医保报销后的个人自付部分;累计超过15000元的部分,且不超过80000元的部分。

小结:以上为6项专项扣除的详细说明,已经很详细了吧?有没有帮助你多了解那么一点点呢??再补个图吧:

扣除限额 享受条件 期限 抵扣方 备查资料
赡养老人 2000元/月
(独生)
赡养60岁及以
上老人
被赡养人60岁
当月起
独生-子/女
非独-子女分摊
分摊协议
(非独)
子女教育 1000元/月 3周岁以上
子女
年满3岁至
博士
父母一方/
双方均摊
就读境外院校:
录取通知书,留学签证等
继续教育 400元/月
3600元/年
学历(学位)
/职业资格继续教育
学历:<48个月
取得职业资格证书当年
纳税人本人 技能人员/专
业技术人员资格证书
住房租金 1)1500元/月
2)1100元/月 3) 800 元/月
主要工作城市
无自住房;未享受住房贷款利息扣减
租赁行为实际
起止
夫妻一方/
承租人本人
租赁合同
住房贷款利息 1000元/月 首套房贷款
利息
240个月内 夫妻一方/
贷款人本人
贷款合同
贷款还款支出凭证等
大病医疗 80000元/年
(上限)
自付超过1.5
万元部分
每个自然年
结算
纳税人本
医保报销单
据等

新法个税预扣预缴说明

扣税容易,减税难啊,专项附加扣除并不能直接减免个人所得税,而是要代入所得税计算公式,最后得到的数才是个人需要缴纳的税额;应纳税所得额计算公式如下:

新法改个重点:采用累积预扣预交方式申报个税

本期应预扣预缴税额 =(累计预扣预缴应纳税所得额×预扣率-速算扣除数)-累计减免税额-累计已预扣预缴税额

累计预扣预缴应纳税所得额=累计收入-累计免税收入-累计减除费用-累计专项扣除-累计专项附加扣除-累计依法确定的其他扣除

是不是看着很晕???~~,其实我也晕~,为了钱,接着看吧,来个例子,看看到底能省多少钱?

举例说明

假设屌丝程序员,赡养老人(60岁以上),有孩子(3岁以上)目前正在偿还首套房贷,月收入25000,每月社保公积金扣减4375,(接受继续学历教育)不考虑其他因素每月可享受各项专
项附加抵扣总额4400,收入和个税计算如下:

专项附加抵扣和个税申报方式

  • 单位代扣
  • 个人申报

专项附加抵扣和个税申报方式

最最最最重要的问题来了,怎么把这个扣掉的钱拿回来~

  • 手机端:个人所得税APP,扫描二维码或者通过应用市场,搜索“个人所得税”下载(国家税务总局开发)

  • 网页端:网页输入网址登陆办税平台
    地址:https://its.tax.sh.gov.cn/

  • 线下
    纸质表格
    • 税务局柜台领取
    • 联系HR领取
    电子表格
    • 自然人办税平台下载打印
    • 联系HR处领取

尾声:

最后一种方式,估计这个没有人愿意跑了,跑你个10次、8次的,一月工资都没有了,不用申请了~

以上汇总整理,希望能帮你进一步了解抵扣个税的各项细节,如觉得不错,请记得右下角给个好看哦。

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:IT平头哥联盟

热门推荐:

作者:苏南 - 首席填坑官

链接:http://susouth.com/

交流:912594095、公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

动画一点点—玩转3D Swiper性感秀之思路分析总结

玩转3D Swiper性感秀之思路分析总结

前言

  继一次的3D魔方之后,这次带你一起玩转性感美女秀,正常套路,请先一堵为快,有兴趣继续,没兴趣也可以看看美女养眼哦🤪!想直接在线预览 👈

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

回顾:

  看过上次的3D魔方的同学对于本次的分析会有一定的帮助,当然如果大佬您本身就对css3就已经玩的很666了,那么对于下文的分解就请扮演老师的角色吧,小弟如有不足之处,欢迎斧正。

解析:

创建列DIV :
  • 从上图中我们能看出,每次旋转的动画是由多列小卡片组成的;
  • 每列根据它的下标,对背景进行位移,做到拼接的效果,整体看起来就成了一张图
  • 一起来看一下真像是啥样的:

旋转的动画是由多列小卡片组成

colNode(){
    //生成列的节点
    for (var i=0;i<this.colLen;i++){
        let iDivCol = document.createElement('div'); //列
        iDivCol.className = "div-col";
        iDivCol.style.width = this.colW+'px';
        iDivCol.style.height = this.cubeH+'px';
        iDivCol.style.zIndex = (i>this.colLen/2?this.colLen-i:i);
        this.swiperEle.appendChild(iDivCol);
    }
}
立体感的构成 :
  • 旋转的立体感是如何构成的呢?
  • 原理其实很简单,可以理解成每列都是一个立体魔方,它们都是相互独立的,
  • 每列 backgroundPosition:index*xcolW,进行一个位移,
  • 简单来说,即每列内部都有6个面组成,每个面都以父级为目标进行 position、transform等设置,
  • 一张图,让你看懂全世界:—— 图五为完成输出

单列的构成

//——[正、上、左、右]
for(var i = 0;i<4;i++){
    let dividingLine = i<2;
    let span = document.createElement('span');
    span.className = `${dividingLine?'bg-img':'pure-color'} i${i}`;
    span.style.width = `${dividingLine? this.colW:this.cubeH}px`;
    span.style.height = this.cubeH+'px';
    if(dividingLine){
        span.style.backgroundPosition = `-${index*this.colW}px 0`;
    };
    iDivCol.appendChild(span);
};
单列的布局结构 :
  • colNode方法中的 zIndex,需要注意一下,层级的调整,可以覆盖立体透视造成的影响,
  • 单列的html布局及重点样式,

Zindex的重要性
transform 等角投影

 /*四个面的样式*/
 ...省略N行
.div-col span.i1{
    /*top*/
    transform-origin:top;
    transform:translateZ(-360px) rotateX(90deg);
}
.div-col span.i2{
    /*left*/
    transform-origin: left;
    transform: rotateY(90deg);
}
.div-col span.i3{
    /*right*/
    transform-origin:left;
    transform:translateX(25px) rotateY(90deg);
}

单列的html布局及重点样式

切换 :
  • 布局完成后,我们只需要操控系列[div-col]来进行旋转即可,
  • 下图为 transform-origin:50% 50% -180px,即设置旋转的中心点:

单列的鼠标经过

  • 鼠标经过都实现了,上下页切换还远吗?
  • 之前创建结构的时候,我们已知div的列数,
  • 为了更好的装B,我们在旋转的时候,给每列都要添加一定延时setTimeout,得以达到缓冲的视差,
  • 然后requestAnimationFrame就该它出场了,setInterval已经成为过去式,
  • 同时旋转前,还要设置下一页,要显示的图片,
  • 当然记得旋转完成,后要重置角度哦。

javascript,3D旋转
javascript,3D旋转缓冲效果

...省略N行
swiperAnimate(){
    const _requestAnimationFrame_ = window.requestAnimationFrame||window.WebkitRequestAnimationFrame;
    const iDivCol = this.swiperEle.querySelectorAll(".div-col");
    for(var i=0;i<iDivCol.length;i++){
        //让动画更逼真,给个过渡,当然也可以调整,requestAnimationFrame每次递增的值,
        iDivCol[i].style.WebkitTransition=`.8s -webkit-transform ease`;
        iDivCol[i].style.WebkitTransformOrigin=iDivCol[i].style.transformOrigin = "50% 50% -180px";
        this.animateMove(iDivCol[i],i,_requestAnimationFrame_);
    }
}
animateMove(Col,index,animationFrame){

    let ColNum =0;
    let spanSurface =  Col.querySelectorAll("span");
    //即将旋转到的面,展示的图片
    spanSurface[1].style.backgroundImage="url(./2.jpg)";
    setTimeout(()=>{
        //每列进行一个延时,以达到缓冲效果
        this.rotate(Col,0,spanSurface,animationFrame);

    },index*this.delayMilli);
}
...省略N行
上下翻页 :
  • 上面基本已实现了旋转的效果,再加一些修饰,
  • 上下点击切换的功能,注意的地方在于,防止重复点击,当前旋转中时不能点:
pageDown(){
    if(this.status){
        console.log("下翻,不能点击")
        return ;
    };
    this.status = 1;
    this.pageNum = this.pageNum>=this.imageList.length ? 1 :++this.pageNum;
    this.swiperAnimate();
}

javascript,3D旋转

预加载 :
  • 因轮播图图片较多,且此示例的图片每次只加载了两张,故要对图片进行一个预加载,
  • 以及图片加载出错后的过滤,避免影响后续效果的呈现:
preloadingImage(){
    this.imageList.map((k,v)=>{
        let imgNode = new Image();
        imgNode.onerror=err=>{
            this.imageList.splice(v,1);
        }
        imgNode.src = k;
    });
}

javascript,图片加载出错后的过滤

总结:

  一个效果实现的方式有很多种,比如我们可以设置6个面,每设置一次,都是展示一张图,这样就不用每次旋转完后又去重置图片、角度等问题,包括requestAnimationFrame动画切换的过渡过程,也应该有更好的方式,新手上路中,欢迎各位大佬指点。以上就是今天为您带来的分享,你GET到了吗?如果觉得不错,记得给个赞哦,想第一时间获得最新分享,欢迎扫码关注我的个人公众号:honeyBadger8,👇!

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8

作者:苏南 - 首席填坑官

来源:@IT·平头哥联盟

链接:https://blog.csdn.net/weixin_43254766

交流:912594095、公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

女生对不喜欢的男生到底有多残忍?- 周五非技术

女生对不喜欢的男生到底有多残忍?- 周五

2018 年面对众多前端新技术,该如何学习? 小程序项目如何设置资源的防盗链?从入门到真实项目配置,首席填坑官∙苏南的专栏

又到周五,轻松一刻时间,

读本本文约预计需要3.6分钟,

如果戳到你的痛点,时间未知~

女生对不喜欢的男生到底有多残忍?

网友:因为不爱 所以都错

IT平头哥联盟 首席填坑官∙苏南的专栏 交流:912594095,掘金是一个帮助开发者成长的社区,是给开发者用的Hacker News,给设计师用的Designer News,和给产品经理用,我眼中都看不见我不喜欢的男生的,你说有多残忍。
会把你对她的好,当笑话给别人说,聊天记录在闺蜜之间传阅,被安排的明明白白的。
残忍是应该的,不喜欢就是不喜欢,拖着反倒显得自己渣,但表达拒绝的方式一定要注意,这年头变态太多了,表白不成遭杀的事件也时常发生。
不成全他也不放过他。IT平头哥联盟 首席填坑官∙苏南的专栏 交流:912594095
对你说:我暂时还不想谈恋爱。(其实她想表达的是:不想和你谈)
无意识的撩,撩完就跑,不负责任的那种。
对你的暗示或者表白装糊涂
觉得他就像一条小狗,我开心有人陪的时候根本不会想到你,失落的时候又觉得有你真好,无聊的时摸摸你的头也能把你逗笑。有时候觉得你很可怜想对你好点,有时候觉得你是个累赘会嫌你很烦,唯一不变的就是我真的觉得他好像一条小狗。
完全没兴趣,不想和他聊天,特别不喜欢他表白心意的话,并不感动,特别反感。不希望他有什么更亲近的话或行为,特别痛苦,真的讨厌。IT平头哥联盟 首席填坑官∙苏南的专栏 交流:912594095,
我感觉女生天生就有第六感,这个男生对我是不是真心的,我都能感觉到,不是讨厌别人喜欢我,第一,讨厌那些死缠烂打的, 并且我已经明确拒绝的那种,第二,我感觉不到他的喜欢,但是他还觉得他特别喜欢我,在我面前恶心我!第一种还好,特别是第二种,把女生当傻子,装情圣!IT平头哥联盟 首席填坑官∙苏南的专栏 交流:912594095,
看到他发的消息,看都不想看。他对我的任何好会更让发自内心的厌恶。奉劝各位不管男还是女, 知道对方是没有可能的,请立刻放弃,别一味的放弃自尊的纠缠,给人添负担,别逼一个善良的人变得残忍!
大概就是,你们十年同窗,青梅竹马,你什么都为她做,但她对你就是什么都行,唯独无关爱情,唯一一次的告白被她拒绝说再逾矩连朋友都没得做。
坚持3不原则:不主动、不拒绝、不负责;贯彻实现4全指示精神:付出全当应该的、温暖全当多余的、吃醋全当无所谓的、推进关系全当听不见的。

网友说:

记得自己有点儿明白事理的时候,妈妈说过:“这个世界不是有人有义务对你好,所以长大了如果有男孩喜欢你而你没办法回馈他时,你至少应该感谢他对你平白无故的喜爱,坚定并以保护好自己的提前去拒绝他,不要恶语相向,若干年后想起你或许还能是个美好回忆”。

~~

码农书籍,一起阅读,一起进步,用心分享 做有温度的攻城狮,苏南的专栏

以上为本周五 IT平头哥联盟 为你带来的轻松一刻,今天不求你笑、但求别哭~,

如果你喜欢的话,欢迎点赞、关注(IT平头哥联盟),

分享给你的好友们就更棒了,谢谢支持~

其他

作者:苏南 - 首席填坑官

链接:http://susouth.com/

交流:912594095、公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

小程序项目之填坑小记

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

作者:首席填坑官∙苏南
公众号:honeyBadger8,本文原创,著作权归作者所有,转载请注明原链接及出处。

简诉

  是的,真的,你没有看错,我就是上次那个加薪的,但是现在问题来了,最近又搞了个小程序的需求,又填了不少坑,其中的辛酸就不说了,说多了都是泪🤪😭,此处省略三千字 ………^……,说重点吧,反正最后就是差点这让老板叫走人了,你说优秀不优秀~。

  前段时间网上一直说的“你可以骂那些中年人,尤其是有车有房的……”,虽然我没有房、也没有车,但也坚决不做那个可以随便骂的中年人(人到中年不如狗??),不存在的啦,这个仇宝宝已经记下了🤫,先分享一下最近遇到的几个坑吧。 —— 我是首席填坑官——苏南,早上好,新的一周加油。

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

填坑一,canvas遮挡问题:

  • 随着小程序的API调整,很多东西都要用户手动授权,不能直接调用后,toast、弹窗这种提示的场景越来越多了,
  • 下图就是公司活动的canvas合成,现在微信API不让直接调用授权了,某些场景要多一个弹窗来提示用户开启设置,但当遇上canvas API这个大佬后,一切都变了,谁都只能站在它后面,
  • 场景一 :如之前拒绝授权了,后续引导用户打开设置页,即 wx.openSetting,下图就是:

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

坑一 小结 :当遇上这种情况,我的第一思路是 设置样式:visibility: hidden;opacity:0;,但是结果是让人失望的,canvas 大佬就是大佬,这两属性在手机上失效了,该显示还是显示,你阻挡不了它的光辉,真的,不信可以去测试!

解决思路:
  • canvas 图片合成,获取到图片的地址后,隐藏canvas,改用image标签显示,这种场景有局限性,如果你的需求是echart交互的,显示挂了;
  • cover-view 貌似也是有局限,<cover-view /> 内只能嵌套 <cover-view /> 和 <cover-image />,view 标签的子节点树在真机上都会被忽略,这是我测试后的浏览器给出的警告,如果自定modal,要加button按钮让用户点击后授权某功能,肯定也就挂了 ;
  • 当弹窗出现的时候,隐藏canvas,这种比较暴力,但覆盖面广,任何场景都能照顾到,却也影响体验;
  • canvas定位移动到屏幕之外绘制内容;
  • 有同学可能说直接使用原生的 wx.showModal,但官方目前,button还不支持设置open-type属性;
  • 微信小程序官方修复😫,好吧,看到这里你肯定笑了~,这不是一个方法,估计还没等到老板真叫你走人了,欢迎大佬们补充!!!

填坑二,Maximum call stack size exceeded

  • 发现这个bug,要从最近换了个手机说起,用了3年的5S终于歇菜了(再也买不起iphone了~),换了个android vivo x23, 以为从此走上人生巅峰了,现实却给了我一个响亮的耳光,又是一个记忆深刻的梗~,被组里的同事笑话好久!!
  • 话说,堆栈溢出,是怎么造成的呢?—— 循环引用
  • 同时我又有些疑惑了,为什么其他手机都正常,就vivo 报了这个错,同样的代码,希望有大神看到能给于解惑!
  • 先来看个示例,简单演示一下
let sum = 20;
    (function test(){
        sum--;
        console.log(sum);
        test();
        /*
        if( sum > 0 ){
            test();
        }*/
    })()

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

  • ** # 而项目中的报错是这样的 # **:
    //fetch.js
    import wepy from 'wepy'
    import _login_ from './login';
    ……省略N行

    //login.js
    import {fetch} from "./fetch.js";
    import Storage from "./storage.js";
    ……省略N行

    //更改后 login.js ,避免了循环引用
    loginFn = ()=>{
        require("./fetch.js").fetch({
            url:"/wabApi/login/login",

        });
    }

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

坑二 小结 :循环引用,可以理解为 a.js内调用了b.js,b.js里又引用了a.js,所以在项目开发中要注意一下,看了下网上的讨论,这个问题需要等官方解决,貌似h5里是可以这样写的。

填坑三,canvasGetImageData、canvasToTempFilePath

  • 这两个方法,之间的调用,要做一定的延时,不明白是为什么,如果不做延时,也不会报错,也不提示,方法执行完,canvas上还是空白的;
  • 但是让人尴尬的是,此在写总结的我,又验证了一下,不加setTimeout,调试器上可以,真机挂了!目测跟绘制的目标对象大小有关系!

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

其他

  • 微信API的调整,如:「 wx.getUserInfo」「 wx.getSetting」「 wx.openSetting」「 wx.getPhoneNumber」等这些现在需要添加按钮,用户手动来点击,带来的不便大家都知道了,就不再多说;
  • 字体文件 ,加载报错,但也能正常显示,而且只有第一次报错哦;
  • 其他还有待发现的坑……
    @font-face {
      font-family: 'test';
      src: url("https://cdn-xx.xxx.com/common/font/font.ttf") format('truetype');
      font-weight: normal;
      font-style: normal;
    }

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

扯淡段子

  小明公司之前上线的小程序项目,好久没有迭代了,产品说有个需求要改一下,很快,就一点点东西,比如一个按钮UI调整一下,改了赶紧发上去,嗯,最好今天就发了审核吧;

  这话,是你会怎么接呢??小明说要一天,产品就惊呆了🤒,这家伙没有发烧吧??小明后来经过半天的努力,终于让产品知道了小程序API更新后,再发布的相关流程都要改的;

  有谁能理解小明的痛苦?有谁能理解小程序的API更新机制?更新过的API没有向下兼容的余地,已经发布过的就放过你了,但是你再改动,所有它改过的流程,你都要改一遍。

结尾

  开心一笑,给自己找点乐,为今天的分享画上圆满的句号,以上就是我最近的一次小小填坑记整理,希望能给其他同学带来些许帮助,文中如有理解不足之处,请指正👇。

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8

作者:苏南 - 首席填坑官

链接:https://blog.csdn.net/weixin_43254766

交流群:912594095、公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

该如何正确的使用SVG Sprites?

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享

前言

  大家好,这里是@IT·平头哥联盟,我是首席填坑官——苏南(South·Su),今天要给大家分享的是SVG Sprites(也叫雪碧图),所谓雪碧图,当然就不是我们常喝的雪碧饮料(Sprites)哦,哈哈~

  当下流程的移动端,手机型号太多太多,今天工作项目中突然发现还有同事在使用以前大家 曾经包括现在还很熟悉的CSS 图片精灵,被我们的测试MM找来说图片在iphone6、iphone plus、iphone x等大屏的手机全糊了,当时我就懵逼了,我说怎么会呢,后面一看,果然如此啊,看了下代码,原来是用的图片,我说为什么不用svg呢??然后同事说一个一个的图标好麻烦,我说可以用svg sprite啊,~~>﹏<,这个时候轮到同事一脸懵逼了……,所以想着可能是不是同样还有很多同学也不知道SVG symbols呢,那么这就给大家分享一下:

正式开讲

  SVG英文全称为( Scalable Vector Graphics),意思为可缩放的矢量图形。它是基于XML(Extensible Markup Language),由World Wide Web Consortium(W3C)联盟进行开发的。严格来说应该是一种开放标准的矢量图形语言,可让你设计激动人心的、高分辨率的Web图形页面,SVG是一种采用XML 来描述二维图形的语言,**那么symbol元素是什么呢?**单纯翻译的话,是“符号”的意思,然我的理解是symbol元素用来定义一个图形模板对象,它可以用一个元素实例化。symbol元素对图形的作用是在同一文档中多次使用,添加结构和语义,SVG是无论如何放大缩小都不会糊,而图片当展示的尺寸大于图片本身,就会糊了,糊了,糊了……

1.1 回顾 Css Sprites

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

<div class="icon-sprite"></div>
.icon-sprite {
    width: 45px;
    height: 45px;
    background-image: url(https://github.com/meibin08/img/sprite_icon.png);
    background-size: 100px 350px;
    background-position: 0 -60px;//**重点在于它**
    background-repeat: no-repeat;
}

  在以前我们为了性能优化,多图标合在一张图上面,然后再使用css的 background-position来定位, 好处是减少了页面的加载,要命的问题是定位遇到兼容问题,1px、.5px偏差时,搞的你死去活来,后来移动端更是不清晰,被人骂了又骂。

本文由@IT·平头哥联盟-首席填坑官∙苏南分享
本文由@IT·平头哥联盟-首席填坑官∙苏南分享

1.2 展望 Svg Sprites

  当后来有一天,在一个月黑风高、暴雨倾盆、雷电交加的夜晚,我独自一人漫步在一片小树林里,后来我发现了新大陆————SVG,当然如果仅仅svg就我也就不会拿出来吹水,因为肯定是会被人喷的一脸口水的,但是如果再加上它的小弟——symbols? SVG symbols、SVG symbols、SVG symbols 重要的事说三遍不过份吧,双重组合(屠龙、倚天)试问天下谁敢它争锋?特别是SVG它还下面还有很多小弟哦~,……有点扯远了;这项技术基于两个元素的使用:<symbol><use>

  • 从ps或者Illustrator创建并导出SVG图标,源码大概是这样的:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1024 1024"> 
    <path style="fill-rule: evenodd;" d="M941.714 512q0 143.433-83.712 258.011t-216.283 158.574q-15.433 2.853-22.565-3.986t-7.131-17.152v-120.576q0-55.442-29.696-81.152 32.585-3.438 58.587-10.277t53.723-22.272 46.299-37.998 30.281-60.014 11.703-86.016q0-69.157-45.129-117.723 21.138-52.005-4.571-116.553-16.018-5.157-46.299 6.29t-52.553 25.161l-21.723 13.714q-53.138-14.848-109.714-14.848t-109.714 14.848q-9.143-6.29-24.283-15.433t-47.726-22.016-49.152-7.717q-25.161 64.585-3.986 116.553-45.129 48.567-45.129 117.723 0 48.567 11.703 85.723t29.989 60.014 46.007 38.29 53.723 22.272 58.587 10.277q-22.857 20.553-28.014 58.843-11.995 5.705-25.71 8.558t-32.585 2.853-37.413-12.288-31.707-35.73q-10.862-18.286-27.721-29.696t-28.27-13.714l-11.447-1.719q-11.995 0-16.567 2.56t-2.853 6.583 5.157 8.009 7.424 6.839l3.986 2.853q12.581 5.705 24.869 21.723t17.993 29.147l5.705 13.129q7.424 21.723 25.161 35.145t38.29 17.152 39.717 3.986 31.707-2.011l13.129-2.304q0 21.723 0.293 50.871t0.293 30.866q0 10.277-7.424 17.152t-22.857 3.986q-132.571-43.995-216.283-158.574t-83.712-258.011q0-119.442 58.843-220.27t159.707-159.707 220.27-58.843 220.27 58.843 159.707 159.707 58.843 220.27z" p-id="3347" />
</svg>

  • 重点来了,那么我们用symbols包装后是这个样子的:
<svg xmlns="http://www.w3.org/2000/svg">
  <symbol id="svg-github"  viewBox="0 0 1024 1024">
    <title>github</title>
    <path style="fill-rule: evenodd;" d="M941.714 512q0 143.433-83.712 258.011t-216.283 158.574q-15.433 2.853-22.565-3.986t-7.131-17.152v-120.576q0-55.442-29.696-81.152 32.585-3.438 58.587-10.277t53.723-22.272 46.299-37.998 30.281-60.014 11.703-86.016q0-69.157-45.129-117.723 21.138-52.005-4.571-116.553-16.018-5.157-46.299 6.29t-52.553 25.161l-21.723 13.714q-53.138-14.848-109.714-14.848t-109.714 14.848q-9.143-6.29-24.283-15.433t-47.726-22.016-49.152-7.717q-25.161 64.585-3.986 116.553-45.129 48.567-45.129 117.723 0 48.567 11.703 85.723t29.989 60.014 46.007 38.29 53.723 22.272 58.587 10.277q-22.857 20.553-28.014 58.843-11.995 5.705-25.71 8.558t-32.585 2.853-37.413-12.288-31.707-35.73q-10.862-18.286-27.721-29.696t-28.27-13.714l-11.447-1.719q-11.995 0-16.567 2.56t-2.853 6.583 5.157 8.009 7.424 6.839l3.986 2.853q12.581 5.705 24.869 21.723t17.993 29.147l5.705 13.129q7.424 21.723 25.161 35.145t38.29 17.152 39.717 3.986 31.707-2.011l13.129-2.304q0 21.723 0.293 50.871t0.293 30.866q0 10.277-7.424 17.152t-22.857 3.986q-132.571-43.995-216.283-158.574t-83.712-258.011q0-119.442 58.843-220.27t159.707-159.707 220.27-58.843 220.27 58.843 159.707 159.707 58.843 220.27z" p-id="3347" />
 </symbol>
</svg>

  • 乍一看,感觉没有变化啊,长一样是不是?:smile:,细看多了个symbol包裹了一下,嗯,也就这点区别了~。那么问题又来了,我们直接在页面上引用,就完事了吗?结果是否定的,请下图:
<body>
    <svg xmlns="http://www.w3.org/2000/svg">
      <symbol id="svg-github"  viewBox="0 0 1024 1024">
        <title>github</title>
        <path style="fill-rule: evenodd;" d="M941.714 512q0 143.433-83.712 258.011t-216.283 158.574q-15.433 2.853-22.565-3.986t-7.131-17.152v-120.576q0-55.442-29.696-81.152 32.585-3.438 58.587-10.277t53.723-22.272 46.299-37.998 30.281-60.014 11.703-86.016q0-69.157-45.129-117.723 21.138-52.005-4.571-116.553-16.018-5.157-46.299 6.29t-52.553 25.161l-21.723 13.714q-53.138-14.848-109.714-14.848t-109.714 14.848q-9.143-6.29-24.283-15.433t-47.726-22.016-49.152-7.717q-25.161 64.585-3.986 116.553-45.129 48.567-45.129 117.723 0 48.567 11.703 85.723t29.989 60.014 46.007 38.29 53.723 22.272 58.587 10.277q-22.857 20.553-28.014 58.843-11.995 5.705-25.71 8.558t-32.585 2.853-37.413-12.288-31.707-35.73q-10.862-18.286-27.721-29.696t-28.27-13.714l-11.447-1.719q-11.995 0-16.567 2.56t-2.853 6.583 5.157 8.009 7.424 6.839l3.986 2.853q12.581 5.705 24.869 21.723t17.993 29.147l5.705 13.129q7.424 21.723 25.161 35.145t38.29 17.152 39.717 3.986 31.707-2.011l13.129-2.304q0 21.723 0.293 50.871t0.293 30.866q0 10.277-7.424 17.152t-22.857 3.986q-132.571-43.995-216.283-158.574t-83.712-258.011q0-119.442 58.843-220.27t159.707-159.707 220.27-58.843 220.27 58.843 159.707 159.707 58.843 220.27z" p-id="3347" />
     </symbol>
    </svg>
</body>

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

  • 那么该如何摆正姿势(你随意就好),正确的使用它呢?热爱学习的你,是不是已经有些饥渴难耐了呢?马上为你送上高潮部分:
    本文由@IT·平头哥联盟-首席填坑官∙苏南分享
    本文由@IT·平头哥联盟-首席填坑官∙苏南分享
    本文由@IT·平头哥联盟-首席填坑官∙苏南分享
<body>
    <svg xmlns="http://www.w3.org/2000/svg" style="display:none">
      <symbol id="svg-github"  viewBox="0 0 1024 1024">
        <title>github</title>
        <path  d="M941.714 512q0 143.433-83.712 258.011t-216.283 158.574q-15.433 2.853-22.565-3.986t-7.131-17.152v-120.576q0-55.442-29.696-81.152 32.585-3.438 58.587-10.277t53.723-22.272 46.299-37.998 30.281-60.014 11.703-86.016q0-69.157-45.129-117.723 21.138-52.005-4.571-116.553-16.018-5.157-46.299 6.29t-52.553 25.161l-21.723 13.714q-53.138-14.848-109.714-14.848t-109.714 14.848q-9.143-6.29-24.283-15.433t-47.726-22.016-49.152-7.717q-25.161 64.585-3.986 116.553-45.129 48.567-45.129 117.723 0 48.567 11.703 85.723t29.989 60.014 46.007 38.29 53.723 22.272 58.587 10.277q-22.857 20.553-28.014 58.843-11.995 5.705-25.71 8.558t-32.585 2.853-37.413-12.288-31.707-35.73q-10.862-18.286-27.721-29.696t-28.27-13.714l-11.447-1.719q-11.995 0-16.567 2.56t-2.853 6.583 5.157 8.009 7.424 6.839l3.986 2.853q12.581 5.705 24.869 21.723t17.993 29.147l5.705 13.129q7.424 21.723 25.161 35.145t38.29 17.152 39.717 3.986 31.707-2.011l13.129-2.304q0 21.723 0.293 50.871t0.293 30.866q0 10.277-7.424 17.152t-22.857 3.986q-132.571-43.995-216.283-158.574t-83.712-258.011q0-119.442 58.843-220.27t159.707-159.707 220.27-58.843 220.27 58.843 159.707 159.707 58.843 220.27z" p-id="3347" />
     </symbol>
    </svg>
    1、使用方式一
    <svg class="svg-icon">
         <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#svg-github" />
    </svg>
    2、使用方式二,外链式引入
    <svg class="svg-icon2">
         <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="./icon.svg#svg-github" />
    </svg>
    <style>
        .svg-icon2{
            fill:#06c; //还可以设置图标的种颜色哦
        }
    </style>
</body>

  可能大家就有点疑惑了,为什么这样引入图标会显示呢?因为要显示图标,我们还需要使用元素,通俗的讲就是你定义了一组图形对象(使用<symbol>元素)之后,可以使用元素来对它进行无限次实例化展示。你使用xlink:href属性来指定你想要展示哪一组图标(相当于css图片精灵中的background-position),这里,我们要展示的是id为#svg-github的,细心的宝宝们可能还发现了style="display:none",你可以把它理解为是css sprite里的图片base64转化后的文件,先声明了变量存放起来了,,而方法二里的xlink:href="./icon.svg#svg-github",可以理解为是Css Sprites里我们background-image 引入图片一样,而 #svg-github 就是background-position里的坐标,还有颜色的改变,我们可以直接在svg内的 path上写行内式 fill="#06c"、style="fill:#06c";都是可以的,在维护上,是不是比图片更加方便呢???

  当然啦,大家都懂的,越漂亮的妹子追的人越多啦,代码也一样,越好用的东西往往也是不可能那么完美啦,看到这里,是不是觉得想骂娘呢?白看你说这么多废话,最后不能用,坑爹…… 
  别慌,其实也没有那么糟糕啦 ,SVG只在IE9以上支持;所以如果你需要支持IE8及以下的浏览器,你需要另外再写一套降级(例如,使用png图片方案),随着科技的发展,IE9以上大多数人还是能接受啦,特别是手机端的用户,再也不用担心测试MM来找你,图标不清晰的问题了啦,是不是很开心,有没有~~

总结:

Svg Sprites相比Css Sprites,不管是在维护和开发的过程中,还是在用户体验、性能、大小、
项目迭代代码维护上都比Css Sprites方便,更高效便捷;

svg sprites优缺点:

  • Svg Sprites使用xlink:href #id的方式获取,便于维护和扩展,因为小图的id不会随便改动;
  • 方便改变图片颜色,通过设置fill:颜色值,随意改变小图颜色;
  • IE9以上支持。

Css Sprites优缺点:

  • Css Sprites使用background-position不便于维护和扩展、定位不精确等问题,例如:在后期项目迭代中我们需要删除其中一个小图,那么排在它后面的小图位置都要移动,需要再次修改csss样式,或每次都要打开PS删除某图标再导出;
  • 无法修改小图颜色,要UI设计师调整后替换,过程漫长效率低;
  • 在移动端的大屏手机图标会模糊,影响体验。

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

  以上就是今天的分享,写了蛮久,最近才在开始尝试写博客,新手上路中,文章中有不对之处,烦请各位大神斧正。如果你觉得这篇文章对你有所帮助,请记得点赞哦~,想了解更多?请猛戳这里!

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8

作者:苏南 - 首席填坑官

链接:https://honeybadger8.github.io/blog/

交流群:912594095,公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明链接及出处。

测试领域,小白问题大集合(适合未入门和入门初级者)

本文由@IT·平头哥联盟-首席背锅官∙松鼠 分享,公众号:honeyBadger8

作者:首席背锅官∙松鼠

交流群:912594095[资源获取/交流群]、公众号:honeyBadger8,本文原创,著作权归作者所有,转载请注明原链接及出处。

前言

​  大家好,这里是@IT·平头哥联盟,我是首席背锅官——松鼠,今天要分享的是最给一些还没入门的同学或需要提升的同学一些指引,详细说明自己这几年来经历怎么一步一步转型,给大家一个参考,希望可以少走些弯路

​  这是@it·平头哥联盟的第一篇测试文章,所以写篇针对小白迷茫或刚培训完入职后想提升迷茫不知道该怎么做的同学,我在15年的时候也培训过,也很清楚从培训或自学到入门转型的整个过程,也清楚工作后的提升过程.

​  说说整体计划,以后我们会分享自动化,性能,基于安全一些技术文章,会结合现在工作中所用到的技术来进行分享,目前工作中有用到jmeter做性能,rf,BDD(lettuce)做自动化,Appscan做安全,当然还有最基本的功能测试(黑盒).当然,有兴趣写博客的大牛,欢迎加入我们@it·平头哥联盟一起写技术博客,一起带动大家学习进步,快乐你我他,欢迎投稿哦~

​ ~~~言归正传~~~

引言

很多小白会问的问题:
  • 我是做***外行的,跟IT没任何关联能做测试吗?

  • 做测试加班多吗?会不会很难呢?

  • 学历要求高吗?

  • 测试难还是开发难,哪个比较好入门,我应该转型哪个呢?

  • 我不知道要怎么自学,不知道要怎么入手,有种不知所措的感觉,是不是要培训呢?

  • 黑盒测试和白盒测试哪个工资高?

  • 我做测试应该要学哪个语言呢?java好还是python好?

  • 测试以后发展前景怎么样呢?

  • 我年纪大了,27,28,30岁了,做测试还来的及吗?

  • 我要是培训了,找不到工作,那岂不是亏了学费又浪费了时间?

已转型做功能的同学可能会问:
  • 我功能做一年,两年了,还只会功能,我要怎么提升呢?

  • 整天工作点点点,想提升又不知道怎么做?

  • 我应该学那门语言呢?

  • 总感觉我工资提不上去了?

反反复复,来来回回都是这些问题,这次我详细说说!仅仅个人观点提供参考!

本文由@IT·平头哥联盟-首席背锅官∙松鼠 分享

以下关于我的一小段转型历程~~~~~~

​  这里简单说明我转型的经历,以前做的行业就不说了,跟IT一点关联都没有,哈...
​  三年前的某一天决定要转行到it行业,想转型到it的想法都是认识一个后台开发的小哥,健身房认识的,当时处于迷茫期的我只要认识一个朋友就会问些行业之类的话题,当然不是直接问了,毕竟有点不好,会先说自己不知道要做什么,然后再问他做的行业之类的.

​  当时他跟我说后台开发,那时的我并不知道后台开发是什么东西,他说些代码的,我回了什么是代码,哈哈哈,他也不知道怎么回答我. 后面他也说这行业工资会高点,当时我并没有很注意这个,因为对我来说都不知道是干什么的,也没去了解,是经过别的行业洗礼后才想到这小哥哥,然后就打电话问他这行业情况,再各种查资料,他最后给我的建议就是去培训,说我这情况只能培训,说了个机构叫我自己去了解,最后我就去很多家机构了解对比啥的,就报名了. 是的没错,直接报名了~~ 想都没想万一转型不成功会咋办的问题.... ,这里培训的是安卓开发,现在想想胆子也挺大的.

本文由@IT·平头哥联盟-首席背锅官∙松鼠 分享

  培训的过程很辛苦,4个月时间,现在想想都不知道怎么熬过去的.是不是很好奇为什么培训开发做测试呢?
当时开发学完入职了一家公司两个月,一直加班好累,每天感觉头脑在冒烟,当时就一个想法,这生活不是我想要的,请原谅没出息的我! 然后就想转型测试.

​  转型测试一开始我在网上了解才知道测试分好多种,功能测试、自动化测试、性能测试、安全测试,当时就想怎么一个测试也有那么多种,还以为直接转很简单,网上看了那么多感觉都没接触过....,当时想法先用开发简历投测试试下,边投简历边自学,一直认为有开发的经验测试应该会很受欢迎,没想到一个电话都没有. 有开发经验测试领域很受欢迎这观点是没有错的,但是测试零经验就没有人要了.我记得当时投简历好几天有个电话叫我去面试,我问了下测试工资能给我多少,对方说最高8k,我回了相对我现在的工资差别有点多,我接受不了,然后就没去面试了.

​  这时候我也好好思考了,要顺利转型我是不是又要培训测试?这样我又要花费好多时间,金钱也要投入,当时松鼠我很穷,生活费都是刷信用卡和支付宝的网商贷里面拿出来的.....,我选择自学,当时我就辞掉这份工作了,然后网上买了一些测试的视频,整套完整的很便宜,视频看了两三天实在是看不下去,这时很清楚自己不适合自学,然后就去走了好多家机构进行对比,了解机构的过程还是挺逗的,很多机构以为我是小白老是要忽悠我,总是说那些什么小机构,不出名的机构怎么样没保障,找工作也没保障之类的,当时好想笑,找工作不就是简历给外包面试吗?有什么不保障的,又不是进自研.当时什么51,川石,泽林,怀谷(这个名字有点忘记了),有同学在泽林培训过,当时我也打算去了,还好群里遇到另一个机构去看了学费好便宜还是不贷款找到工作后再自觉给学费的,当时觉得好神奇,直接就定下来了,去那边租房学了两个月,有开发的基础学测试真的是太简单了,哈哈哈哈 ~~ 学完果然都在我的预算之中,顺利拿了很多的of.

本文由@IT·平头哥联盟-首席背锅官∙松鼠 分享

~~~~~~~以上是我的一个转型过程,比较麻烦,还花费很多的时间,不过到现在没后悔过~~~~~~~~

问题观点:

转行其实就是看一个字 —— 胆量!

本文由@IT·平头哥联盟-首席背锅官∙松鼠 分享

  • 很多人转行都犹豫这犹豫那的,怕这做不了怕那做不了,我当时都没犹豫过这个,刷信用卡当时有个大胆的想法…就算我转行没成功这几千块钱的生活费我去餐厅洗碗也能还上…… 哈哈哈哈,现在想想还挺逗的

  • it学历确实要求比较高,这是行业的硬性要求没办法,身边有很多高中毕业的,虽然也是高薪就业,但肯定是用了些办法进公司的,低学历首先肯定的是跟大公司无缘.这个要切记,现在本科以下自研的公司很难进,大专外包很容易,外包要求比较低

  • 不管以前你学习怎么样,测试这个绝对是能上手的,这点倒不用担心,因为测试太简单了(功能测试),至于自动化,性能都是要后续自己提升,这就看自己了

  • 还要注意一点:测试学习两个月就够了,开发学习起码要4个月(如果培训的话)

  • 自学的,测试给自己3个月时间,开发一般需要8个月左右,自学效率不高,能在这个时间内完成那是很了不起

  • 加班问题,太过于执着加班的人,可能真的有点不适合it,这行业不加班的公司还真的很少,不想加班的单位其实是有的,但你本身要有这条件,一般不怎么加班的公司比较多的领域就是银行单位(带编制岗位),金融行业的技术不加班的还是挺多的,当然加班的也不少,我所知道的金融公司不加班的比较多(这里不加班的概念是加班比较少),外包的话,像bat华为等类似大公司都是加班特别厉害的,身边有华为外包的真的是996上班形式的.....,还有一种公司不加班的,那就是外企

  • 年纪问题,年纪大了做it确实是有点不合适,这是个人观点.身边很多年纪在30+的才去培训,这个年纪培训有个点事你要学好点,因为你找工作这经验需要包装挺多的,要懂的比别人多,一个三十多岁总不能说才工作一两年吧,半路转行的很多公司不会要的,外包还是很好近的.年纪大也确实比较不好找工作,我们公司一般面试接到32以上的一般就不怎么会要了.....,个别公司吧!

  • 语言方面:现在测试领域java和python用的都比较多,python是一个趋势,现在测试很多都在转型python,测试方面这两个语言已经不相上下了,新人建议学python,因为python相对好入手点

  • 测试的前景,前景这个心态还挺重要的,首先你进入这行业,总不能一直只做功能不去提升吧,一辈子只做功能的话,那你的前景就真的很窄,不过功能做的好的话转产品那前景又扩大了一步,拿我自己来说吧!我到现在我都很担心自己哪天失业,所以只能经常看看书,视频来提升自己.也有计划转型产品但是感觉技术还不错,还想多做两年,当然只是一个计划而已.只要你技术好,就不用担心前景问题

  • 小白怎么入门?一般it入门方式也就三种,校招进入企业,自学和培训,转行的也只有自学和培训两条路,有能力自学的优势就是省了挺多钱的,培训就需要培训费和生活费,我个人不排斥培训,毕竟经历培训也都找到工作,工资也还好,个人建议找个便宜的机构培训. 原因:培训出来一半工资会比自学的工资高,假设自学6k,培训8k,那培训出来年薪就会多两万多,这两万多足够付这培训的费用了,最后还是赚了.需要注意的是,年纪太小,培训需要小心,年纪小培训工资都不会高到哪里的

  • 工作后要怎么提升呢? 工作后提升两种方式: 1.最快的就是利用公司项目提升 2.业余时间提升(看书,视频等),业余提升可以说是相当难,亲身体验的,因为工作后有点惰性,下班后就不想动了,哈哈哈.要是公司有需求做自动化参与什么的,提升是最快的.我提升的几乎都是公司需求自己摸索自己做的.业余都是担心做不出来查资料学习,只要有需求都会去补知识的.

我个人想到的目前是这些问题,还有其他问题的可以留言,我会一一回复的,当然有不懂的也可以问我,如果我会的问题,知无不言.也可以加群,在下方有群号,测试的加测试群,前端加前端,也可以加q9617 101 68

写文章目的:一方面逼自己学习提升,一方面提升自己文采,还有最重要想积累下自己的名气,不然就不会辛辛苦苦写博客了,需要能帮助大家,来给我个赞吧!👍

下一步文章计划列表:

  • 用例设计方法详解
  • mysql入门(测试必备技术)
  • Linux入门(测试必备技术)
  • 什么是接口测试
  • python-lettuce介绍
  • 基本安全测试知识
  • python基础学习
  • jmeter性能测试
  • 性能优化策略(难度较大)
  • robotframwork 讲解

接下去先写这些文章吧! 慢慢来,一个一个写,哈.感觉要好辛苦,留个言给个赞吧! 一个人可能记不住那么多,有漏的欢迎指点.

有大牛要写博客的可以加入我们@IT·平头哥联盟,一起写博客!

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8

作者:松鼠 - 首席背锅官

链接:https://honeybadger8.github.io/blog/

交流群:912594095[资源获取/交流群]、公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

小程序项目如何设置资源的防盗链?

小程序项目如何设置资源的防盗链?从入门到真实项目配置,首席填坑官∙苏南的专栏

做过前端,或对小程序有些了解的同学都知道,小程序是没有域名访问概念的,访问的路径都是以:“/pages/index”、“/pages/my”这种方式进行页面跳转的。域的概念从何而来?

事情是这样的,前段时间突然冒出个想法,大家上下班,有些人离公司比较远,回家路上/地铁上,可能都会比较无聊,看看新闻、听听音乐啥的。

但是对于IT行业的程序员们来说,入了IT领域就意味着,永远有学不完的东西,经常就有看到一些人在地铁拿着一本书在看,于是我灵机一动,想着做了个小程序,收集一些电子书,方便大家随时随地的阅读,既不耽误学习,回家的路上也不无聊,而且小程序集成在微信里,不会给大家带来负担。

说干就干,经过几个周末的开发和测试,慢慢的小程序成型了,也发布上线了,是基于wepy框架开发的,坑点之前的文章已经说过了,就不再提了。主要讲讲后面发生的一些事。

作为技术交流,平时也加了一些群,都有一些不错的书,工作几年自己也弄了些存货,这次是全部家当都拿出来了、还找了几个测试java的后端大佬,都收集了些他们的珍藏品,因为没有自己的服务器,刚开始是把内容存放在阿里云上的,但没两天告诉我欠费了……,

想哭,就这么工资,怎么经的起折腾啊,后来了解了一下腾讯云,每月有些免费的流量,果然放弃了阿里云,把东西转移到了腾讯云。嗯,就这样很开心的把小程序上线了,每天有事没有看看书,觉得还是蛮方便,身边同事也都觉得不错,还给提了些小建议。

然而小程序放上去不到两周,就在昨天、就在昨天、就在昨天,突然收到腾讯云的邮件提示,cos欠费,C\A\O,什么情况啊,我懵逼了……,想了半天,先充了几块钱进去……,毕竟不想自己努力构思的产品,就诞生这么几天就夭折了。

今天在快下班了突然想起这个事,想着赶紧看一下,发现cos的数据把我吓哭了、真的、如果不到两周能有这么高的访问量,我会很开心的,然而小程序的后台数据是不一样的。

  • 小程序访问次数:1000次,不到;
  • cos请求数:2.85w,呵呵~,

cos的访问次数,previewImage与腾讯COS防盗链的配置问题,从入门到真实项目配置,首席填坑官∙苏南的专栏

欠费通知,小程序的访问量,从入门到真实项目配置,首席填坑官∙苏南的专栏

坑爹的啊,请求次数2.85w,小程序的访问量不到1000

不用说,这是被人欺负了……,内心1W个草泥马,在心里奔腾,怎么办呢?第一时间是想到了防盗链,不允许指定域名以外的站点访问你的链接。

但问题又来了,前面说过,小程序没有域名啊~

微信小程序怎么获取当前页面的url啊,从入门到真实项目配置,首席填坑官∙苏南的专栏

于是在项目中,把Network面板的信息看了又看,查看Headers信息,看到Referer这里有一个没见过的域名把整个页面请求头(后面发现的,哈哈~),百度搜索无果,最后还是谷歌告诉我,小程序也是有个域名的,请看下图:
@IT·平头哥联盟,七牛CDN防盗链开启后,微信小程序无法加载其资源问题解决

原谅我穷,赶紧在cos上配置了这个白名单,同时也赶紧测试了一下,去掉后,是否还能访问,以图为示例:

@IT·平头哥联盟,赶紧在cos上配置了这个白名单

当然这个方法是不完全可靠的,比如其他小程序也是这个域名啊,还是能调用你的资源,有点纳闷~,求大佬们指点可靠的方法。感谢!!

以上就是今天的随笔小记,希望能帮到其他遇到同样坑爹事情的同学,最后分享一下做的小程序:码农书籍,爱学习、阅读电子书的同学可以收藏一下!

码农书籍,一起阅读,一起进步,用心分享 做有温度的攻城狮,苏南的专栏

作者:苏南 - 首席填坑官

链接:http://susouth.com/

交流:912594095、公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

大家好 这就是2018年的我~- 周五非技术

2018年终总结 请在2019对我好点~,2018 年面对众多前端新技术,该如何学习? 小程序项目如何设置资源的防盗链?从入门到真实项目配置,首席填坑官∙苏南的专栏

大家好,今天周五,明天就是周末,再过几天也就是2019,2018即将成为过去,昨晚抽时间对自己的2018做了个年终总结,今天跟大家汇报一下。

以下就是2018年的我:

首先请看看我的钱包

它有如下特点: 渐进式框架,采用自底向上增量开发设计模板双向绑定机制利用 ... 组件化.png 围绕Vue.js框架,涉及到的常用技术/插件有,首先请看看我的钱包

接下来就是我的积蓄

接下来就是我的积蓄

然后就是我的体重

然后就是我的体重,对于开发者而言,2019出奇的高效,不过2019年有望为IT领域带来更多发展。本文中 ... 我们没想到这个开发环境成为前端技术工具列表中的佼佼者

还有大家比较关心的我的睡眠质量

还有大家比较关心的我的睡眠质量

啦啦~ 我的发量,

默默问一句,你的有多少?

我的发量,2019 年,前端开发人员应该关注哪些新晋技术?

我对生活的态度

佛系青年有没有,是不是很棒棒??

HTML5.2新标签dialog HTMl5.2新的版本出现了一个有意思的标签,那就是 ... 2018年02月26日 阅读8973. 2018年你应该了解的前端新技术 ...
随着互联网技术不断的发展,前端的新技术也开始日新月异,旧的技术已经不能满足工作的需要,根据业务需求来将重构也是常有的事情,为了减少,佛系青年有没有??
佛系青年有没有??

我的感情经历

相信自己的眼睛,你没有看错、网络也正常??

 随着近年来前端的一波又一波技术浪潮,前端早已经告别了切图的时代,迎来的是规模化,工程化的大路。但是在如此多变的技术浪潮下,我们如何 ...

我的生活经历

字不重要,图是重点??

佛系青年有没有??

我的求知欲

学习使我进步,我对知识的渴望……

GMTC为期2天,主要面向各行业对移动开发、前端、AI技术感兴趣的中高端技术人员,大会聚焦前沿技术及实践经验,旨在帮助参会者了解移动开发&前端领域最新的,我的求知欲
我对知识的渴望……

我的夜生活

身处一线城市,丰富多彩的夜生活……

我的求知欲,2019年前端工程师的未来在哪里?

抱歉 上面那张图是我比较期望的

这才是我的夜生活~

我对知识的渴望……

我的理想

我对知识的渴望……
我对知识的渴望……2019年一个合格的前端应该是什么样子的?
我对知识的渴望……

残酷的现实

我对知识的渴望……

我的养生理念

人人都爱美,我也有自己的养生理念

人人都爱美,我也有自己的养生理念
我的养生理念
我的养生理念

我的自信心

我的养生理念

我的上班状态

热爱工作的我,干劲十足~

我的养生理念,信息管理、财务、建筑、航天、水利、金融、制造等传统行业软件以及阿里提出的五新:新零售,新制造,新金融,新技术和新能源,新技术赋能传统行业

我的下班状态

好烦,怎么这么快就下班了~

好烦,怎么这么快就下班了~

开会时的我

它有如下特点: 渐进式框架,采用自底向上增量开发设计模板双向绑定机制利用 ... 组件化.png 围绕Vue.js框架,涉及到的常用技术/插件有,开会时的我

听到八卦的我

听到八卦的我

我的朋友圈

如果你想在深入学习Vue 之前对它有更多了解,我们制作了一个视频,带您了解其核心概念和一个示例工程。 如果你已经是有经验的前端开发者,想知道Vue 与其它库,我的朋友圈

年初的我

新的一年开始了,一定要大展身手

年初的我

年终的我

年初的我

总的来说
我的2018年大概是这样的

年初的我

这样的

本文旨在帮助大家认识Vue.js,了解Vue.js的开发流程,并进一步理解如何 ... 的情况,所以我们需要用到Vue提供的技术栈来构建强大的前端项目年初的我

这样的

Vue 常见业务场景以及细节心得-年初的我

这样的

最近做了一次关于vue 组件自动化测试的分享,现在将vue 组件单元测试环境搭建过程整理一下。这次搭建的测试环境和开发环境隔离,所以理论上,年初的我

和这样的

年初的我

真是丰富而又充实的一年呢!

滴滴D8工程师手把手教授,不只是技术,还有很多手机端开发技巧从0到1实现一个全整项目,符合生产级别的标准代码使用Vue.js+ES6+webpack技术,采用组件化,年初的我
年初的我

好啦,2018终于过完啦,大概就是这样,
2019,请千万对我好一点啊~~
2019,请千万对我好一点啊~~

码农书籍,一起阅读,一起进步,用心分享 做有温度的攻城狮,苏南的专栏

*今年的冬天特别的冷,希望此文能博你一笑,

如果你喜欢的话,欢迎点赞、关注(IT平头哥联盟),

分享给你的好友们就更棒了,谢谢支持~

其他

作者:苏南 - 首席填坑官

链接:http://susouth.com/

交流:912594095、公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

如何规范化测试流程,看这篇就够了~

本文由@IT·平头哥联盟-首席背锅官∙松鼠 分享,公众号:honeyBadger8

作者:首席背锅官∙松鼠
交流群:912594095[资源获取/交流群]、公众号:honeyBadger8,本文原创,著作权归作者所有,转载请注明原链接及出处。

引言

  • 什么是软件测试?

    1、利用人工或自动化的手段对软件进行测试,找出bug,从而降低商业风险;

    2、正向思维:软件测试是一系列的活动来验证程序是否正常运行,以及是否达到了用户预期的需求;

    3、逆向思维:软件测试是为了发现程序的错误或者缺陷而进行的一系列活动;

    4、一个软件/应用是由文档需求、数据、程序等部分组成,所以软件测试就不仅仅是对程序进行测试,而是多方位的验证;

    小结:测试工程师大概可以归纳为在规定的条件下对程序进行测试操作,了解程序项目需求/正常流程,发现程序的错误、不合格的流程及表现,对项目程序进行评估。

  • 测试的好处?

    1、发现程序的错误行为;

    2、定位程序的错误表现(UI展示);

    3、确认程序的逻辑与产品需求的一致性;

    4、确保呈现给用户的是完美无误的程序应用,给用户更好的体验。

  • 测试的目的?

    1、寻找项目的缺陷;

    2、跟踪修正项目的缺陷;

    3、验证修正的项目缺陷;

    4、没有完美的代码,也没有完美的应用,那么测试只有通过测试,发现问题才能提升应用程序的完美。

环境说明

  • dev(测试环境):根据开发人员提测的功能块:
    • 按照测试用例优先级,卓条进行测试验证,
    • 发现问题录入禅道系统并知会对应开发人员,
    • 修复完成后再验证;
  • uat(预发环境):dev测试通过后发送测试通过邮件并抄送各组leader知会;且发布预发(uat)环境;
  • uat发布完成后,进行第二轮流程验证测试,反馈发现的bug,修复验证通过后;确认需求不会变更,代码不再提交的前提下,进行回归测试验证(即对整个业务流程进行上线前的再次确认);
  • prd(生产环境):uat确认后,可根据项目要求输出测试报告 ,并发送邮件给各组负责人,项目测试完成可上线。

bug状态标准:提交bug -> 待处理 -> 已确认 -> 已处理 -> 测试验证 -> 已修复(关闭)

​ **需要注意的:**有的小公司只有测试环境和生产环境,

bug等级划分

  • bug一般可分为4个等级,根据问题的实际影响正确填写,严禁不区分问题的实际影响随意填写,对应级别如下

    • 致命bug:ID值5分,

      • 关键功能/性能不符合产品需求,或阻碍测试工作(如:项目运行死循环、程序导致的数据库数据丢失);
    • 严重bug:ID值 3分,

      • 部分模块功能缺失遗漏、项目无法测试、接口稳定性(60%)、数据保存后数据库显示错误/未存入、程序接口调用错误、界面严重错乱等;
    • 一般bug:ID值2分,

      • 功能没有完全实现但不影响使用、操作/查询等待时间过长、格式错误、边界条件错误等;
    • 提示bug:ID值0.5分。

      • 界面错乱/重叠、错别字、描述提示语与需求不符;
    • 建议

      • 测试人员觉得体验不好,但流程符合需求的,可以提出建议;

测试流程(目前公司的流程)

  • 1.测试基本流程图

本文由@IT·平头哥联盟-首席背锅官∙松鼠 分享,公众号:honeyBadger8

二.测试开始条件

  1. 项目需求阶段,产品提相应的jira,需要召开响应的需求评审会议,测试开始介入,熟悉项目需求,着手设计系统测试用例;

  2. 当所有的模块都开发完毕,研发人员对各个模块进行合成进行自测,自测通过后才可以发布测试版本,接口测试开发需要提供对应的接口文档,测试人员根据需求进行系统测试;

  3. 当新增功能或者版本升级,需要对新增功能及升级模块进行测试,对其他关联模块进行回归测试。

三.测试流程

  • 1.测试启动阶段

​ 产品,项目管理者,测试人员参,研发人员以及和项目有关联的其他人共同参与需求会议,需求评审中需要评估本次需求是否需要性能测试,明确需求及任务完成时间,产品需提供详细的需求文档,产品功能清单,研发人员需向测试人员提供产品项目需求文档、接口文档等,明确测试任务,确定测试周期。需求评审完后由项目经理发出项目计划表,后续项目进展时间节点按照此项目计划表来执行。

​ 测试人员根据项目工作量大小及项目进度编写测试计划书,对本次测试的范围、测试进度、测试策略等内容进行把控。

​ 研发人员在功能开发完成且自测通过后发布测试版本,提交测试申请单,发送提测邮件给测试人员,测试人员进行冒烟测试,冒烟测试通过,进入测试阶段,否则打回测试。测试人员在测试阶段,要做好版本控制,研发人员在这一版本中修复的bug,需要下一个版本中再次验证。

​ 临时新增的紧急需求和改动点,产品需要提供对应的jira,研发需要新增提测单并且填写测试注意点。

  • 2.设计用例阶段

​ 在拿到需求文档,产品功能列表之后,测试人员就开始着手设计测试用例了。测试人员根据产品功能列表后尽量多的设计测试用例,尽可能多的覆盖所有的测试需求。测试用例完成后需进行用例评审,产品和对应的研发人员必须参加,评审会上发现的问题需要及时补充和完善。

  • 3.用例执行阶段

​ 开发提测后,进行冒烟测试用例,冒烟通过率低于80%,测试有权力打回测试,冒烟通过后进入正式测试阶段,测试过程中发现的bug需要记录在jira中,测试人员要争取每个bug都能够重现,便于开发修改;测试人员将bug反馈给相关开发人员,开发人员进行修复,测试人员对已修复的bug进行再次验证,直到bug解决为止,把状态置为关闭,并将测试结果记录。

  • 4.提交测试总结报告

​ 在约定的测试周期内,在所有的用例都执行完,一般及以上的bug都修复完,遗留bug需要记录在jira中便于后续版本的回归,测试人员需要针对本次测试项目编写测试总结报告,将测试结果反馈,以及容易出现bug的模块给予建议,相关负责人在下次开发中予以借鉴,避免类似错误的出现,测试报告可通过邮件形式,让相关研发人员知晓。

四.测试结束

  1. 当所有的用例都被执行完,所有一般及以上的bug都被修复,产品验收通过,测试编写完测试总结报告;

  2. 基本功能都已实现,一些遗留bug可以再下一版本中修复;

  3. 如遇项目紧张,急于上线,测试基本功能没问题,对于用户后续发现的bug可以进行跟踪,并且后续发现的问题记录在jira中。

如果觉得不错,请记得关注我们公众号哦,第一时间获得最新分享~👇

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8

作者:松鼠 - 首席背锅官

链接:https://honeybadger8.github.io/blog/

交流群:912594095[资源获取/交流群]、公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

初学者可能不知道的vue技巧

@IT·平头哥联盟,公众号:honeyBadger8

前言

  大家好,这里是@IT·平头哥联盟,我是首席甩锅官——老金,今天给大家分享的,一些日常中神秘而又简单的vue的实用小技巧,以及我在我司项目中实用vue的总结和坑,跟大家一起分享,希望能给其他攻城狮带来些许便利,如有理解错误,请纠正。

技巧/坑点

1.setTimeout/ setInterval

  • 场景一 :this指向改变无法用this访问vue实例
  mounted(){
    setTimeout( function () {
    //setInterval同理
    console.log(this); //此时this指向Window对象
    },1000) ;
  }
  • 解决方法 :使用箭头函数或者缓存this
  //箭头函数访问this实例因为箭头函数本身没有绑定this
  setTimeout(() => {
    console. log(this);},  500) ;
    //使用变量访问this实例let self=this;
  },1000);
  setTimeout (function () {
    console. log(self);//使用self变量访问this实例
  }, 1000) ;
setInterval路由跳转继续运行并没有销毁
  • 场景一 :比如一些弹幕,走马灯文字,这类需要定时调用的,路由跳转之后,因为组件已经销毁了,但是setlnterval还没有销毁,还在继续后台调用,控制台会不断报错,如果运算量大的话,无法及时清除,会导致严重的页面卡顿。
    • 解决方法 :在组件生命周期beforeDestroy停止setInterval
 
  created() {
       this.intervalid = setInterval(() => {
          this.layerError = "";
          this.Timer = null;
      }, 100000);
   }
  beforeDestroy( ){
    //我通常是把setInterval( )定时器赋值给this实例,然后就可以像下面这么暂停。
    clearInterval(this.intervalid);
  }

2.Vue路由拦截浏览器后退实现草稿保存类似需求

  • 场景一 :为了防止用户突然离开,没有保存已输入的信息。
    • 解决方法 :
  //在路由组件中:mounted(){},
  beforeRouteLeave (to, from, next) {
      if(用户已经输入信息){
        //出现弹窗提醒保存草稿,或者自动后台为其保存
      }else{
        next(true);//用户离开
      }
  }

3.自定义组件添加click等事件不生效

  • 场景一 :一些自定义组件,需要额外添加一些事件来实现一些特定需求
  <template>
    <el-progress type="circle" :percentage=“0" @click=“stopProgress”></elprogress>
  </template>
  <script>
    export default {
       methods:{
            stopProgress() { 
            console.log('停止')
            }
        }
    }
  </script>
  • 解决方法:使用.native修饰符
  <template>
    <el-progress type="circle" :percentage=“0" @click.native=“stopProgress”></el-progress>
  </template>
  <script>
    export default {
        methods:{
            stopProgress() { 
            console.log('停止')
            }
        }
    }
  </script>

4.手动操控自定义组件

  • 场景一 :一些自定义组件,需要去获取组件对象进行一些其他的Dom操作
    • 解决方法 :使用ref属性暴露组件获取句柄
  <template>
    <el-progress type="circle" :percentage="O" ref="progress"></el-progress></template>
  <script>
    this.$refs.progress //组件对象实例, 可以手动调用组件的内置方法和属性
    this.$refs.progress.$el //组件 对象的最外层dom元素
  </script>

5.深度作用选择器

  • 场景一 : scoped的样式,希望影响到子组件的默认样式

在样式中设置完scoped在浏览器解析为如下图这样,a是个div,a div里面包含一个组件里面解析完了div的样式名字为b,想在父组件影响到子组件的默认样式。

平头哥
解决方法:

  <style scoped>
    .a >>> .b { /* ... */ }
  </style>
    //有些像Sass之类的预处理器无法正确解析>>>。这种情况下你可以使用/deep/操作符取而代之- - - -这是一个>>>的别名,同样可以正常工作。
  <style scoped lang=“scss”>
    .a /deep/ .b { /* ... */ }
  </style>

6.Vue数组/对象更新视图不更新

  • 场景一 :很多时候我们习惯于这样操作数组和对象
  data() { 
    return {
        arr: [1,2,3],
        obj:{
          a: 1,
          b: 2 
        }
    }; 
  },

  // 数组更新视图不更新
  this.arr[0] = 'OBKoro1';
  this.arr.length = 1;
  console.log(arr);// ['OBKoro1']; 
  // 数据更新,对象视图不更新	 
  this.obj.c = 'OBKoro1';
  delete this.obj.a;
  console.log(obj);  // {b:2,c:'OBKoro1'}
 
  • 解决方法
    • this. $set(你要改变的数组/对象,你要改变的位置/key,你要改成什么value)
    • 数组原生方法触发视图更新( vue官网可查):
    • 整体替换数组/对象
      平头哥

7.Vue Filters过滤器的使用

  • 场景一 :常见的数据文本的格式化
  <!-- 在双花括号中 -->
  <div>{{ message | DateFormat }}</div>	//展示正确时间
  <!-- 'v-bind' -->
  <div v-bind:id="rawId | formatId"></div>

  Demo:一个日期过滤器返回yyyy- MM-ddhh:mm:ss的样式
  引入一个提前写好日期格式化的js
 import dayjs from 'dayjs'
  export default {
      data() {
               return {
                  		//时间毫秒
          				message:18324798324789
          			}
      },
    filters: {
    		//传入进行日期格式化
        DateFormat(value) {
          return dayjs(value).format("YYYY-MM-DD HH:mm:ss")
    		}
    }
  }

8.Vue深度watch与watch立即触发回调

  • 场景一 :在watch里面监测对象里面对应的值是监测不到的,可以用如下方法。
    • 选项: deep
    • 在选项参数中指定deep:true,可以监听对象中子属性的变化。
    • 选项: immediate
    • 在选项参数中指定immediate:true,将立即以表达式的当前值触发回调,也就是默认触发一次。
  watch: {
    obj: {
        handler(val, oldVal) {
          console.log('属性变化触发这个回调',val, oldVal); 
        },
        deep: true // 监测这个对象中每一个属性的变化
    },
    step: { // 属性 //watch
       handler(val, oldVal) {
        console.log("默认触发一次", val, oldVal); 
       },
       immediate: true // 默认触发一次
    }
  }

欢迎大家一起探讨 ~~

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮,公众号:honeyBadger8

作者:老金 - 首席甩锅官

链接:https://honeybadger8.github.io/blog/

交流群:912594095,公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明链接及出处。

动画一点点——CSS3画出懂你的3D魔方

本文由@IT·平头哥联盟-首席填坑官(苏南)分享,公众号:honeyBadger8

作者:首席填坑官∙苏南
交流群:912594095、公众号:honeyBadger8,本文原创,著作权归作者所有,转载请注明原链接及出处。

前言

  最近在写《每周动画点点系列》文章,上一期分享了< 手把手教你如何绘制一辆会跑车 >,本期给大家带来是结合CSS3画出来的一个立体3d魔方,结合了js让你随心所欲想怎么转,就怎么转,这里是 @IT·平头哥联盟,我是首席填坑官苏南(South·Su),我们先来看看效果,然后再分解它的实现过程吧

  本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

绘制过程:

  好吧,gif图看着好像有点不是很清晰,想在线预览的同学,可点击在线预览 👈,废话不多扯了,先来分析一下,看如何实现这个功能吧。

∙ API预热 :
  • 本次示例是一个立体的正方形,既然有立体效果,肯定少不了CSS3中的 -webkit-perspective-透视、preserve-3d-三维空间,这个两个是重点哦,当然还有transform-origintransitiontransform等,先来回故一下 API 怎么是讲的吧:

perspective 取值 :

  • none :不指定透视 ;
  • length :指定观察者与「z=0」平面的距离,使具有三维位置变换的元素产生透视效果。「z>0」的三维元素比正常大,而「z<0」时则比正常小,大小程度由该属性的值决定,不允许负值。

transform-style 取值

  • flat :指定子元素位于此元素所在平面内;
  • preserve-3d :指定子元素定位在三维空间内,当该属性值为 preserve-3d时,元素将会创建局部堆叠上下文;

小结 :决定一个变换元素看起来是处在三维空间还是平面内,需要该元素的父元素上定义 <' transform-style '> 属性,也就是说想某元素有三维效果,需要设定它的父级有 preserve-3d

transform-origin 取值

  • percentage:用百分比指定坐标值。可以为负值;
  • length:用长度值指定坐标值。可以为负值;
  • left:指定原点的横坐标为left;
  • center①:指定原点的横坐标为center;
  • right:指定原点的横坐标为right;
  • top:指定原点的纵坐标为top;
  • center②:指定原点的纵坐标为center;
  • bottom:指定原点的纵坐标为bottom;

transform、transition等,就不介绍了

/* perspective 使用示例:*/
div{
  -webkit-perspective:600px;
  perspective:600px;
}

/*transform-style 使用示例:*/
.preserve{
  transform-style:preserve-3d;
  -webkit-transform-style:preserve-3d;
}

  /*transform-origin 使用示例:*/
.preserve{
  -webkit-transform-origin:50% 50% -100px; or 
  -webkit-transform-origin:bottom; or
  -webkit-transform-origin:top;
  …………
}
  
∙ 绘制6个面 :
  • 是的,我没有说错,就是6个面:上、正面、下、背面、左、右,
  • 上面API讲了这么多,来实践试一下吧,写6个div,结构大概是这样的,也是接下来的魔方需要的结构:
<div class="cube">
    <div class="cube-inner running">
        <p class="single-side s1"><span></span></p>
        <p class="single-side s2"><span></span></p>
        <p class="single-side s3"><span></span></p>
        <p class="single-side s4"><span></span></p>
        <p class="single-side s5"><span></span></p>
        <p class="single-side s6"><span></span></p>
    </div>
</div>

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8
本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

  • !!!发生了什么??是不是很吃惊??说好的值越大,透视效果越强的呢?后面明明藏了个妹子,怎么看没有透视出来?
  • 开始我也是跟你一样吃惊的,但瞬间就悟透了,少了rotate,加个它再来看看效果吧:

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

.cube{
    width:200px;
    height:200px;
    margin:10px auto;
    padding:260px;
    position:relative;
    -webkit-perspective:600px;
    perspective:600px;
    transition: .5s ;

}
.cube-inner{
    width:200px;
    height:200px;
    position:relative;
    -webkit-transform-style:preserve-3d;
    transition:.3s; 
    -webkit-transform-origin:50% 50% -100px;
    transform: rotateX(45deg);
}
.cube:hover{
    /*鼠标经过时,把 perspective 过渡到100 */
    -webkit-perspective:100px;
    perspective:100px;
}
  • 既然API有效,那么拉下来我们就画出6个面吧,按:上、正面、下、背面、左、右,这个顺序来设置吧;
  • 首先,我们要指定它们是在三维空间内的preserve-3d,也就是6个面的父级要设置 transform-style 样式;
  • 以上都设置好后,再来看看6个面吧,为了便于区分,给它们每个都设置了不同颜色(用了css3的渐变 radial-gradient)——不想手写的同学推荐一个网站可在线设置你要的效果,复制样式即可,先来一睹风采,为了便于观察,整体角度旋转了10deg:

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

  • 说到渐变,偶然之间发现了一个有意思的东西hue-rotate,它能在你初始的颜色基础上旋转元素的色调及其内容,从而达到不同的效果。了解更多

hue-rotate : The hue-rotate() CSS function rotates the hue of an element and its contents. Its result is a .

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

  • ** 上 ** - "":
.cube-inner .single-side.s1{
    /*s1顶部*/
    left:0;top:-200px;
    background: radial-gradient(circle, rgba(255,255,255,.88), #00adff);
    background: -webkit-radial-gradient(circle, rgba(255,255,255,.88), #00adff);
    transform-origin:bottom;
    -webkit-transform-origin:bottom;
    transform:rotateX(90deg);
    -webkit-transform:rotateX(90deg);
}

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

  • ** 正面 ** - "":

    • 下面就是默认的,什么都不用设置,所以就不展示了 ;
  • ** 下面 ** - "":

    • 即底部,底部的设置,正好跟顶部它是相反的,一个origin 以 bottom为基准为坐标,一个以top为基准为坐标;
.cube-inner .single-side.s3{
    /*s3底部*/
    left:0;top:200px;
    background: radial-gradient(circle, rgba(255,255,255,.88), #100067);
    background: -webkit-radial-gradient(circle, rgba(255,255,255,.88), #100067);
    transform-origin:top;
    -webkit-transform-origin:top;
    transform:rotateX(-90deg);
    -webkit-transform:rotateX(-90deg);
}

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

  • ** 背面 ** - "":
    • 即正面的后边,整体旋转了 135deg,让背面更直观能看到;
    • translateZ 、rotateX 同时移动,形成透视的关系,让它看起来,在正面面的后面;
    • 下图二,把默认的正面,设置了透明度,可以看出,背面的透视效果;
.cube-inner .single-side.s4{
    /*s4背部*/
    z-index:2;
    left:0;top:0;
    background: radial-gradient(circle, rgba(255,255,255,.88), #F0C);
    background: -webkit-radial-gradient(circle, rgba(255,255,255,.88), #F0C);
    transform:translateZ(-200px) rotateX(180deg) ; 
    -webkit-transform:translateZ(-200px) rotateX(180deg) ; /*rotateZ(-180deg) 左右旋转的时候,Z轴旋转180°,因为字是倒着的*/
}

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8
本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

  • ** 左侧面 ** - "":
    • origin以right为基准,left负元素的宽度,rotateY轴旋转90deg;
.cube-inner .single-side.s5{
    /*s5左侧*/
    left:-200px;top:0;
    background: radial-gradient(circle, rgba(255,255,255,.88),rgba(33,33,33,1));
    background: -webkit-radial-gradient(circle, rgba(255,255,255,.88),rgba(33,33,33,1));
    transform-origin:right;
    -webkit-transform-origin:right;
    transform:rotateY(-90deg)
    -webkit-transform:rotateY(-90deg)
}

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

  • ** 右侧面 ** - "":
    • 同理右侧,与左侧正好相反;
.cube-inner .single-side.s6{
    /*s6右侧*/
    right:-200px;top:0;
    transform-origin:left;
    -webkit-transform-origin:left;
    background: radial-gradient(circle, rgba(255,255,255,.88), #f00);
    background: -webkit-radial-gradient(circle, rgba(255,255,255,.88), #f00);
    transform:rotateY(90deg);
    -webkit-transform:rotateY(90deg);
}

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

小结 : 嗯,以上魔方的6个面的绘制过程,基本已经完成,主要在在于transform-originrotatetranslate等属性的应用,但为了让它更炫酷一些,我们还要给边角加一些光感。

∙ 添加高光 :
  • 细心的宝宝,前面的布局应该已经发现了,每一行布局的p标签里,都多套了一层span,就是为高光光感,埋下的伏笔,一个平面正方形有四个边,after、before只有两,那么肯定要再套一层,当然方法很多,比如直接用border也是可以的,但比较麻烦,我就选择了现在要讲的这种:
  • after、before设置1px的边框,设置一个线性渐变,中间是白色,两断是过渡到透明的,这样高光就有了,来看一组图吧:

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8
本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

∙ CSS 360°旋转 :
  • 上面是一个鼠标经过的过渡动画,可以看出立体效果是已经有了,接下来就写一个CSS animation的动画,让它360度旋转,每个角都能看到,这样会显的很666;
  • animation 配合 keyframes 使用,请看代码示例:
.cube .cube-inner{ 
  /*-webkit-transform:rotateX(180deg) rotateY(0deg) ;*/
  animation: elfCube 10s infinite ease-in-out;
  -webkit-animation: elfCube 10s infinite ease alternate;
}

@keyframes elfCube {
  0% { 
    transform: rotateX(0deg) rotateY(0deg); 
  }
  50% { 
    transform: rotateX(360deg) rotateY(360deg); 
  }
  100% { 
    transform: rotateX(0deg) rotateY(0deg); 
  }
}
@-webkit-keyframes elfCube {
  0% {
   -webkit-transform: rotateX(0deg) rotateY(0deg); 
  }
  50% {
   -webkit-transform: rotateX(360deg) rotateY(360deg); 
  }
  100% { 
    transform: rotateX(0deg) rotateY(0deg); 
  }
}

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

∙ 跟随鼠标旋转 :
  • 说好的随着鼠标旋转呢??
  • 别慌,接下来就是带你装逼,带你飞的时候,
    • 首先我们要了解,鼠标在容器内所在的位置,X = e.pageX - ele.offsetLeft, Y = e.pageY - ele.offsetTop;
    • 同时要知道元素内的中心点:centerX = width/2,centerY =height/2;
    • 然后得出值:axisX = X - centerX,axisY = Y - centerY;
    • PS : 开始尝试想的是鼠标从哪个方向进入,得到它的角度,但发现旋转效果不明显 ,有兴趣的同学可以尝试一下:(((Math.atan2(Y, X) * (180 / Math.PI)) + 180) / 90),参考司徒大神的JS判断鼠标从什么方向进入一个容器;
    • 最后,给容器绑上事件:mouseovermousemovemouseout,鼠标进入时,暂停css的动画,不然会相互打架哦!

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,公众号:honeyBadger8

 ……
getAxisX(e){
  let left = this.cubeEle.offsetLeft;
  return e.pageX - left - (this.cubeW/2) * (this.cubeW>this.cubeH ? this.cubeH/this.cubeW : 1);
}
getAxisY(e){
  let top = this.cubeEle.offsetTop;
  return e.pageY - top - (this.cubeH/2) * (this.cubeH>this.cubeW ? this.cubeW/this.cubeH : 1);
}
 …………
 …………
run(){
  this.cubeEle.addEventListener('mouseover',(e)=>this.hoverOut(e),false);
  this.cubeEle.addEventListener('mousemove',(e)=>this.move(e),false);
  this.cubeEle.addEventListener('mouseout',(e)=>this.hoverOut(e),false);
}
hoverOut(e){
  //进入/离开
  e.preventDefault();
  this.axisX = this.getAxisX(e),
  this.axisY = this.getAxisY(e);

  if(e.type == 'mouseout'){ //离开
    this.axisX=0;
    this.axisY = 0;
    console.log("离开")
    this.cubeInner.className="cube-inner running";
  }else{
    this.cubeInner.className="cube-inner";
    console.log("进入")
  };
  let rotate = `rotateX(${-this.axisY}deg) rotateY(${-this.axisX}deg)`;
  this.cubeInner.style.WebkitTransform = this.cubeInner.style.transform = rotate;
}
 ……

结尾:

  • -webkit-perspective,
  • -webkit-transform-style,
  • -webkit-transform-origin,
  • radial-gradient、linear-gradient,
  • transform:rotate、translate、scale,
  • transition,
  • animation;
  • 以上就是今天为大家带来的分享,以及使用到的知识点的API,如文章中有不对之处,烦请各位大神斧正,
  • 文章源码获取-> blog-resource 👈
  • 想直接在线预览 👈

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8

作者:苏南 - 首席填坑官
链接:https://honeybadger8.github.io/blog/
交流群:912594095、公众号:honeyBadger8
本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮

做完小程序项目、老板给我加了6k薪资~

本文由@IT·平头哥联盟-首席填坑官(苏南)分享

  大家好,这里是@IT·平头哥联盟,我是首席填坑官——苏南(South·Su),今天要给大家分享的是最近公司做的一个小程序项目,过程中的一些好的总结和遇到的坑,希望能给其他攻城狮带来些许便利,更希望能像标题所说,做完老板给你加薪~

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

  今天是中秋节的第一天,假日的清晨莫名的醒的特别早,不知道为什么,也许是因为,昨晚公司上线的项目回来的路上,发现了个小bug,心里有些忐忑吧,一会偷偷先改了,让领导发现这个月绩效就没了~~~~

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

​  以上纯为扯淡,现在开始一本正经的装逼,请系好安全带,中间过程有可能会开车,请注意安全!!!!!

  最近这个项目跟团队小伙伴沟通在众多框架中最后选择了wepy,没有直接用原生的,小程序原生就……,大家都懂的,用wepy框架,给自己带来了便利,也带来了不少坑,但纵是如此,我还是怀着:“纵你虐我千百遍,我仍待你如初恋”的心态去认真把项目做好。

toast组件

  • toast组件,大家都知道,官方的api wx.showToast 是满足不了我们的需求的,因为它只支持 "success", "loading"两种状态,同时“ title 文本最多显示 7 个汉字长度”,这是官方原话,有图有真相哦,样式巨丑~

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

wx.showToast({
  title: '成功',
  icon: 'success',
  duration: 2000
})
wx.showModal({
  title: '提示',
  content: '首席填坑官∙苏南帅不帅?',
  success: function(res) {
    if (res.confirm) {
      console.log('用户点击确定,表示很帅')
    } else if (res.cancel) {
      console.log('用户点击取消')
    }
  }
})

wx.showModal的content的文字是不会居中的(现在不确定有没有扩展,可以设置),依稀记得有一次因为问题差点跟产品经理吵起来,让文字居中,我说最少要两小时,当时产品就炸了,什么鬼???让文字居中一下要两小时??两小时??两小时??呵呵~走了,后来就下决定自己封装了一个属于自己的toast组件,以下为部分核心代码:

<template lang="wxml">
    
    <view class="ui-toast  {{ className }}" hidden="{{ !visible }}">
        <view class="ui-toast_bd">
            <icon wx:if="{{ options.icon}}" type="{{ options.icon }}" size="40" color="{{ options.color }}" class="ui-toast_icon" />
            <view class="ui-toast_text">{{ options.text }}</view>
        </view>
    </view>
</template>

<script>
    import wepy from 'wepy';
    const __timer__ =1900;
    //方法以 : __XX__ 命名,因并入其他组件中后,可能引起方法名重复
    class Toast extends wepy.component {
            
        /**
         * 默认数据
         */
        data={
             list:[
                {
                    type: `success`,
                    icon: `success`,
                    className: `ui-toast-success`,
                },
                {
                    type: `cancel`,
                    icon: `cancel`,
                    className: `ui-toast-cancel`,
                },
                {
                    type: `forbidden`,
                    icon: `warn`,
                    className: `ui-toast-forbidden`,
                },
                {
                    type: `text`,
                    icon: ``,
                    className: `ui-toast-text`,
                },
            ],
            timer:null,
            scope: `$ui.toast`, 
            animateCss:'animateCss',
            className:'',
            visible:!1,
            options:{
                type: ``, 
                timer: __timer__, 
                color: `#fff`, 
                text: `已完成`, 
            }
        }
        /**
         * 默认参数
         */
        __setDefaults__() {
            return {
                type: `success`, 
                timer: __timer__, 
                color: `#fff`, 
                text: `已完成`, 
                success() {}, 
            }
        }
        /**
         * 设置元素显示
         */
        __setVisible__(className = `ui-animate-fade-in`) {
            this.className = `${this.animateCss} ${className}`;
            this.visible = !0;
            this.$apply();
        }

        /**
         * 设置元素隐藏
         */
        __setHidden__(className = `ui-animate-fade-out`, timer = 300) {
            this.className = `${this.animateCss} ${className}`;
            this.$apply();
            setTimeout(() => {
                this.visible = !1;
                this.$apply();
            }, timer)
        }
        /**
         * 显示toast组件
         * @param {Object} opts 配置项
         * @param {String} opts.type 提示类型
         * @param {Number} opts.timer 提示延迟时间
         * @param {String} opts.color 图标颜色
         * @param {String} opts.text 提示文本
         * @param {Function} opts.success 关闭后的回调函数
         */
        __show__(opts = {}) {
            let options = Object.assign({}, this.__setDefaults__(), opts)
            const TOAST_TYPES = this.list;
            TOAST_TYPES.forEach((value, key) => {
                if (value.type === opts.type) {
                    options.icon = value.icon;
                    options.className = value.className
                }
            })
            this.options = options;
            if(!this.options.text){
                return ;
            };
            clearTimeout(this.timer);
            this.__setVisible__();
            this.$apply();
            this.timer = setTimeout(() => {
                this.__setHidden__()
                options.success&&options.success();
            }, options.timer);

        }
        __info__(args=[]){
            let [ message, callback, duration ]  = args;
            this.__show__({
                type: 'text',
                timer: (duration||__timer__),
                color: '#fff',
                text: message,
                success: () => {callback&&callback()}
            });
        }
        __success__(args=[]){
            let [ message, callback, duration ]  = args;
            this.__show__({
                type: 'success',
                timer: (duration||__timer__),
                color: '#fff',
                text: message,
                success: () => {callback&&callback()}
            });
        }
        __warning__(args){
            let [ message, callback, duration ]  = args;
            this.__show__({
                type: 'forbidden',
                timer: (duration||__timer__),
                color: '#fff',
                text: message,
                success: () => {callback&&callback()}
            });
        }
        __error__(args){
            let [ message, callback, duration ]  = args;
            this.__show__({
                type: 'cancel',
                timer: (duration||__timer__),
                color: '#fff',
                text: message,
                success: () => {callback&&callback()}
            });
        }
        __showLoading__(options){
            wx.showLoading({
                title: (options&&options.title||"加载中"),
            });
        }
        __hideLoading__(){
            wx.hideLoading();
        }
        onLoad(){
            this.$apply()
        }
    }

    export default Toast;
</script>

调用示例:

<template>
    <view class="demo-page">
        <Toast />
        <Modals />
    </view>
</template>

<script>
    import wepy from 'wepy'
    import Toast from '../components/ui/Toast'
    import Modals from '../components/ui/Modals'
    import {fetchJson} from '../utils/fetch';

    export default class Index extends wepy.page {
        config = {
            navigationBarBackgroundColor: "#0ECE8D",
      navigationBarTextStyle:"white",
            navigationBarTitleText: ''
        }
        components = {
            Toast: Toast,
            Modals: Modals
        }
        methods = {
            tapToast(){
                this.$invoke("Toast","__success__",[`本文由@IT·平头哥联盟-首席填坑官∙苏南分享`]);
            }   
        }
    }
</script>

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

Storage (数据存储)

Storage (存储)在前端我们存储的方式,cookielocalStoragesessionStorage等这些,特性就不一一说明了,小程序里大家都知道,数据存储只能调用 wx.setStorage、wx.setStorageSync,相当于h5的localStorage,而 localStorage是不会过期的,这个大家都知道,而且在很多的面试中,面试官都会问到这个问题,怎么让localStorage像cookie一样,只存两小时、两天、甚至只存两分钟呢?今天带你解惑,让你在职场面试中又减少一个难题,这也是我们项目中一直在用的方式,小程序中也同样实用:

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

class storage {

  constructor(props) {
    this.props = props || {}
    this.source =  wx||this.props.source;

  }

  get(key) {
    const data = this.source,
          timeout = (data.getStorageSync(`${key}__expires__`)||0)

    // 过期失效
    if (Date.now() >= timeout) {
      this.remove(key)
      return;
    }
    const value = data.getStorageSync(key)
    return value
  }

  // 设置缓存
  // timeout:过期时间(分钟)
  set(key, value, timeout) {
    let data = this.source
    let _timeout = timeout||120;
    data.setStorageSync(key,(value));
    data.setStorageSync(`${key}__expires__`,(Date.now() + 1000*60*_timeout));
 
    return value;
  }

  remove(key) {
    let data = this.source
        data.removeStorageSync(key)
        data.removeStorageSync(`${key}__expires__`)
    return undefined;
  }
}
module.exports = new storage();

  其实很简单,大家看了之后就都 “哦,原来还可以这样” 懂了,只是一时没想到而已,就是个小技巧,每次在存储的时候同时也存入一个时效时间戳,而在获取数据前,先与当前时间比较,如果小于当前时间则过期了,直接返回空的数据。

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

接口API维护

  • **接口API的维护,**在没有nodejs之前,前端好像一直都在为处理不同环境(dev、test、uat、prd)下调用对应的API而烦恼,做的更多的就是用域名来进行判断,当然也有些高级一点的做法,后端在页面渲染的时候,存一个变量到cookie里或者在页面输出一个全局的api变量(建立在没有前后端分离的基础上),到了小程序同样也是如此,每次都要手动改环境,那么一个项目可能有不同的业务,要调用不同域名api,又有不同的环境区分,怎么维护会比较好呢??
env/dev.js
//本地环境
module.exports = {
    wabApi:{
        host:"https://dev-ali.southsu.com/XX/api/**",
    },
    questionApi:{
        host:"https://dev-ali.bin.com/question/api/**/question",
    },
    mockApi:{
        host:"https://easy.com/mock/594635**c/miniPrograms"
    },
    inWelApi: {
        host: "https://dev.**.com/Wab/api/escene/v2"   
    }
};
 
import dev from './env/dev'; //本地或开发
import uat from './env/pre'; //体验环境
import prd from './env/prd'; //线上


var ENV = "prd"; //'dev | uat | prd';
let _base_ = {
  dev,
  uat,
  prd
}[ENV];
var config = {
  ENV,
  baseAPI:{..._base_, env : ENV },
  appID:"wx*****b625e", //公司账号(指数)appid
  isAuthorization:true,
  'logId': 'gVDSMH****HAas4qSSOTb-gzGzoHsz',
  'logKey': 'pxFOg****Jn3JyjOVr',
  questionnaireNo:'z**Insu' // 问卷调查编号
};
export const __DEBUG__ = (ENV!="prd");
export default  config;
请求调用api处理的示例

import wepy from 'wepy'
import _login_ from './login';
import config,{__DEBUG__} from './config';
import 'wepy-async-function';
export const  fetchJson = (options)=>{
    /*
     *  请求前的公共数据处理
     * @ param {String}     url 请求的地址
     * @ param {String}     Type 请求类型
     * @ param {String}     sessionId 用户userToken
     * @ param {Boolean}    openLoad 开启加载提示,默认开启,true-开,false-关
     * @ param {function} StaticToast 静态提示方法 ,详细说明请参考 components/ui/Toast
     * @ param {Object}     header 重置请求头
     * @ param {Boolean}    isMandatory 是否强制用户授权,获取用户信息
    */

    StaticToast = getCurrentPages()[getCurrentPages().length - 1];
    let { url,openLoad=true, type, data={},header={}, ...others } = options||{};
    let sessionId = (Storage.get(__login__.server+'_userToken')||"");
    /*Start */
       
        var regExp = /\/(.*?)\//,
        hostkey = url.match(regExp)[1];
    let baseUrl = config.baseAPI[hostkey].host;
    url = url.replace(regExp, '/');

    /*End */

    __DEBUG__&&console.log('#--baseUrl:', baseUrl);
    __DEBUG__&&console.log('#--请求地址:', `${baseUrl}${url}`);
    __DEBUG__&&console.log('----------分割线---------------');
    openLoad&&StaticToast.__showLoading__();
    return new Promise((resolve, reject) => {
        return wepy.request({
            url:`${baseUrl}${url}`,
            method:(type || 'POST'),
            data,
            header:{
                "t9oken":sessionId,
                'content-type': 'application/json',
                // 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
                ...header
            },
            success:(res)=>{
                StaticToast.__hideLoading__();
                return resolve(resHandler(res,options));
            },
            error:(err,status)=>{
                StaticToast.__hideLoading__();
                return reject(errorHandler(err,options,err.statusCode));
            }
        });
    })
    

业务调用示例:

fetchJson({
	type:"post",
	// url:"/mockApi/service/XXX", 最后请求得到的地址是 https://easy.com/mock/594635**c/miniPrograms/service/XXX (域名不同环境不一样,在config里的 ENV baseAPI控制)
	data:{
		name:"苏南"
	},
	success:res=>{
		console.log("大家好,我是@IT·平头哥联盟-首席填坑官∙苏南",res)
	}
})

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

填坑时间了

填坑时间了wepy框架中每个组件内的生命周期回调 onload,只要是引入了组件,不管你视图有没有渲染,他都会执行,导致某些业务逻辑用不上它的时候也执行了产生异常(当然为个锅< 小程序 >肯定说我不背~^~ ),详细看链接:Tencent/wepy#975https://github.com/Tencent/wepy/issues/1386 ,不知道后面有没有人解决。

rich-text组件

  • **rich-text,**小程序的一个组件,虽然有那么一点点用处,但又不得不说到底要它何用啊?其它的我就忍了,a标签,a标签啊,属性没有,那还要它何用啊??你都不要我跳转,我还要用你吗?b、i、span、em……哪个我不能用?不知道设计这个组件的人是不是脑被驴踢了(愿老天保佑,我在这骂他,可千万别被看到了,哈哈~),又是业务需求后台配置的内容有链接,没办法,来吧,搞吧,往死里搞吧,一切的推脱都是你技术low的借口(你看,你看,别人的怎么可以跳转啊,别人怎么做到的?给我一刀,我能把产品砍成渣),所以有了后面的填坑:

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

<template>
	<view class="test-page">
			<button @tap="cutting">点击解析html</button>
			<view wx:if="{{result.length>0}}" class="parse-list">
					<view  class="parse-view" wx:for="{{result}}" wx:key="unique" wx:for-index="index" wx:for-item="items">
							<block wx:if="{{items.children&&items.children.length}}">
									<block wx:for="{{items.children}}" wx:for-item="child" >
											<text wx:if="{{child.type == 'link'}}" class="parse-link" @tap="goToTap({{child.link}})">{{child.value}}</text>
											<text class="parse-text" wx:else>{{child.value}}</text>
									</block>
							</block>
							<text class="parse-text" wx:else>{{items.value}}</text>
					</view>
			</view>
			<Toast />
			<Modals />
	</view>
</template>

<script>
	import wepy from 'wepy'
	import { connect } from 'wepy-redux'
	import Toast from '../components/ui/Toast'
	import Modals from '../components/ui/Modals'
	import {fetchJson} from '../utils/fetch';
	import Storage from "../utils/storage";

	function wxHtmlParse(htmlStr=''){
		if(!htmlStr){
				return []
		};
		const httpExp  =/(http:\/\/|https:\/\/)((\w|=|\?|\.|\/|\&|-)+)/g;//提取网址正则
		const aExp=/<a.[^>]*?>([(^<a|\s\S)]*?)<\/a>/ig; //a标签分割正则
		let cuttingArr = htmlStr.split(/[\n]/);
		let result = [];
		//有a标签的html处理
		let itemParse = (itemHtml='')=>{
				let itemCutting = itemHtml.split(aExp)||[];
				let itemResult = [];
				for(var i = 0;i<itemCutting.length;i++){
						let _html = itemCutting[i];
						if(_html!==''){
								let itemData = {
										value:_html,
										type:'text',
										class:"parse-text"
								};
								let matchTag = itemHtml.match(aExp)||[]; //再次匹配有 a 标签的
								if(matchTag.length){
										let itemIndex = matchTag.findIndex((k,v)=>(k.indexOf(_html)!==-1));
										if(itemIndex>=0){
												let link = matchTag[itemIndex].match(httpExp)[0];
												itemData.type = 'link';
												itemData.link = link;
												itemData.class = "parse-link";
										};
								};
								itemResult.push(itemData)
						}
				};
				return itemResult;
		};
		cuttingArr.map((k,v)=>{
				let itemData = {type : "view",class:"parse-view"};
				let isATag = k.match(aExp);
				if(isATag){
						itemData.children = itemParse(k);
				}else{
						itemData.value = k;

				};
				result.push(itemData);
				return k;
		}) ;
		return result;
	};
	export default class Index extends wepy.page {
		config = {
			navigationBarBackgroundColor: "#0ECE8D",
			navigationBarTextStyle:"white",
				navigationBarTitleText: '小程序解析数据中的a标签'
		}
		components = {
			Toast: Toast,
			Modals: Modals
		}
		data = {
			html:'大家好,我是苏南(South·Su),\n职业:@IT·平头哥联盟-首席填坑官,\n身高:176cm,\n性别:男,\n性取向:女,\n公司:目前就职于由腾讯、阿里、平安三巨头合资的一家互联网金融公司深圳分公司某事业部、,\n简介:宝剑锋从磨砺出 梅花香自苦寒来,认真做自己,乐于分享,希望能尽绵薄之力 助其他同学少走一些弯路!,gitHub:https://github.com/meibin08/,\n兴趣:跑步、羽毛球、爬山、音乐、看书、分享自己的微薄知识帮助他人……,\n其他:想了解更多吗?可以加入<a href="https://honeybadger8.github.io/blog/#/">386485473交流群</a>,也可以给我电话<a href="https://github.com/meibin08/">134XX852xx5</a> ,开玩笑啦',
			result:[]
		}
		methods = {
			cutting(e){
				this.result = wxHtmlParse(this.html);
				console.log(`result`,this.result);
				this.$apply();
			},
				
		}
			
	}
</script>

PS完整示例源码 来啦~,觉得不错记得 Star、StarWatch 哦,感谢!

今天的分享就到这里,写了蛮久,最近才在开始尝试写博客,新手上路中,文章中有不对之处,烦请各位大神斧正。如果你觉得这篇文章对你有所帮助,请记得点赞哦~,想了解更多?那就关注正文的公众号吧!

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮,公众号:honeyBadger8

作者:苏南 - 首席填坑官

链接:https://honeybadger8.github.io/blog/

交流群:912594095,公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明链接及出处。

全栈资源共享 一起成长 ,努力成为想成为的那个样子

全栈资源共享 一起成长 ,努力成为想成为的那个样子,视频、文档、电子书、小程序项目如何设置资源的防盗链?从入门到真实项目配置,首席填坑官∙苏南的专栏, 100+ 经典技术书籍,涵盖:计算机系统与网络、系统架构、算法与数据结构、前端开发、后端开发、移动开发、数据库、测试、项目与团队、程序员职业修炼、求职面试 和 编程相关的经典书籍

经常有群友在问,是否有学习的资源分享:视频电子书实战项目、其他资源等,想着为了感谢大家对于 我们IT平头哥联盟的支持和肯定,所以周末就果然放弃拒绝了漂亮小姐姐的邀请(本来是准备跟小姐姐一起去爬山的),在家整理了一些相关的资源,分享给大家:

笔试面试题:

面试题,这个肯定是大家每个人都需要的,所以写在最前,
主要有前端、JAVA、C++、Python、测试、大数据云计算等等方面的吧,
精选国内著名互联网,软件等IT公司的面试题包括但不限于百度,腾讯,微软,华为
中兴等企业,并根据岗位进行划分,分门别类的提供 研发工程师(程序员),测试工程师(QA),产品经理(PM)等经典面试题目,内容会不定期更新,欢迎持续关注。

👉公众号回复:"面试题"

前端攻城狮:

前端以前叫切图崽,随着互联网的发展干的的事情越来越多,业界人士都给点面子,人称:攻城狮,介于设计师、程序员之间的一个角色,主要是网站的前台代码实现,包括基本的HTML和CSS以及JavaScript/ajax,和现在比较流行的React、vue、angular等MVVM/MVC等框架。

👉公众号回复:"大前端"

Vue.js

Vue.js是一套构建用户界面的渐进式框架。
与其他重量级框架不同的是
Vue 采用自底向上增量开发的设计。
Vue 的核心库只关注视图层,并且非常容易学习,
非常容易与其它库或已有项目整合。

👉公众号回复:"vue"

Webpack

webpack是一款模块加载器、编译、打包工具,
能把js、css、页面、图片等各种资源,进行模块化处理。

👉公众号回复:"webpack"

Angular

大型电商分布式系统,
课件教程源码作业,
从数据库设计开始,
手把手教学.
👉公众号回复:"angular"

小程序实战

小程序实战分享,
实战中进步,其实官方文档已经很详细了,

👉公众号回复:"小程序实战"

HTML / CSS

超文本标记语言,标准通用标记语言一个应用。
“超文本”就是指页面内可以包含图片、链接,甚至音乐、程序等非文字元素。

👉公众号回复:"html"

JavaScript

JavaScript一种直译式脚本语言,
是一种动态类型、弱类型、,
基于原型的语言,内置支持类型。,
最早是在HTML网页上使用,,
用来给HTML网页增加动态功能。

👉公众号回复:"JS"

Git / SVN

Git (是一个开源的分布式版本控制系统
可以有效、高速的处理从很小到非常大的项目版本管理。

SVN 是Subversion的简称,是一个开放源代码版本控制系统,
相较于RCS、CVS,它采用了分支管理系统,
说简单一点SVN就是用于多个人共同,
开发同一个项目,共用资源的目的。

👉公众号回复:"git"、"SVN"

java资源

Java是一门面向对象编程语言,
不仅吸收了C++语言的各种优点,
还摒弃了C++里难以理解的,
多继承、指针等概念,
因此Java语言具有功能强大和简单易用两个特征。

👉公众号回复:"java"

Mybatis

MyBatis 本是apache的一个开源项目iBatis, 是一个基于Java的持久层框架。
iBATIS提供的持久层框架包括SQL Maps和Data Access Objects

👉公众号回复:"Mybatis"

Spring

Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,
因此它将面向接口的编程**贯穿整个系统应用,
Spring是于2003 年兴起的一个轻量级的Java 开发框架
由Rod Johnson创建。

👉公众号回复:"Spring"

Spring MVC

Spring MVC属于SpringFrameWork的后续产品,已经融合在
Spring Web Flow里面。Spring 框架提供了构建
Web 应用程序的全功能 MVC 模块。

👉公众号回复:"Springmvc"

Spring Cloud

Spring Cloud是一系列框架的有序集合。
它利用Spring Boot的开发便利性巧妙
简化了分布式系统基础设施的开发

👉公众号回复:"Spring cloud"

Spring Boot

Spring Boot的开发便利性巧妙.
简化了分布式系统基础设施的开发.

👉公众号回复:"Spring boot"

Python

Python, 面向对象的解释型计算机程序设计语言,
Python语法简洁清晰,强制用空白符作为语句缩进。

👉公众号回复:"Python"

SSM框架

是Spring + Spring MVC + MyBatis的缩写
这个是继SSH之后,目前比较主流的Java EE企业级框架
适用于搭建各种大型的企业级应用系统。

👉公众号回复:"SSM"

区块链

被称为2018最火新技术,
区块链是分布式数据存储、点对点传输共识机制,
加密算法等计算机技术的新型应用模式,也被称之为分布式账本技术,是一种互联网数据库技术,其特点是去中心化、公开透明,让每个人均可参与数据库记录。

👉公众号回复:"区块链"

机器人

机器学习是一门多领域交叉学科
涉及概率论、统计学、逼近论、凸分析
算法复杂度理论等多门学科

👉公众号回复:"机器人"

计算机视觉/深度学习

计算机视觉是.指用摄影机和电脑代替人眼对目标进行识别
跟踪和测量等机器视觉,并进一步做图形处理

深度学习的概念源于人工神经网络的研究。
含多隐层的多层感知器就是一种深度学习结构。

👉公众号回复:"计算机视觉"、"深度学习"

BAT算法精讲

算法(Algorithm)是指解题方案的准确的描述,
是一系列解决问题的清晰指令,
一个算法的优劣可以用,
空间复杂度与时间复杂度来衡量。

👉公众号回复:"BAT"

数据结构

作为一名合格的程序员必须要深入理解的,
最为重要的计算机课程为《计算机组成原理》、《计算机体系结构》、《操作系统原理》、《编译原理》、《数据结构》、《算法设计》

👉公众号回复:"数据结构"

Oracle

甲骨文公司,
一款关系数据库管理系统

👉公众号回复:"Oracle"

简历模板

在求职过程中,简历是淘汰率最高的一环。
据统计:86%求职的简历在HR眼里都是不及格的
如果你的简历不能秒杀HR,突出你的亮点,就只能无奈地被HR秒杀,注意下面几个方面,迈出完美的第一步。

👉公众号回复:"简历"

Java基础 、分布式

JAVA的一些基础知识,适合小白入门或弥补前端同学后端知识的空缺。

redis,lucene dubbo activemq

👉公众号回复:"java基础"、"java分布式"

Linux运维全套

Linux运维即linux运维工程师;
Linux是一套免费使用和自由传播的类Unix操作系统
是一个基于POSIX和UNIX的多用户、多任务、
支持多线程和多CPU的操作系统
是一个性能稳定的多用户网络操作系统。

👉公众号回复:"运维"

Node.js

Node.js是一个Javascript运行环境(runtime)
发布于2009年5月
由Ryan Dahl开发
实质是对Chrome V8引擎进行了封装。

👉公众号回复:"node"

shiro

Apache Shiro是一个强大且易用的Java安全框架
执行身份验证、授权、密码学和会话管理。

👉公众号回复:"shiro"

c#

C#是微软公司发布的一种面向对象的,
运行于.NET Framework之上的高级程序设计语言。
👉公众号回复:"c#"

Query

虽然现在有些过时,但对于一些新入门的同学,还是有很大用处的,
jQuery是一个快速、简洁的JavaScript框架,
是继Prototype之后又一个优秀的 JavaScript代码库
jQuery设计的宗旨是“write Less,Do More”
即倡导写更少的代码做更多的事情。

👉公众号回复:"jQuery"

测试

再完美的程序,也少不了测试同学的一步步测试,
分享一些测试领域的资源,GET新技能后给开发同学多提点bug,哈哈~

👉公众号回复:"测试"

电子书籍

整理了一些电子书、前/后端、测试的都有,为了方便大家随时随地阅读,业余时间撸了个小程序可直接在线阅读,
如果里面没有你想看书籍,可以反馈给我,会不定期更新上去。
程序员必备的书籍有哪些? - 知乎,编程书籍

CSDN资源

!!预告,为了感谢大家对我们的支持,后续预计会开通了CSDN的积分下载年度超级会员,也就意味着后续大家需要下载CSDN的资源可以联系我,我将免费为大家下载,只为给各位读者提供更好的服务,更多的福利!。
欢迎大家留意公众号信息、或群通知,进群请加我微信:su-south!

如果您觉得不错的话,欢迎分享和点赞、关注我们公众号:IT平头哥联盟,您的支持是我最大的动力!

IT平头哥联盟,苏南的专栏,前端开发

热门推荐:

作者:苏南 - 首席填坑官

链接:http://susouth.com/

交流:912594095、公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

面对团队解散 我们该何去何从?

小程序项目如何设置资源的防盗链?从入门到真实项目配置,首席填坑官∙苏南的专栏

就在刚才,下班回家的路上,看到群信息,说:听说、京东裁员了~

图片来源于掘金

就在上月,也一度被传的沸沸扬扬的:阿里京东华为相继被曝停止社招,新闻也是满天飞舞,不管是裁员,还是停止社招,这些事情没有落在亲身经历,没有落在自己身上我们都会觉得不痛不痒,毕竟一个旁观者,永远无法感受当事人的喜怒哀乐~。

俗话说:人无远虑 必有近忧,假如当你遇上裁员,又该如何面对~

今天看到这个新闻,第一时间想到的是自己,当然啦,大家别慌,我没有被裁,不用紧张,

工作几年下来相信大家或多或少遇到过一些要么自己、要么身边的朋友、同事,都有过一些欠薪、公司倒闭、团队解散甚至裁员的事。

嗯,还有刚刚过去的掘金

嗯,还有刚刚过去的掘金

往事不堪回首

为什么说想到自己呢?我没有被裁过,但**团队解散过**,这个事情得从去年说起:

从毕业到现在,工作也有些年头了,这些年多多少少也遇到过一些机会,

  • 2014年中旬,一个阿里PHP大佬,自己创业,做婚庆的电子请柬,记得那个时候特别流行H5移动微场景制作,某企秀、兔*,之类的公司应风而起,包括到现在好像也还做的不错,当时是兼职业余时间帮做一些前端工作,一直持维了近一年时间合作的都很不错,后面更是亲自邀请我让去他公司玩一下,来回车票都包销(公司在湖南),再后来提出让全职去他公司(合伙性质),基础保底年薪是20W,但最近因为不在深圳、觉得项目并不是特别看好等原因放弃了~

  • 15年左右,当时是在个游戏公司,有个领导出去创业,当时拉了几个团队的同事,其中也有我,是的,结果你已经猜到了,我最后没有去,主要受当时所在的游戏公司部门的产品经理特别变态、真的特别变态,天天加班到12点,早上晚到一会,开会点名批评(公司是有这个福利的,加班晚第二天能晚到),说我们部门不能搞特殊(到底谁在搞特殊??),要按时上班,当时一度特别烦躁,想着去了创业公司……。

  • …… 中途也有小米公司,某部门新组件的研发负责人的邀请,

  • 这些都是后话了,就在去年、对去年,今天都还清楚的记得2018-07-26,这天去了前面提到的解散的公司报到,当时也是之前某公司的领导找到我,说他将出任某公司研发总监职位,新成立的子公司,问我是否有兴趣一起,在考虑过综合因素后最后决定去了,主要是公司也在深圳、薪资是有涨幅的,更重要的是了解了一下母公司的背景(挺强、有干爹的那种``)资金方面不会出问题,钱都不是问题了,未来钱`途还是问题吗?

回头想想这些年,因为种种原因,错过了很多机遇,随着年龄的增涨,是时候博一下了(哪怕是失败,自己也并不会损失什么),跟几个不错的朋友也讨论过后,也认为觉得一次不错的机会,所以就欣然前往了,

公司是从0开始的,

一切都是从0开始的,

包括第一行代码都是从0开始写的,每一天都是从早到晚的在忙,赶着把产品上线,几乎每天都在加班,但团队的每个同事们都毫无怨言,因为这些都是在已知的预料之中。

日复一日,产品迭代了又迭代、APP、PC端、小程序等都陆续上线,慢慢走上正轨,业务也开始接入,团队成员都感觉看到了胜利的曙光。

然而,人在家中坐、锅从天人上来,暴风雨来临的总是显得特别的宁静,在3月初中旬左右(往事不堪回首~),周末还约了同事一起穿越了南澳东西涌

东西涌有毒,回来公司就没了~😂

新一周周一,一如往常的去公司上班,刚坐来,准备大显身手,开始元气满满的一天,领导发来消息让去他办公室一趟,后面说了些公司的情况:

  • 大概意思是总部对于子公司业务、管理层的不满,做采取一些措施,但这个不会影响到下面员工等等之类的,他可能也会有所变动等,提前跟我说一下。
  • 然后又过了没有几天,领导叫去了全部leader,说总部出于某些原因,子公司可能不会再投资了~~,是不是很棒棒??晴天霹雷~、刺激不??第一反应是先来让几个深呼吸、再呼吸,然后轻轻的扶住墙、嗯,扶住墙~

上右图为公司一同事当时的感慨~

事情已经这样了,后面也就不用再继续讲了,我没有遇到过裁员,但我经历了团队解散,是不是很优秀??

看到这里,可能有些同学会认为我的经历的些扯了,合伙是假,压榨、利用、……等是真的;但我想说:如果你遇到这样的事情,应该值得高兴,至少还有被压榨、利用的价值,换个角度讲,凡事没有绝对的公平,任何事如果没有一定的利益关系捆绑,都难以长期维持,所以不存在利用一说。

至少我觉得自己很棒,能得到大家的认可。

如果你连利用的价值都没有,那么恭喜你,裁员标签,可能就要落在你身上了,

前路在何方?

说了这么多,其实是想表达不管是裁员、欠薪、还是团队解散,当这样的问题发生时?我们该怎么做、怎么做、怎么做呢??
我只能说送上四个字:## 未雨绸缪 ##

  • 首先,好好跟公司沟通,维护好自己应有的权益,哪怕仲裁,这点不可妥协~;

  • 其次 ,不要因为这种小意外,而否定了自己能力,自信的人最美(你永远是最棒的),此处不留爷 自有留爷处。

  • 然后 好好静下心来,好好复习准备下一份工作,只要你活好,走到哪里都不怕,条条大路通罗马,你的星光大道就在前方;

  • 最后,也是最重要的,工作之余,我们也应该多关注一些技术的发展趋势,不断的学习,强化自己的专业技能,才能不会被时代的洪水淹没。

  • 特别是近两年,互联网一直处理一个高速持续的过程发展,前端更是如此:ReactVueAngular等,甚至还有衍生出的 React Navite 、H5的新特性dialogshowModal()等等,常常会有网友在调侃老了、学不动了,调侃的同时却又阐述着无奈,迫于生活的压力,不得不提速前行。

​未来的路我们是无法预知的,谁都不知道明天将会发生什么,我们能做的就是未雨绸缪,在事情未发生之前,自己多做、多想、多学。

一入IT深似海,从此妹子是路人,最近不是React、Vue都发布了新版本吗?好好学吧🤪。

以上来自一个年近30的码农心声,给自己一点危机感。

欢迎关注:IT平头哥联盟,支持我们。

码农书籍,一起阅读,一起进步,用心分享 做有温度的攻城狮,苏南的专栏

作者:苏南 - 首席填坑官

链接:http://susouth.com/

交流:912594095、公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

博客留言区

  • @IT·平头哥联盟主要分享前端测试 等领域的积累,文章来源于(自己/群友)工作中积累的经验、填过的坑,希望能尽绵薄之力 助其他同学少走一些弯路,欢迎加入我们一起分享您的心灵历程,也可以给我们投稿哦💯~

Eruda 一个可能被人遗忘的移动端调试神器

Eruda 是一个专为手机网页前端设计的调试面板,类似 DevTools 的迷你版,其主要功能包括:捕获 console 日志、检查元素状态、捕获XHR请求、显示本地存储和 Cookie 信息等等。,首席填坑官∙苏南的专栏 交流:912594095、公众号:honeyBadger8

引言

​  日常工作中再牛逼的大佬都不敢说自己的代码是完全没有问题的,既然有问题,那就也就有调试,说到调试工具,大家可能对于fiddlerCharleschrome devtoolsFirebug、还有Safari远程调试等比较熟悉,甚至有些是我可能也没有用过的;

  这里喷一句吧,谁都别给我提IE啊,IE那个不叫调试工具,那叫坑爹神器,话说最近不是又甩锅了,把自己的革命老根据地都甩了。

  俗话说预先善其事必先利其器,今天想给大家分享的是一个可能被人们忽略的小工具,为什么说被人们忽略呢?因为发现github上它才4.6k Star、457 ForkWatch 173次,也就是说千万开发者中知道它的人可能不超过5w,于是决定分享一波,此文重在引导,希望能帮大家开发中带来一点点便利、效率的提升

在日常的移动端开发时,一般都是试用chrome浏览器的移动端模式进行开发和调试,只有在chrome调试完成,没有问题了才会上到真机测试,移动端,宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8

!> 这里是IT平头哥联盟,我是首席填坑官苏南,用心分享 做有温度的攻城狮。

Eruda是什么?

  Eruda是什么?Eruda 是一个专为前端移动端移动端设计的调试面板,类似Chrome DevTools 的迷你版(没有chrome强大 这个是可以肯定的),其主要功能包括:捕获 console 日志、检查元素状态、显示性能指标、捕获XHR请求、显示本地存储Cookie 信息、浏览器特性检测等等。

  虽说日常的移动端开发时,一般都是在用Chrome DevTools浏览器的移动端模式模拟各种手机型号来进行开发和调试,确保功能/页面展示等都没有问题了,才会提交测试;

  但是前面都讲了,只是模拟模拟,当下手机品牌可算是千千万,手机中各种类浏览器,甚至APP都有自己不一样的特色 腰间盘突出,有的还特别突出,有病我们得给它治啊,不然测试、产品、需求、领导都不会放过我们,比如下图场景。

首席填坑官∙苏南的专栏 交流:912594095、公众号:honeyBadger8

如何使用?

  • 它支持npm方式的,这个是不是很开心??
  • 外链,没错,就是外链的形式引入,对于它,我觉得npm的方式没有什么太大意义,直接以外链的引入更方便,也能减少项目资源包的大小,更便于控制是否要加载这个资源。
方式一,默认引入:
<script src="//cdn.jsdelivr.net/npm/eruda"></script>
<script>eruda.init();</script>

方式二,动态加载:

__DEBUG__ && loadJS('http://cdn.jsdelivr.net/eruda/1.0.5/eruda.min.js', ()=>{
  eruda.init();
});//苏南的专栏 交流:912594095、公众号:honeyBadger8

方式三 ,指定场景加载:
//比如线上 给自己留一个后门,
//我们一般的做法是喜欢给某个不起眼的元素,添加一个点击事件,要点它十次、八次以后才开启 debug 模式;
;(function () {
    var src = 'http://cdn.jsdelivr.net/eruda/1.0.5/eruda.min.js';
    if (!/eruda=true/.test(window.location) && localStorage.getItem('active-eruda') != 'true') return;
    document.write('<scr' + 'ipt src="' + src + '"></scr' + 'ipt>');
    document.write('<scr' + 'ipt>eruda.init();</scr' + 'ipt>');
})();

方式四 ,npm:
 npm install eruda --save

…… 加载的方式很多

小而美

  • 这里小,不是指它的包小啊,知道它的同学都知道,其实它的包并不小(约100kb gzip);
  • 100kb不小了,用形容妹子的话来说就是:丰满,直接说它胖,你就死定了;
  • 这里的小而美是指小巧功能也强大,界面也好看;
  • 说了这么多 来看看它到底长啥样吧:

做移动端Web开发的一大痛点就是,在真机运行下无法查看console.log日志和其他信息如网络请求、显示本地存储等信息。如果网页是运行在手机浏览器中还算好,可以把网址在电脑上打开查看console信息,但是如果是做APP的内嵌H5页面,那就只能靠开发阶段在浏览器模拟环境中尽量没有Bug,公众号:honeyBadger8

功能清单

console

  • console 的作用就不用废话了,大家都懂;
  • 早期在console诞生之前,我们的调试功能都是alert过多,包括现在的移动端,在手机上我们想看到参数值、数据、节点等都以alert打印为多数,但过于粗暴、而且一不小心有可能带到线上去了;
  • eruda 能帮我们解决这个问题;所有的日志、错误都能帮我们捕获到
  • 甚至我们还能像chrome,直接在控制台执行js代码;

微信开发必备】h5开发调试,利器Eruda ,公众号:honeyBadger8

Elements

  • eruda 它没有在PC端这么直观,但也因为在移动端展示的方式局限性,
  • 它能把每一个父节点下的每一个子节点全部列出来;你点击某个子节点时,列出当前节点全部的属性、样式、盒子模型等;
  • 查看标签内容及属性;查看Dom上的样式;支持页面元素高亮;支持屏幕直接点击选取;查看Dom上绑定的各类事件。
  • 甚至也能使用Plugins 插件,做到跟PC端一样,形成 dom tree;

使用神器eruda 进行移动端调试-,公众号:honeyBadger8
PC、Mobile调试节点对比

Network

  • 现在的项目大多都是前后端分享的形式了,前端处理的业务越来越多、各种请求资源等;
  • 干的越多承担责任也越多、锅也越多,又大又平的那种哦~
  • 所以 Network 的必要性不言而喻,它能捕获请求,查看发送数据、返回头、返回内容等信息,它对于我们平时前后端联调出现的问题定位是有很大帮助的,比如:后端说你请求参数少了,前端你看了代码逻辑没有问题,但在手机上就是调不通,Network 能很直接明了的看到你请求带了什么。

The Hypertext Transfer Protocol (HTTP) is an application protocol for distributed, collaborative, ... HTTP is designed to permit intermediate network elements to improve or enable communications between clients and servers,vConsole便是这样一款很棒的移动端DevTools工具,由大厂企鹅出品。但本文把他定位为男二号,今天的主角男一号是:Eruda!vConsole的同类。,PC、eruda 数据请求对比

Resources

  • 它跟 Chrome Devtools 里的 Application + Source,两者的结合体;
  • Resources 它能查看 Cookie、localStorage、sessionStorage等信息,并且还能执行清除操作(Application);
  • 它还查看当前页面加载脚本及样式文件;查看页面加载过的图片等资源(Source);
  • 好吧,感觉说的再多,也不如上图直接:
    有哪些关于前端开发技术HTML、CSS、JavaScript 等值得推荐的书籍? 从菜鸟到大 ... 锋利的jQuery第2版 【书籍】. Js知识点. JavaScript深入系列15篇正式完结!Resources 功能分析

Sources/Info

  • Sources:查看页面源码;格式化html,css,js代码及json数据。
  • Info:主要输出URL信息及User Agent;及其他的一些手机系统信息,同时也支持自定义输出内容哦。

通常写前端页面都在Chrome浏览器的开发模式下进行调试,但是写放在移动端的H5页面时,有时候会遇到在Chrome上调试没有问题,但是在手机的浏览器上有问题的情况;也有的页面是需要放在微信公众号中的,调用了微信JSSDK的方法,必须得通过手机上的微信内置浏览器才能使用,这个时候如果遇到了报错,只能够通过alert一步一步地定位问题。今天发现了一个好用的可以在手机浏览器上直接定位问题的插件:eruda.js,Resources 功能分析

高阶用法

  • 以上刚才介绍的是它的一些基本的功能,也是我自己在工作中用的较多的;
  • 最近发现新版本功能要强大不少,之前一直用的1.0.5,好像是没有插件这一项的;
  • 大概看了一下,都蛮强大,包括上面的Dom tree,插件这部分并没有都实际应用过,所以也就不打肿脸充胖子了,有兴趣的同学可以自己看看。
  • 如果觉得已经的插件都满足不了你的需求,它还支持自定义插件自己编写。

These share data are from my usual work and learning,hoping to help you,If you like you can star. Javascript. Article, Article. Javascript深浅 ,Resources 功能分析

结尾:

  以上就是今天给大家带来的分享,工作中用了蛮久,挺方便的,对于定位移动端的疑难杂症问题、甚至留下后门定位线上问题都有很大帮助,如文中有理解不到位之处,欢迎留言指出。

  线上问题我们一般的做法是喜欢给某个不起眼的元素,添加一个点击事件,要点它十次、八次以后才开启 debug 模式;

  上面二维码确实是真实的官方Demo,不用担心有套路,也有链接:https://eruda.liriliri.io/

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:IT平头哥联盟

其他

作者:苏南 - 首席填坑官

链接:https://blog.csdn.net/weixin_43254766

交流群:912594095[资源获取/交流群]、公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系IT平头哥联盟获得授权,非商业转载请注明原链接及出处。

互联网'凛冬',看大厂HR怎么说~

先简单的介绍一下我自己以及文中所提及的学习大纲。过去的5 年里,我一直在做全栈开发,现担任tajawal 的总工程师,于2018年12月做个小小的前端技术分享,分享包括但不限于:Web 前端发展史、JQuery 与Vue 的比较、Vue/React/Angular 的比较、前端开发经验的,Taro 一套代码多端运行的框架,带你掌握Taro开发基本语法,以及项目开发 · React. ... 基于weex前端开发框架的使用,开发出一个接近原生应用体验的案例

写在前面的话

  最近互联网朋友圈充斥着一股恐慌的气息。是的,如果你是圈内人,恐怕已经猜到了,席卷整个行业的CAI员、降薪席卷业内。以滴滴程维宣布“公司高管无年终奖、普通员工年终奖减半”上微博热搜为标志,全民都感受到“互联网的寒冬”来了。

  想写这篇文章,是因为一位多年的好友(资深程序猿)昨天向我抛出了一个问题 —— 以资深HR的角度说说,如何在这场风波中不被裁员

  当然,这不是我今天要讲的问题,因为任何措施都无法保证做到这一点,到最后也只会归结为简单的一句话——实力至上。这人人可见的道理,写出来就是一碗无用的毒鸡汤,想来也不必浪费各位的眼球了。反之,如果你的实力确实不容小觑,这个担心也就自然多余了。

  但实际情况必然不是如此的,人无完人,没有人是保证立于不败之地的。既然没有一劳永逸的办法,那我想换一个角度来谈谈我的想法。与其终日惶惶,等待那一纸不知何时会降临的“裁决书”,不如主动出击,提前做好应急准备。如此,你便能掌握主动权,不管是主动寻求更好的机会,亦或是真的拿了“抚慰金”,都可以游刃有余,无后顾之忧。

  本人作为一名HR,万不敢称资深,只是呆过几年大型央企和大型互联网企业,聊有一点自己的看法罢了。在此,从HR 的角度,讲讲换工作过程中的一些事情,希望在你用得上时能有一些参考意义,便自觉功德无量了。

本文由IT平头哥联盟特邀某大厂资深HR,从HR的角度讲讲如何完美渡过“凛冬”
公众号:honeyBadger8,群:912594095

人生的路~,React是Facebook开发的一款JS库,那么Facebook为什么要建造React呢,主要为了解决什么问题,通过这个又是如何解决的?

一.确定目标

  求职者经常会自问或被问到这样一个问题:你想要一份怎样的工作?许多人都没有认真去思考过这个问题或者比较含糊,更多的是一种感觉,甚至会说随便。所以,在找工作的各个阶段就会表现出各种迷茫、纠结,这便是我们常说的“无头苍蝇”。一旦成为这种生物,你便会到处乱窜,撞到大运的可能性自然是少之又少的,结果只能是撞得满头包,然后随便找个“还可以”的工作,继续将就,在以后的日子里继续重复“不满—辞职—找工作”这一不断重复妥协的过程,最后职业生涯中断,技能无法沉淀,职场资源得不到积累,领导信任需要重新建立,永远在基层岗位徘徊,待你人到中年,还奋斗在码农一线,人家也该嫌弃你不如年轻少壮了。

  因此,想好“你想要一份怎样的工作”这一问题,是关乎你整个职业生涯的大计。那么如何确定呢?我认为应该分两个阶段——投递简历前和拿到offer后。投递简历前确定目标是为了提高找到合适工作的可能性,而拿到offer后进一步明确目标是为了提升你的选择正确的可能性。本文的行文思路是寻求一个新机会的整个过程,因此先从投递简历前建立目标谈起,拿到offer后的选择问题后文有详谈。

  这一阶段的目标不需要是具体而清晰的,不可走两个极端——广撒网和一条道走到黑。

  广撒网会带来两个后果:一是这会带来简历无针对性,泛泛而谈,获得好的面试机会的概率不大;二是一些不太好的机会找上门来,影响你对自我的定位或者因盲目地想积攒面试经验而浪费时间。
 
  一条道走到黑,指的是把自己限得太死,只选自己熟悉的企业或者只选一两家死磨硬泡。这也是不可取的,世界之大无奇不有,机会很多,只是你可能不知道有这个机会或者不知道这个机会你可以。所以还是鼓励多尝试。

  那这就有一个度的把握的问题,如何做到既不把自己限在死胡同而又避免到处乱窜,这不是一个艺术问题,而是可以通过确定目标去做到的。我们知道,我们在投递简历过程中,可以大概了解到的信息主要有公司简介、岗位JD和岗位薪资范围。所以,我们的目标范围就选择我们可以获取到的信息作为参考。

  总结来看,行业有地位、工作内容有挑战、薪资范围可期待,那么就值得尝试。其他机会果断放弃。如果不放心,以一周为期,对展示在面前的机会进行初步分级。HR处理简历一般都会在一周内完成,如果一周内没有太多面试机会,再补充投递第二级别的企业。

二、准备简历

  在这里要聊的不是如何做一份漂亮的简历,因为这个你大可以网上找一个模板,都很棒。而且,在网上投递阶段更多的是在线简历,都有固定的式样。所以更多的要聊的是内容的呈现。有几个要点。

  一是要条理清晰,突出重点。工作经历和项目经历是简历的重点,在叙述时按点呈现,言简意赅的讲清楚做了什么,自己发挥了什么作用。HR筛选简历实际上就像改卷,是找亮点的过程,是按点匹配的过程。招聘平台“简历匹配”的计算也是参照这一逻辑。

  二是切忌万金油式的简历。针对不同的企业和岗位,选择不同版本的简历。例如,国企对所获荣誉等比较看中,可以选择一定的篇幅来呈现自己的获奖经历。面对不同的企业,选择不用的简历,呈现你想呈现的重点。

  三是不要贪心。简历只需要做到90分即可。十分理解每个人尽善尽美的态度,特别是这种关乎前途命运的时候,争一把当然是对的。但我认为,只需要90分,让你获得可以面试的机会就可以了,因为这只是第一步,重头戏在面试。如果你的简历100分,会拔高企业对你的期望,面试下来就会转而失望。反之,企业会从你身上发现更多惊喜。不要过早地摊牌。

IT平头哥联盟程序员,首席填坑官∙苏南的专栏,React还是Vue:你该如何选择?,人生之尺 量人量己

三、面试

  前期讲了很多,但面试却是最具决定性的。社会招聘过程中,大部分企业往往采用结构化面试,因此这里主要以结构化面试场景进行一些技巧介绍。其他面试形式以后有机会再谈。

  采用“三步走”战略,即准备阶段面试阶段结束阶段

准备阶段:

1.对企业、岗位做初步了解,以表示自己对企业的尊重和对机会的重视;

2.大致了解企业文化,以做出服装和面试过程中表现等风格的应对。如果是国企,尽量穿正装应试;在摸不清楚的情况下,亦可着正装面试,还是摆明态度问题。
做好以上两点,基本上印象分就可以拿到了。接下来到了面试问答环节。

面试阶段:

1.自我介绍言简意赅。不超过两分钟,一定要条理清晰,不可太过冗长。讲清楚个人基本情况、工作成绩即可。而在工作成绩展现方面也应根据不同的企业调整侧重点,比如国企多看中企业认可度,因此多展现做了什么获得了什么荣誉;私企则强调效益,可以进行一些数据化的呈现。

2.回答问题采用“总分”或“总分总”的形式。面试就是一场“作文”,摆明你的观点,再分点阐述,会使你显得富有条理。

3.把简历内容做实。这个有些隐晦,但“你懂的”。如果你要写在简历上,那么一定要经得住问。

4.向面试官推荐自己。多数面试官会采用多听面试者说的心态进行面试,以期获得意外收获。那我们可以主动掉入他的“陷阱”,讲一些我们希望他听到的信息。那自然是我们的优点。所以可以在面试过程中讲一些自我评价,9分优点,1分不痛不痒的缺点,同时准备好案例佐证,因为面试官一定会问:“你这样评价自己,有什么实际案例吗?”

5.不要啰嗦。推荐自己,但不是说得越多越好,问题回答完了即可。多余的叙述会造成不沉稳的印象,或者会显得总结概括能力不佳,也可能言多必失,说出一些你不想呈现的点。

6.期望薪资怎么回答。说出内心真实的想法即可,特别是私企,这会成为给你定薪的重要参照。也可以略高于期望,以此探一探对方的反应。如果确实不太确定,可以回答相信贵公司会给出一个与我能力相匹配的薪资。

近两年前端技术的发展如火如荼,大量的前端项目都在使用或转向Vue 和React 的阵营,由前端渲染页面的单页应用占比也越来越高,浅谈react,angular,vue 及其部分前端框架· w3c,程序员,首席填坑官∙苏南的专栏

结束阶段:

1.提一个好的问题。面试的最后,企业为了表示尊重,一般会给面试者提问的机会。千万不要以为这个时候面试结束了,可以随便发问。其实面试官有自己的考虑,面试还在继续,他是希望通过这个获取到你内心深处的想法,因为你问什么代表你关心什么。问一个好的问题,会加深他对你的良好印象。反之,会因为近因效应,前面的一切付之东流。如何提好一个问题呢?一句话“显上进、莫啰嗦”。

举几个例子。

案例一:某求职者以为面试结束了,问:“请问贵公司加班严重吗?”;面试官心里会想“他也许不能加班,他可能不太求上进”

案例二:某求职者问“请问贵公司的培训体系是怎么样的?”;面试官心里会想“他很上进,在考虑日后长远发展的问题”

那么,很明显了,第二种提问更好。有人要问,第一个问题难道没有了解的必要性吗?当然要了解,但不是现在。

2.表示感谢和期待。礼多从来人不怪。

以上从面试全过程的角度简单阐述了一些面试技巧,希望各位受用。如果实力不差,又确实做到了这几点,基本上可以等着拿offer了。

四、offer洽谈

  Offer洽谈也要看企业类型,以企业类型定策略。

  这个“谈”字,在国企一般是“告知”的意思,也就是说基本没有讨价还价的余地,他们是严格按照你的工作年限、岗位情况、面试情况等对应相应的职级来确定薪资,而且为了保证内部团队的稳定性,基本不会为个人去做太大的突破。很多国企薪资听上去挺低,但年收入算下来往往不比私企差,甚至更高。因此,国企offer洽谈重在“了解”,把他们的各项福利摸清楚才是你的重点。国企一般会比较隐晦,有些东西你不问,他们并不会主动告诉你。

  私企的“谈”字就更贴近字本身的意义一些。现在私企定薪比较灵活(粗放),一般是在你原来薪资的基础上给你加一些,但是如果你能力突出,也许能争取到一些突破。所以,私企谈薪重在“试”,试他们对你的态度,来判定能不能争取到更高的薪资。当然,更多的了解也是有必要的,私企的月薪较高,但也可能存在一些隐患秘而不宣,比如年终奖少,五险一金基数和比例低等等,综合收入算下来并不高。

IT平头哥联盟,webpack 是一个模块打包器。webpack 的主要目标是将JavaScript 文件打包在一起,打包后的文件用于在浏览器中使用,是什么让你坚持走到了这里?

五、offer选择

  到了这一步,自然是手上有几个可供选择的offer了。买东西都讲究“货比三家”,offer选择自然也是一样。切忌拿到一个差不多的offer就下定论,“货比三家”既能帮助你选到更好的,也能坚定你对这份工作的信心。所以如果你没有三个及以上offer,下文先别看了,回去先继续找。
言归正传,如何选择最佳offer呢?

  首当其冲应建立起对工作本身的评价体系。换句话说一份工作是由各种因素组成的,它应该是立体而鲜活的。我们选取最重要的维度进行构建工作评价模型。

  经初步统计,笔者HR从业期间,“阅人无数”,曾做过一个简单统计,在求职者应聘过程中最关心的问题排行榜中占据最高比例的三个问题,依次为:薪资福利、企业平台、职业发展。当然,工作地点、工作氛围、加班时长、户口问题等等也是重要的考虑维度。“没有一份工作是完美的”,这是我们面对工作应有的态度。所以,考虑时也无法面面俱到,必须有所偏向,有所舍弃。我将这些维度分为三类:重要因素、必要因素、非必要因素。

  重要因素,顾名思义,是我们找工作过程中最看中的,是决定是否选择这份工作的决定性因素。我姑且取大部分人最关心的三要素纳入其中。当然,每个人都可以根据自身情况自行调整。

  必要因素,指的是那些根据自身情况,必不可少的因素。换句话说,不管这份工作有多好,只要它不满足这个因素,我绝对不能接受。举个例子,我已经在这个城市定居,老婆在本地工作,孩子在这儿上学,我绝对不会去外地,那么,工作地点就是我的必要因素。再比如我是一个看中工作与生活平衡的人,加班严重的机会我绝对不会选择,那这个也是我的必要因素。

  非必要因素,指的既不是必要,也没那么重要,有则锦上添花,无则无伤大雅的因素。比如某些小企业爱搞的生日祝福、某些国企爱搞的企业年金等,可有可无。

  那么,很明了了,我们的重点应该放在重要因素上。我们先用排除法排除掉那么不符合必要因素的工作,避免浪费时间。非必要因素前期无法了解那么清楚,也不是我们的考虑重点。

  接下来,我们来分析一下重要因素。以代表性的三个因素为例:

  薪资福利,是工作价值的体现,也是养家糊口的必备项,重要性不言而喻;
企业平台,本人从来不认同“是金子总会发光”这句话,因为金子并不是发光体。如果你把它埋在沙里,那得撞大运的人才能找到。所以,我们向来提倡“酒香也怕巷子深”的**,选择一个好的平台,会让你更加容易实现自己的价值。

  职业发展,“大的平台不一定有好的职业发展”,这是我们首先应该建立的一个认知。阿里腾讯自然是国内认可的顶级互联网公司平台,但依然有很多人辞职,我相信职业发展这一原因不在少数。很浅显的道理,你可能会在这里做一颗螺丝钉。当然,平台大机会也多,但是竞争者也一样多。所以,职业发展见仁见智了。如果非要谈一下看法的话,适合自己的才是最好的。

  各因素都了然于胸了,那么到了建立模型的时候。这个模型很简单,每个人都会。我把它称为“加权计数法”。具体操作方式如下表:

维度 重要性(以比例表示) 工作机会1评分 工作机会2评分
薪酬福利 40% 90 80
企业平台 30% 80 90
职业发展 30% 90 80
合计 87 83

那么,无需纠结,选择工作机会1。

结束语

  寥寥数语,不能尽言。希望能为你度过“互联网的寒冬”提供一点助益,那也不枉我敲了几个小时了。

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:IT平头哥联盟

关注我们,一起成长 做有温度的攻城狮!

热门推荐:

作者:小菜园的菜园-IT平头哥联盟

链接:https://blog.csdn.net/weixin_43254766

交流群:912594095[资源获取/交流群]、公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系IT平头哥联盟获得授权,非商业转载请注明原链接及出处。

内推工作福利

本文由@IT·平头哥联盟-首席填坑官(苏南)分享,公众号:honeyBadger8

  俗话说:在家靠父母、出门靠朋友,为了感谢各位粉丝、朋友对本公众号「honeyBadger8」的关注和支持,我们特地为您提供了一些工作的内推机会,这些公司分布在深圳、广州、杭州、上海、北京、成都、南京等城市,内推人是我本人或者工作中/生活中认识的朋友们,来自各个大厂,非常的靠谱,直接真内推渠道能帮您增加面试的机会和通过的机率

公司名单:

  • 腾讯
  • 阿里巴巴 - 深圳、杭州均可
  • 美团
  • 平安
  • 环球易购 - 电商
  • 点融
  • 众安保险 - 上海、深圳、杭州、北京均可
  • 团贷网 - 深圳子公司
  • 顺丰
  • 金蝶
  • 360金融 - 360浏览器子公司
  • 微保 - 腾讯子公司
  • 微众银行 - 腾讯子公司
  • 苏宁易购 - 南京
  • Vivo - 深圳

不管何时,想换工作的您,我们将在收到您简历的第一时间,为您联系推荐,并实时跟进向您反馈内推进度,助您拿到一份靠谱、坑少的offer。

  大家都知道如其自己海量的在招聘网站上投简历,不如把简历发给身边的朋友们,让朋友内推获得的面试率/通过率都比投简历要高的多,而您就是我们最好的朋友,简历发送给我们来帮您内推,并为您提供职位选择和部门选择的建议。当然内推是要有条件的,我们认为您有机会进这些公司,才给您内推,否则会给您一些学习和准备大厂的建议。

  如果您有这方面的意向,请准备好简历(最好是pdf文件,以保证不会因为兼容问题而错乱),以附件的形式发送到我的邮箱,并在邮件中做下简短的自我介绍(包括您期望的公司、职位)。请按照模板:以【工作内推 - 姓名 - 城市 - 心仪岗位】的邮件名,发到我的邮箱:[email protected]

发完邮件之后,可以在下方留言(限公众号),或进群交流,申请时需注明:内推+真实姓名

职位主要以:前端、测试、java、php、产品/BA等职位为主,其他算法、GO、区块链职位沟通后再确定�。

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8

作者:苏南 - 首席填坑官
链接:https://blog.csdn.net/weixin_43254766
交流群:912594095[资源获取/交流群]、公众号:honeyBadger8

webpack4配置详解之常用插件

webpack4配置详解之常用插件分享

常用的webpack插件整理

前言

  继上一次webpack的基础配置分享之后,本次将分享一些工作中项目常用的配置插件、也会包含一些自己了解过觉得不错的插件,如有分析不到位的,欢迎纠错,嗯,这些东西文档都有,大佬可绕过

  Wepack4之后废弃了很多的插件,这里只会讲解webpack4还支持的(包含4之前插件),已经废弃的将不再阐述。

  上一次的分享之后,有部分掘金网友留言质疑:骗小白的赞是否原创是否是抄别人等等,当然也有很多的网友支持和鼓励,不管褒贬,苏南都非常的感谢,是你们让我认识到自己的不足与优劣。

  大家的留言,让我想起了自己刚入门前端初期的心酸,基本靠自己自学,没有人带,遇到问题像无头的苍蝇,到处乱撞网上一顿搜索,百度不曾欺我,在点了一个又一个的广告之后,翻过十页八页之后终于找到了问题的解决方案。

  执着于对前端的热爱,常常一个问题卡到深夜,初入前端的我曾一度感叹在编辑器写一些东西,在网页上就能跑,甚至感叹 js 写上一个 alert hello world,浏览器就会自动弹出一个窗口,感觉全世界都在向你招手,当时的兴奋是难以形容的,甚至幻想着未来有一天,可能有千万、亿万的用户,在用你写的东西。

  这几天一直在想,这篇插件的总结还是否要继续写下去?从写博客到今天,将近两个月吧,也算是一个新人,技术方面虽说工作了几年,但也不敢说多牛B,写博客的初衷是为了对自己工作中遇到的问题/心得等做一个总结,俗话说:好记性不如烂笔头;同时也希望能把自己遇到的问题、坑点分享给他人,让遇到同样问题的基友们能少走那么一点点弯路。

  终于最后在想了很久之后明白,人无完人,百人百性、千人千面,不管你做总会有不同的声音,同样不管你分享什么,总会有人需要。所以走自己的路,让别人打车吧,坚持自己所想 努力成为自己想成为的样子,就是对自己最大的肯定 ———— 至曾经初入前端的我们

  • 去做想做的事,去爱值得的人;
  • 去成为自己喜欢的模样,
  • 去让自己发光!浑身充满力量,
  • 充实的日子最美好!

各位早安,这里是@IT·平头哥联盟,我是首席填坑官∙苏南,用心分享 一起成长 做有温度的攻城狮。
公众号:honeyBadger8,群:912594095

mini-css-extract-plugin

  • css-提取,看名字就懂提取css用的。
  • 在这之前我们可能会使用extract-text-webpack-plugin比较多一些,两者相比它有什么优势呢?
  • extract-text-webpack-plugin 它对css的提取,最终是根据你创建的实例、或者配置多个入口 chunk来的,
  • 比如你配置了一个入口文件,最终所有的css都会提取在一个样式文件里,
  • 如果你创建了多个extract-text-webpack-plugin实例,则会生成多个css的文件,
  • mini-css-extract-plugin,它默认就会对你的样式进行模块化拆分,嗯,有点跟output里的配置一个意思,异步按需加载,不再仅仅是js的特权;
    两者编译结果进行比较
//extract-text-webpack-plugin 编译打包
config.module.rules.push({
  test: /\.(scss|css)$/,
  use: ExtractTextPlugin.extract({
    use: [
      "css-loader",
      { //首席填坑官∙苏南的专栏 交流:912594095、公众号:honeyBadger8
        loader: 'postcss-loader',
        options: {
          plugins: [
            require('autoprefixer')({ //添加前缀
              browsers: CSS_BROWSERS,
            }),
          ],
          minimize: true
        },
      },
      "sass-loader"
    ]
  })
})
config.plugins.push(new ExtractTextPlugin({
  filename: 'css/[name].css',
  disable: false,
  allChunks: true,
}));


//mini-css-extract-plugin  编译打包
config.module.rules.push({
  test: /\.(scss|css)$/,//同时处理css/scss
    use: [
      {
        loader: MiniCssExtractPlugin.loader,
      },
      "css-loader", //css处理器
      {
        loader: 'postcss-loader',
        /*
            postcss 这个插件的作用在于,与已有的工具集成一起使用,很少有单独使用的情况,
            通用我们用的最多的,是配合 autoprefixer 来添加各浏览器的前缀,以达到更好的兼容,
            再深入一些就是 cssnext 就是允许开发者自定义属性和变量 :     color:var(--theme-color,#42b983);
        */
        options: {
          plugins: [
            require('autoprefixer')({ 
              browsers: CSS_BROWSERS,
            }),
          ],
        },
      },
      "sass-loader" //sass处理器 、甚至还可以再加一个less的处理器
    ]
})

config.plugins.push(new MiniCssExtractPlugin({
  filename: 'css/[name].css', //这里配置跟output写法一致
  chunkFilename: 'css/[id][chunkhash:8].css',
}));
config.plugins.push(new OptimizeCssAssetsPlugin({})); //压缩文件

optimize-css-assets-webpack-plugin

  • 上面的示例里已经用到了,它的作用在于压缩css文件,
  • assetNameRegExp:默认是全部的css都会压缩,该字段可以进行指定某些要处理的文件,
  • cssProcessor:指定一个优化css的处理器,默认cssnano
  • cssProcessorPluginOptions:cssProcessor后面可以跟一个process方法,会返回一个promise对象,而cssProcessorPluginOptions就是一个options参数选项!
  • canPrint:布尔,是否要将编译的消息显示在控制台,没发现有什么用!
  • 坑点 :建议使用高版本的包,之前低版本有遇到样式丢失把各浏览器前缀干掉的问题,
new OptimizeCssAssetsPlugin({
  assetNameRegExp: /\.optimize\.css$/g,
  cssProcessor: require('cssnano'),
  cssProcessorPluginOptions: {
    preset: ['default', { discardComments: { removeAll: true } }],
    //autoprefixer: { browsers: CSS_BROWSERS }, 也是可以指定前缀的
  },
  canPrint: true
})

SplitChunksPlugin、RuntimeChunkPlugin

  • 它们跟上一篇的optimization配置下的的splitChunksruntimeChunk基本是一致的,;
  • SplitChunksPlugin、RuntimeChunkPlugin,其实就是webpack4之前CommonsChunkPlugin的替代品,用于提取一些公共模块;
  • chunks:要进行处理的类型,它有三个值:all,async,initial
  • minSize:最少大小
  • maxSize:最大包的大小,超出生成新的包
  • minChunks:至少要引用N次的模块,
  • maxAsyncRequests:最大的按需加载并行请求数量
  • maxInitialRequests:最大的初始化加载请求次数
new webpack.optimize.SplitChunksPlugin({
        chunks: 'async', 
      minSize: 30000, 
      maxSize: 0, 
    minChunks: 1,  
      maxAsyncRequests: 1,
        maxInitialRequests:1, 
    name: true, //可以指定
    ……,

  }),
  new webpack.optimize.RuntimeChunkPlugin({
    name: 'manifest',
    name: entrypoint => `runtimechunk~${entrypoint.name}` //动态文件名
  })

HotModuleReplacementPlugin

  • 热更新替换,在不刷新重载页面的情况下更换编辑修改后的代码:
  • 它只会更新改动过的内容,所以速度很快,几乎在自己刚改完,切到浏览器窗口内容就已经更新完了;
  • 使用 HotModuleReplacementPlugin插件后,它会暴露一个module.hot对象,它下面有很多的属性:
  • accept:它有两个参数,一个是授权模块(可以直接是单个文件路径、也可以是一个数组包含多个文件路径),第二个参数,是回调函数,即更新后要做的逻辑处理。
  • decline 有点黑名单的意思,就是忽略一些模块,不更新它们,
  • status 当前更新的状态,idle、check、prepare、ready、dispose、apply、fail等;
  • 一般只用到 accept 最多,下面有个示例;

热更新替换展示过程

new webpack.HotModuleReplacementPlugin()


//路由入口页
……
if (module.hot) {
    module
        .hot
        .accept([
            './pages/routes'
        ], (err) => {
            const NextRoute = require('./pages/routes')
            // 从DOM 中移除已经挂载的 React 组件 然后重装
            ReactDOM.unmountComponentAtNode(APP_DOM);
            ReactDOM.render(
                <Provider store={Store}>
                    <Router routes={NextRoute} history={browserHistory}/>
                </Provider>, APP_DOM);
        });
}
……

html-webpack-plugin

  • 这个插件相信大家都熟悉的不能再熟悉了,
  • 把编译后的文件(css/js)插入到入口文件中,可以只指定某些文件插入,可以对html进行压缩等
  • filename:输出文件名;
  • template:模板文件,不局限于html后缀哦;
  • removeComments:移除HTML中的注释;
  • collapseWhitespace:删除空白符与换行符,整个文件会压成一行;
  • inlineSource:插入到html的css、js文件都要内联,即不是以link、script的形式引入;
  • inject:是否能注入内容到 输出 的页面去;
  • chunks:指定插入某些模块;
  • hash:每次会在插入的文件后面加上hash ,用于处理缓存,如:;
  • 其他:favicon、meta、title ……;
new HtmlWebPackPlugin({
  filename: path.resolve(__dirname, '../assets/index.html'), 
  template: path.resolve(__dirname,"../views/temp.html"),
  minify:{ //压缩HTML文件 
  removeComments:true, 
  collapseWhitespace:true 
    },
  inlineSource:  '.(js|css)',
  inject: false,
    chunks: ['vendors', 'index'], //首席填坑官∙苏南的专栏
    hash:true, 
    favicon、meta、title等都可以配置,页面内使用「<%= htmlWebpackPlugin.options.title %>」即可
    ……
})

uglifyjs-webpack-plugin

  • js代码压缩,默认会使用 optimization.minimizer,
  • cache: Boolean/String ,字符串即是缓存文件存放的路径;
  • test:正则表达式、字符串、数组都可以,用于只匹配某些文件,如:/.js(?.*)?$/i;
  • parallel : 启用多线程并行运行来提高编译速度,经常编译的时候听到电脑跑的呼呼响,可能就是它干的,哈哈~;
  • output.comments : 删除所有注释,
  • compress.warnings :插件在进行删除一些无用代码的时候,不提示警告,
  • compress.drop_console:喜欢打console的同学,它能自动帮你过滤掉,再也不用担心线上还打印日志了;
  • 等等还有一些如:定义压缩的程度、提出多次出现但没有变量的值的配置,想深入的同学可移步官方;
//默认:
optimization:{
    minimizer:true
};

//自定义
minimizer: [
  new UglifyJsPlugin({
    cache: true,
    // cache: "assets", 
    parallel: true, //也可以指定 Number ,即最多并行运行数量
    sourceMap: true,
    uglifyOptions: {
      output: {
        comments: false,
        …… //首席填坑官∙苏南的专栏,QQ:912594095
      },
      compress: {
          warnings: false,
          drop_console:true,
          …… 
        }
    },
  }),
],

BannerPlugin

  • 这个插件,它的作用在于某些时候,我们需要对文件添加一些说明,比如版本号,作者、日期等,
  • 它就可以帮到,每次编译,在头部插件一些注释;
  • 它可以直接是一个字符串,也可以是一个options;
  • 嗯,差点忘说了,它是webpack自带的一个插件,不用另外再安装依赖,

以上为自定配置中使用频率较高的选项,公众号:honeyBadger8

//字符串:
new webpack.BannerPlugin('给文件添加一些信息,打包日期:'+ new Date());

//自定义
plugins: [
  new webpack.BannerPlugin({
    {
          banner: ' \n @item:苏南的项目 \n @author:suSouth \n @date:'+new Date()+' \n @description:苏南的项目 \n @version:'+package.version+'  \n', // 要输出的注释内容
          test:string/正则/数组,//可用于匹配某些文件才输出,
          entryOnly: boolean, // 即是否只在入口 模块 文件中添加注释;
          ……
        }
  })
],

preload-webpack-plugin

  • 在使用这个插件之前,我们需要先了解一下 preloadprefetch,从字面意思上讲:预加载
  • 不难理解,就是提前加载资源(匹配其他页面可能用到的资源进行预先,从而达到无loading ,用户无感知的跳转),它的使用也非常的简单,在你要进行预加载的资源上添加 rel="preload"标签即可;
  • 示例:
  • preload-webpack-plugin它的作用就是在编译打包的时候,帮我们把以上的操作都做了,
  • 编译完成后,你可以(指定某些/全部)文件动态插入到 HtmlWebPackPlugin 配置输出的文件内,
  • as: 表示你预加载的资源类型;可以有有先多:script、font、image、style、video等等,更多详细请查看API,它还可以返回function;
  • include:要插入,进行预加载的文件,它有:allChunks、initial、asyncChunks、数组等选项,数组即表示指定插入某些文件
  • fileBlacklist:即文件黑名单,可以指定某个文件,也可以使用正则来匹配;

以上为自定配置中使用频率较高的选项,公众号:honeyBadger8

//注意点1:请把配置一定写在HtmlWebPackPlugin插件之后,否则会报`HtmlWebpackPlugin.getHooks is not a function`错误,
//注意点2:webpack4之后,请使用最新版本 npm install --save-dev preload-webpack-plugin@next,

new PreloadWebpackPlugin({
  rel: 'prefetch',
  as: 'script',
  // as(entry) {
  //   if (/\.css$/.test(entry)) return 'style';
  //   return 'script';//首席填坑官∙苏南的专栏,QQ:912594095
  // },
  include: 'asyncChunks',
  // fileBlacklist: ["index.css"]
  fileBlacklist: [/\index.css|index.js|vendors.js/, /\.whatever/]
})

webpack-bundle-analyzer

  • 这个插件还是蛮棒的,强烈推荐可以看看,也是本次分享的最后一个插件
  • 它的作用在于能帮我们很清晰直观的看到,你编译后的每一个、每一个文件哦,内容的分布组成,有利于我们快速查找包过大、内容是否重复、问题定位优化等;
  • 它会在编译完成后,自动启动一个服务、也可以自定义配置,打开一个可视化窗口,鼠标移动到对应的模块上,都可以显示出,该模块在某文件内占比的大小及stat、parsed、gzipped等的状态;
  • analyzerHostanalyzerPort:自定配置打开的地址、端口,默认使用:127.0.0.1:8888
  • reportFilename: 报告生成的路径,默认以项目的output.path输出;
  • openAnalyzer:是否要自动打开分析窗口,
  • 其他还有很多属性,官网也有,这里只是引导简介,请大佬们勿喷;

以上为自定配置中使用频率较高的选项,公众号:honeyBadger8
以上为自定配置中使用频率较高的选项,公众号:honeyBadger8

plugins:[
    new BundleAnalyzerPlugin({...}) //默认配置就很好了,能满足我们的要求
]

常用的几个插件地址汇总:

结尾:

  以上就是今天为大家整理的几个项目中常用的插件,可能有些地方理解的不是特别到位,欢迎大家补充,同时我也给大家准备了一个整合后完整的webpack配置的示例,如有兴趣可自行测试。

  下一期计划跟大家一起分享“React如何封装一个组件”(或者说沉淀一个组件库)来简单实战一下react如何上手?欢迎持续关注,如觉得不错记得点个赞哦,当然您能动动手指关注下方公众号就更棒了,谢谢支持!

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8

更多文章:

webpack4配置详解之慢嚼细咽
如何给localStorage设置一个过期时间?
easy-mock 最好的备胎没有之一
immutability因React官方出镜之使用总结分享!
面试踩过的坑,都在这里了~
你应该做的前端性能优化之总结大全!
如何给localStorage设置一个过期时间?
动画一点点 - 如何用CSS3画出懂你的3D魔方?

作者:苏南 - 首席填坑官

链接:https://blog.csdn.net/weixin_43254766/article/details/83758660

交流:912594095、公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

推荐 码农书籍小程序

  • 让你随时都能学习进步的小程序,欢迎体验

码农书籍小程序,一起阅读,一起进步,做有温度的攻城狮

浅谈easy-mock 最好的备胎没有之一

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,首席填坑官∙苏南的专栏,梅斌的专栏,公众号:honeyBadger8

引言

​  今天我们来聊聊Mock,随着互联网发展,这两年前后端分离的开发模式兴起,Mock也从以住的幕后走上了台面,让更多的人而得知,以前传统的开发方式Mock大多局限在后端人员接触较多一些。

  Mock已经是老生常谈了,网上一搜索就很多,各位前辈们都讲的很到位,但今天我只讲它——easy-mock

  为什么会突然来聊它,这个就说来话长了,个人简介里就说过,专注于分享工作中遇到的坑,但这一次不是我的坑,来源于QQ群友(# 如果您有想知道的故事,而正好我也会,那么就由我为您讲出来吧,欢迎留言哦 # ),请看下图:

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8

早安,这里是@IT·平头哥联盟,我是首席填坑官∙苏南,用心分享 做有温度的攻城狮。
公众号:honeyBadger8,群:912594095

什么是Mock

  什么是Mock?? Mock其实就是真实数据存在之前,即调试期间的代替品,是个虚拟的存在,用人话讲它就是个备胎,如女生长的好看,追她的人多,但又不是很满意但也不拒绝,在自己心仪的小哥哥出现之前,一直吊着你😂!

一张图带你看清,什么叫备胎,公众号:honeyBadger8
  

如何Mock数据?

  • 不要告诉我 new 一个哦,对象可以 new,备胎可new不出来呢🤫;
  • 方法一:最low的方式将 Mock 数据写在代码里、json文件里;
  • 方法二:利用 CharlesFiddler等代理工具,将 URL 映射到本地文件;
  • 方法三:本地起 Mock Server,即mockjs,有点麻烦每次修改了后还要重启服务,nodemon能解决,但开的东西多了,电脑卡出翔,维护也麻烦;
  • 方法四:规范些的公司自己已经集成了一套mock数据体系;
  • 重点来了easy-mock一个在线 Mock 平台,活儿好又性感是你备胎的最佳选择。
  • 当然优秀的你可能还有很多其他的方式,欢迎补充。
//mock 基本使用示例
import Mock from "mockjs";
Mock.mock({
    "code": 0,
    "message": "请求成功",
    "data|20": [{
        "name": "@cname",//cname 中文,name 英文
        "userId": "@id",
        "lastDate": "@datetime"
    }]
})

什么是easy-mock,能给我们带来什么?

  • Easy Mock 是一个可视化,并且能快速生成 模拟数据 的持久化服务,
  • Easy Mock 支持基于 Swagger 创建项目,以节省手动创建接口的时间;
  • 简单点说:Easy Mock就是一个在线创建mock的服务平台,帮你省去你 配置安装起服务维护多人协作Mock数据不互通等一系列繁琐的操作, 它能在不用1秒钟的时间内给你所要的一切,呼之即来、挥之即去的2018最优秀备胎没有之一,完全不用担心负任何责任哦。
  • 更多优点它在等你去发现哦……

一张图带你看清,什么叫备胎,公众号:honeyBadger8

深入浅出 - 简介

  • 就跟人一样长的再好看,了解过后才懂,一样东西也是如何,谁用谁知道;
  • Easy Mock支持团队协作,也可以是个人项目,
  • 以下以个人项目为例,与多人协作没有区别,只是少了成员邀请;

一张图带你看清,什么叫备胎,公众号:honeyBadger8

深入浅出 - Mock语法回顾

  • @ip -> 随机输出一个ip;
  • @id -> 随机输出长度18的字符,不接受参数;
  • "array|1-10" -> 随机输出1-10长度的数组,也可以直接是固定长度;
  • "object|2" -> 输出一个两个key值的对象,
  • "@image()" 返回一个占位图url,支持size, background, foreground, format, text
  • 等等,这里就不再一一介绍。
    深入浅出 - Mock语法回顾,公众号:honeyBadger8

深入浅出 - 创建一个接口

  • 它的写法,跟Mock.js一模一样,上面代码已经展示过,更多示例
  • 使用Easy Mock创建一个接口,请看下图:
    深入浅出 - 创建一个接口,公众号:honeyBadger8

深入浅出 - 高阶用法 Function

  • 在线编辑,它也能支持 function
  • 是不是很优秀,能获取到全部请求头,可以让我们像写在js里一样写逻辑,写运算,
  • 当然它肯定是还有很多局限性的,如并不支持ES6
  • 有一点需要注意的是 function 里要写传出Mock对象,不能直接@...
  • 来看示例:
对象 描述
Mock Mock 对象
_req.url 获得请求 url 地址
_req.method 获取请求方法
_req.params 获取 url 参数对象
_req.querystring 获取查询参数字符串(url中?后面的部分),不包含 ?
_req.query 将查询参数字符串进行解析并以对象的形式返回,如果没有查询参数字字符串则返回一个空对象
_req.body 当 post 请求以 x-www-form-urlencoded 方式提交时,我们可以拿到请求的参数对象
... _req.cookies、ip、host等等,我只是一个代码的搬运,更详细请看这里
//简单模拟登录,根据用户传入的参数,返回不同逻辑数据
{
  defaultName:function({_req}){
    return _req.query.name;
  },
  code: function({_req}){
    return this.defaultName ? 0 : -97;
  },
  message: function({_req}) {
    return this.defaultName ? "登录成功" : "参数错误";
  },
  data: function({_req,Mock}){
    return this.defaultName ? {
      token: Mock.mock("@guid()"),
      userId: Mock.mock("@id(5)"),
      cname: Mock.mock("@cname()"),
      name: Mock.mock("@name()"),
      avatar: Mock.mock("@image(200x100, #FF6600)"),
      other:"@IT·平头哥联盟-首席填坑官∙苏南 带你再谈Mock数据之easy-mock"
    }:{}
  }
}

深入浅出 - 在线调试

  • 再优秀的工程师写出的代码也一样要测试,没有人敢说自己的代码无Bug
  • Easy Mock 它是真的懂你的,已经为你准备好了,接口编写好后,立马就能让你测试,
  • 是不是觉得很棒棒呢??如果是你自己本地写mock数据,你需要重启服务、手动写参数、可能还需要整个测试页,
  • 知道你已经非常饥渴迫切的想要知道,具体的调试方式了:
  • 看不清吗??已经为你备好在线调试链接,支持POST、GET、PUT等方式,因gif图加载比较大,就不一一演示了

深入浅出 - 在线调试,公众号:honeyBadger8

结尾:

  天下无不散之宴席,又到说再见的时候了,以上就是今天苏南为大家带来的分享,您GET到了吗?Easy Mock更多强大之处自己去折腾吧,#用心分享 做有温度的攻城狮#,希望今天的分享能给您带来些许成长,如果觉得不错记得点个赞哦,,顺便关注下方公众号就更棒了呢,每周为您推最新分享👇👇。

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8

更多文章:

immutability因React官方出镜之使用总结分享!
小程序项目之做完项目老板给我加了6k薪资~
小程序项目之填坑小记
面试踩过的坑,都在这里了~
你应该做的前端性能优化之总结大全!
如何给localStorage设置一个过期时间?
动画一点点 - 如何用CSS3画出懂你的3D魔方?
动画一点点 - 手把手教你如何绘制一辆会跑车
SVG Sprites Icon的使用技巧

作者:苏南 - 首席填坑官

链接:https://blog.csdn.net/weixin_43254766

交流群:912594095、公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

码农书籍,首席填坑官∙苏南的专栏

Eruda 一个可能被人遗忘的移动端调试神器

Eruda 是一个专为手机网页前端设计的调试面板,类似 DevTools 的迷你版,其主要功能包括:捕获 console 日志、检查元素状态、捕获XHR请求、显示本地存储和 Cookie 信息等等。,首席填坑官∙苏南的专栏 交流:912594095、公众号:honeyBadger8

引言

​  日常工作中再牛逼的大佬都不敢说自己的代码是完全没有问题的,既然有问题,那就也就有调试,说到调试工具,大家可能对于fiddlerCharleschrome devtoolsFirebug、还有Safari远程调试等比较熟悉,甚至有些是我可能也没有用过的;

  这里喷一句吧,谁都别给我提IE啊,IE那个不叫调试工具,那叫坑爹神器,话说最近不是又甩锅了,把自己的革命老根据地都甩了。

  俗话说预先善其事必先利其器,今天想给大家分享的是一个可能被人们忽略的小工具,为什么说被人们忽略呢?因为发现github上它才4.6k Star、457 ForkWatch 173次,也就是说千万开发者中知道它的人可能不超过5w,于是决定分享一波,此文重在引导,希望能帮大家开发中带来一点点便利、效率的提升

在日常的移动端开发时,一般都是试用chrome浏览器的移动端模式进行开发和调试,只有在chrome调试完成,没有问题了才会上到真机测试,移动端,宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8

!> 这里是IT平头哥联盟,我是首席填坑官苏南,用心分享 做有温度的攻城狮。

Eruda是什么?

  Eruda是什么?Eruda 是一个专为前端移动端移动端设计的调试面板,类似Chrome DevTools 的迷你版(没有chrome强大 这个是可以肯定的),其主要功能包括:捕获 console 日志、检查元素状态、显示性能指标、捕获XHR请求、显示本地存储Cookie 信息、浏览器特性检测等等。

  虽说日常的移动端开发时,一般都是在用Chrome DevTools浏览器的移动端模式模拟各种手机型号来进行开发和调试,确保功能/页面展示等都没有问题了,才会提交测试;

  但是前面都讲了,只是模拟模拟,当下手机品牌可算是千千万,手机中各种类浏览器,甚至APP都有自己不一样的特色 腰间盘突出,有的还特别突出,有病我们得给它治啊,不然测试、产品、需求、领导都不会放过我们,比如下图场景。

首席填坑官∙苏南的专栏 交流:912594095、公众号:honeyBadger8

如何使用?

  • 它支持npm方式的,这个是不是很开心??
  • 外链,没错,就是外链的形式引入,对于它,我觉得npm的方式没有什么太大意义,直接以外链的引入更方便,也能减少项目资源包的大小,更便于控制是否要加载这个资源。
方式一,默认引入:
<script src="//cdn.jsdelivr.net/npm/eruda"></script>
<script>eruda.init();</script>

方式二,动态加载:

__DEBUG__ && loadJS('http://cdn.jsdelivr.net/eruda/1.0.5/eruda.min.js', ()=>{
  eruda.init();
});//苏南的专栏 交流:912594095、公众号:honeyBadger8

方式三 ,指定场景加载:
//比如线上 给自己留一个后门,
//我们一般的做法是喜欢给某个不起眼的元素,添加一个点击事件,要点它十次、八次以后才开启 debug 模式;
;(function () {
    var src = 'http://cdn.jsdelivr.net/eruda/1.0.5/eruda.min.js';
    if (!/eruda=true/.test(window.location) && localStorage.getItem('active-eruda') != 'true') return;
    document.write('<scr' + 'ipt src="' + src + '"></scr' + 'ipt>');
    document.write('<scr' + 'ipt>eruda.init();</scr' + 'ipt>');
})();

方式四 ,npm:
 npm install eruda --save

…… 加载的方式很多

小而美

  • 这里小,不是指它的包小啊,知道它的同学都知道,其实它的包并不小(约100kb gzip);
  • 100kb不小了,用形容妹子的话来说就是:丰满,直接说它胖,你就死定了;
  • 这里的小而美是指小巧功能也强大,界面也好看;
  • 说了这么多 来看看它到底长啥样吧:

做移动端Web开发的一大痛点就是,在真机运行下无法查看console.log日志和其他信息如网络请求、显示本地存储等信息。如果网页是运行在手机浏览器中还算好,可以把网址在电脑上打开查看console信息,但是如果是做APP的内嵌H5页面,那就只能靠开发阶段在浏览器模拟环境中尽量没有Bug,公众号:honeyBadger8

功能清单

console

  • console 的作用就不用废话了,大家都懂;
  • 早期在console诞生之前,我们的调试功能都是alert过多,包括现在的移动端,在手机上我们想看到参数值、数据、节点等都以alert打印为多数,但过于粗暴、而且一不小心有可能带到线上去了;
  • eruda 能帮我们解决这个问题;所有的日志、错误都能帮我们捕获到
  • 甚至我们还能像chrome,直接在控制台执行js代码;

微信开发必备】h5开发调试,利器Eruda ,公众号:honeyBadger8

Elements

  • eruda 它没有在PC端这么直观,但也因为在移动端展示的方式局限性,
  • 它能把每一个父节点下的每一个子节点全部列出来;你点击某个子节点时,列出当前节点全部的属性、样式、盒子模型等;
  • 查看标签内容及属性;查看Dom上的样式;支持页面元素高亮;支持屏幕直接点击选取;查看Dom上绑定的各类事件。
  • 甚至也能使用Plugins 插件,做到跟PC端一样,形成 dom tree;

使用神器eruda 进行移动端调试-,公众号:honeyBadger8
PC、Mobile调试节点对比

Network

  • 现在的项目大多都是前后端分享的形式了,前端处理的业务越来越多、各种请求资源等;
  • 干的越多承担责任也越多、锅也越多,又大又平的那种哦~
  • 所以 Network 的必要性不言而喻,它能捕获请求,查看发送数据、返回头、返回内容等信息,它对于我们平时前后端联调出现的问题定位是有很大帮助的,比如:后端说你请求参数少了,前端你看了代码逻辑没有问题,但在手机上就是调不通,Network 能很直接明了的看到你请求带了什么。

The Hypertext Transfer Protocol (HTTP) is an application protocol for distributed, collaborative, ... HTTP is designed to permit intermediate network elements to improve or enable communications between clients and servers,vConsole便是这样一款很棒的移动端DevTools工具,由大厂企鹅出品。但本文把他定位为男二号,今天的主角男一号是:Eruda!vConsole的同类。,PC、eruda 数据请求对比

Resources

  • 它跟 Chrome Devtools 里的 Application + Source,两者的结合体;
  • Resources 它能查看 Cookie、localStorage、sessionStorage等信息,并且还能执行清除操作(Application);
  • 它还查看当前页面加载脚本及样式文件;查看页面加载过的图片等资源(Source);
  • 好吧,感觉说的再多,也不如上图直接:
    有哪些关于前端开发技术HTML、CSS、JavaScript 等值得推荐的书籍? 从菜鸟到大 ... 锋利的jQuery第2版 【书籍】. Js知识点. JavaScript深入系列15篇正式完结!Resources 功能分析

Sources/Info

  • Sources:查看页面源码;格式化html,css,js代码及json数据。
  • Info:主要输出URL信息及User Agent;及其他的一些手机系统信息,同时也支持自定义输出内容哦。

通常写前端页面都在Chrome浏览器的开发模式下进行调试,但是写放在移动端的H5页面时,有时候会遇到在Chrome上调试没有问题,但是在手机的浏览器上有问题的情况;也有的页面是需要放在微信公众号中的,调用了微信JSSDK的方法,必须得通过手机上的微信内置浏览器才能使用,这个时候如果遇到了报错,只能够通过alert一步一步地定位问题。今天发现了一个好用的可以在手机浏览器上直接定位问题的插件:eruda.js,Resources 功能分析

高阶用法

  • 以上刚才介绍的是它的一些基本的功能,也是我自己在工作中用的较多的;
  • 最近发现新版本功能要强大不少,之前一直用的1.0.5,好像是没有插件这一项的;
  • 大概看了一下,都蛮强大,包括上面的Dom tree,插件这部分并没有都实际应用过,所以也就不打肿脸充胖子了,有兴趣的同学可以自己看看。
  • 如果觉得已经的插件都满足不了你的需求,它还支持自定义插件自己编写。

These share data are from my usual work and learning,hoping to help you,If you like you can star. Javascript. Article, Article. Javascript深浅 ,Resources 功能分析

结尾:

  以上就是今天给大家带来的分享,工作中用了蛮久,挺方便的,对于定位移动端的疑难杂症问题、甚至留下后门定位线上问题都有很大帮助,如文中有理解不到位之处,欢迎留言指出。

  线上问题我们一般的做法是喜欢给某个不起眼的元素,添加一个点击事件,要点它十次、八次以后才开启 debug 模式;

  上面二维码确实是真实的官方Demo,不用担心有套路,也有链接:https://eruda.liriliri.io/

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:IT平头哥联盟

其他

作者:苏南 - 首席填坑官

链接:https://blog.csdn.net/weixin_43254766

交流群:912594095[资源获取/交流群]、公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系IT平头哥联盟获得授权,非商业转载请注明原链接及出处。

那些年面过的坑,都在这里了~

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享

前言

  前段时间面试(包括阿里巴巴的电话面试),遇到过一些面试题,且面试中出现机率较高的提问/笔试,有些答的不是很好挂掉了,今天终于有时间整理出来分享给大家,希望对大家面试有所帮助,都能轻松拿offer。

主要分三部分:htmlcssjs;react/vue等都归类于js,内容来源于面试过程中遇到的、在复习过程中看到认为值得加深巩固群友交流分享的;如有理解的错误或不足之处,欢迎留言纠错、斧正,这里是@IT·平头哥联盟,我是首席填坑官苏南(South·Su) ^_^~

  本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,君自故乡来,应知故乡事。来日绮窗前,寒梅着花未?——唐·王维

HTML

1、什么是盒子模型?

  有些面试官会问你对盒子模型的理解,在我们平时看到的网页中,内部的每一个标签元素它都是有几个部分构成的:内容(content)、外边距(margin)、内边距(padding)、边框(border),四个部分组成,当你说完这些面试官是不会满意这个答案的,因为还有一个重点(IE盒模型和标准盒模型的区别)———IE盒模型的content包括border、padding

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

2、页面导入样式时有几种方法,它们之间有区别?
  • link标签引入,也是当下用的最多的一种方式,它属于XHTML标签,除了能加载css外,还能定义rel、type、media等属性;
  • @import引入,@import是CSS提供的,只能用于加载CSS;
  • style 嵌入方式引入,减少页面请求(优点),但只会对当前页面有效,无法复用、会导致代码冗余,不利于项目维护(缺点),此方式一般只会项目主站首页使用(腾讯、淘宝、网易、搜狐)等大型网站主页,之前有看到过都是这种方式,但后来有些也舍弃了 

小结link页面被加载的时,link会同时被加载,而@import引用的CSS会等到页面被加载完再加载,且link是XHTML标签,无兼容问题; link支持动态js去控制DOM节点去改变样式,而@import不支持,

3、简单讲述一下块元素、内联元素、空元素有哪些,它们之间的区别?
  • 行内元素有:a、b、span、img、input、select、textarea、em、img、strong(强调的语气);
  • 块级元素有:ul、ol、li、dl、dt、dd、h1、h2、h3、h4…p、section、div、form等;
  • 空元素: input type="hidden"/>、br>、hr>、link>、meta>; 

小结:块元素总是独占一行,margin对内联元素上下不起作用; 

4、说说 cookies,sessionStorage 、 localStorage 你对它们的理解?
  • cookie是网站为了标示用户身份而储存在用户本地终端上的数据(通常经过加密),cookie数据始终在同源的http请求中携带,记会在浏览器和服务器间来回传递。 
  • sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
  • 大小: cookie数据大小不能超过4k,sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
  • 时效:localStorage 存储持久数据,浏览器关闭后数据不丢失除非用户主动删除数据或清除浏览器/应用缓存;sessionStorage 数据在当前浏览器窗口关闭后自动删除。
  • cookie 设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭部分面试官可能还会再深入一些:

1)、如何让cookie浏览器关闭就失效?——不对cookie设置任何正、负或0时间的即可;
2)、sessionStorage在浏览器多窗口之间 (同域)数据是否互通共享? ——不会,都是独立的,localStorage会共享;
3)、能让localStorage也跟cookie一样设置过期时间?答案是可以的,在存储数据时,也存储一个时间戳,get数据之前,先拿当前时间跟你之前存储的时间戳做比较 详细可看我之前写的另一篇分享(小程序项目总结 )。

5、简述一下你对HTML语义化的理解 ?

  语义化是指根据内容的类型,选择合适的标签(代码语义化),即用正确的标签做正确的事情; html语义化让页面的内容结构化,结构更清晰,有助于浏览器、搜索引擎解析对内容的抓取; 语义化的HTML在没有CSS的情况下也能呈现较好的内容结构与代码结构; 搜索引擎的爬虫也依赖于HTML标记来确定上下文和各个关键字的权重,利于SEO;

CSS

1、position的static、relative、absolute、fixed它们的区别?
  • absolute:绝对定位,元素会相对于值不为 static 的第一个父元素进行定位(会一直往父级节点查找),且它是脱离正常文档流、不占位的;
  • fixed:同样是绝对定位,但元素会相对于浏览器窗口进行定位,而不是父节点的position (IE9以下不支持);
  • relative:相对定位,元素相对于自身正常位置进行定位,属于正常文档流;static: position的默认值,也就是没有定位,当元素设置该属性后( top、bottom、left、right、z-index )等属性将失效; 
  • inherit:貌似没用过,查了一下文档“规定从父元素继承 position 属性的值”;
2、如何让一个元素垂直/水平(垂直水平)都居中,请列出你能想到的几种方式?
  • 水平垂直居中 —— 方式一
<div class="div-demo"></div>
<style>
	.div-demo{
		width:100px;
		height:100px;
		background-color:#06c;
		margin: auto;
		position:absolute;
		top: 0;
		left: 0;
		bottom: 0;
		right: 0;
	}
</style>
  • 水平垂直居中 —— 方式二
<style>
	.div-demo{
		width:100px;
		height:100px;
		background-color:#06c;
		margin: auto;
		position:absolute;
		top: 50%;
		left: 50%;
		transform: translate(-50%,-50%);
		-webkit-transform: translate(-50%,-50%);
	}
</style>
  • 水平垂直居中 —— 方式三,(新旧伸缩盒兼容)
<body class="container">
	<div class="div-demo"></div>
	<style>

		html,body{
			height:100%;
		}
		.container{
			display: box;
			display: -webkit-box;
			display: flex;
			display: -webkit-flex;
			-webkit-box-pack: center;
			-webkit-justify-content: center;
			justify-content: center;
			-webkit-box-align: center;
			-webkit-align-items: center;
			align-items: center;
		}
		.div-demo{
			width:100px;
			height:100px;
			background-color:#06c;
		}
	</style>

</body>

3、项目中有用纯CSS样式写过 三角形icon吗?
<body class="container">
	<div class="div-angles"></div>
	<div class="div-angles right"></div>
	<div class="div-angles bottom"></div>
	<div class="div-angles left"></div>
	<style>

		html,body{
			height:100%;
		}
		.container{
			display: box;
			display: -webkit-box;
			display: flex;
			display: -webkit-flex;
			-webkit-box-pack: center;
			-webkit-justify-content: center;
			justify-content: center;
			-webkit-box-align: center;
			-webkit-align-items: center;
			align-items: center;
		}
		.div-angles{
			width: 0;
			height: 0;
			border-style: solid;
			border-width:30px;
			width:0px;
			height:0px;
			border-color: transparent transparent #06c transparent;
		}
		.right{
			border-color: transparent transparent transparent #06c ;
		}
		.bottom{
			border-color: #06c transparent transparent ;
		}
		.left{
			border-color: transparent #06c transparent transparent;
		}
	</style>

</body>

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享

4、什么是外边距合并,项目中是否有遇到过?
  • 有,外边距合并指的是,当两个垂直元素的都设置有margin外边距相遇时,它们将形成一个外边距。 合并后的外边距的高度等于两个发生合并的外边距的值中的较大那个。
5、:before 和 :after两伪元素,平时都是使用双冒号还是单冒号?有什么区别?以及它们的作用:
  • 单冒号(:)用于CSS3伪类,双冒号(::)用于CSS3伪元素。(伪元素由双冒号和伪元素名称组成) ;
  • 双冒号是在当前规范中引入的,用于区分伪类和伪元素。不过浏览器需要同时支持旧的已经存在的伪元素写法,比如:first-line、:first-letter、:before、:after等,
    而新的在CSS3中引入的伪元素则不允许再支持旧的单冒号的写法;
  • 想让插入的内容出现在其它内容前,使用::before,之后则使用::after; 在代码顺序上,::after生成的内容也比::before生成的内容靠后。
    如果按堆栈视角,::after生成的内容会在::before生成的内容之上; 
6、Chrome、Safari等浏览器,当表单提交用户选择记住密码后,下次自动填充表单的背景变成黄色,影响了视觉体验是否可以修改?
input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill {
  background-color: #fff;//设置成元素原本的颜色
  background-image: none;
  color: rgb(0, 0, 0);
}
//方法2:由(licongwen )补充
input:-webkit-autofill {
    -webkit-box-shadow: 0px 0 3px 100px #ccc inset; //背景色
}
7、浏览器的最小字体为12px,如果还想再小,该怎么做?
  • 用图片:如果是展示的内容基本是固定不变的话,可以直接切图兼容性也完美(不到万不得已,不建议);
  • 找UI设计师沟通:为了兼容各大主流浏览器,避免后期设计师来找你撕逼,主动找TA沟通,讲明原因 ————注意语气,好好说话不要激动,更不能携刀相逼;
  • CSS3:css3的样式transform: scale(0.7),scale有缩放功能;
  • 又去找chrome复习了一下,说是 “display:table;display: table-cell;” 可以做到,没用过。
8、移动端的边框0.5px,你有几种方式实现?
  • devicePixelRatio:它是window对象中有一个devicePixelRatio属性,设备物理像素和设备独立像素的比例,也就是 devicePixelRatio = 物理像素 / 独立像素;这种方式好麻烦,js检测,再给元素添加类名控制,难维护;
  • 切图:直接.5px的切图,这种方式太low,建议还是别用了,特别难维护,高清屏就糊了,更重要的是被同行看到会觉得你们很渣渣~;
  • image背景:css3的background-image:linear-gradient,缺点就是:样式多,遇到圆角这个方案就杯剧了; box-shadow:网上看到说使用box-shadow模拟边框,box-shadow: inset 0px -1px 1px -1px #06c;没用过,不过多评论,建议自己百度;
  • 伪类缩放:现在用的比较多的方式之一 :after 1px然后transform: scale(0.5);基本能满足所有场景,对于圆角的处理也很方便;

贴上3、5两方案代码,也是目前公司一直在用的(预处理SCSS):

//3、css3的background-image 本文由@IT·平头哥联盟-首席填坑官∙苏南分享
@mixin border($top:1, $right:1, $bottom:1, $left:1, $color:#ebebf0) {
  background-image:linear-gradient(180deg, $color, $color 50%, transparent 50%), 
                  linear-gradient(90deg, $color, $color 50%, transparent 50%), 
                  linear-gradient(0deg, $color, $color 50%, transparent 50%),
                  linear-gradient(90deg, $color, $color 50%, transparent 50%);
  background-size: 100% $top + px, $right + px 100%, 100% $bottom + px, $left + px 100%;
  background-repeat: no-repeat;
  background-position: top, right top, bottom, left top ;
}

@mixin borderTop($top:1, $color:#ebebf0) {
  @include border($top, 0, 0, 0, $color);
}
@mixin borderRight($right:1, $color:#ebebf0) {
  @include border(0, $right, 0, 0, $color);
}
@mixin borderBottom($bottom:1, $color:#ebebf0) {
  @include border(0, 0, $bottom, 0, $color);
}
@mixin borderLeft($left:1, $color:#ebebf0) {
  @include border(0, 0, 0, $left, $color);
}
@mixin borderColor($color:#ebebf0) {
  @include border(1, 1, 1, 1, $color);
}

//5、css3的transform:scale  本文由@IT·平头哥联盟-首席填坑官∙苏南分享
@mixin borderRadius($width:1,$style:solid,$color:#ebebf0,$radius:2px) {
  position:relative;
    &:after{
       left:0px;
       top:0px;
       right:-100%;
       bottom:-100%;
       border-radius:$radius;
       border-style: $style;
       border-color: $color;
       border-width: $width+ px;
       position:absolute;
       display:block;
       transform:scale(0.5);
       -webkit-transform:scale(0.5);
       transform-origin:0 0;
       -webkit-transform-origin:0 0;
       content:'';
    }
}
display:none与visibility:hidden两者的区别?
  • display:none在页面中是不占位置的,而visibility:hidden保留原来的位置后;
  • display:none显示/隐藏 页面会产生回流和重绘的问题,visibility则不会 ——重绘/回流请看JS部分第七题;

Javascript

1、请将下列b函数进行修改,保证每次调用a都能+1(考闭包):
//本文由@IT·平头哥联盟-首席填坑官∙苏南分享,如有错误,欢迎留言
function b(){
	var a=1;
};

function b(){
	var a=1;
	return ()=>{
		a++;
		return a;
	}
};
let c = b();
c(); //2
c(); //3
c(); //4

####### 2、js有哪些基本数据类型:   
ECMAScript 标准定义有7种数据类型:  

  • Boolean
  • Null
  • Undefined
  • Number
  • String
  • Symbol :(ECMAScript 6 新定义 ,Symbol 生成一个全局唯一、表示独一无二的值) 
  • Object :(Array、Function、Object)
3、用js将 386485473.88 转换为 386,485,473.88(千位分割符):
//方法1:
var separator=(num)=>{
	if(!num){
		return '0.00';
	};
	let str = parseFloat(num).toFixed(2);
	return str && str
		.toString()
		.replace(/(\d)(?=(\d{3})+\.)/g, function($0, $1) {
			return $1 + ",";
		});
}

separator(386485473.88) //"386,485,473.88"

//方法2:
(386485473.88).toLocaleString('en-US')  // "386,485,473.88" 由 (sRect)补充
4、js的 for 跟for in 循环它们之间的区别?
  • 遍历数组时的异同: for循环 数组下标的typeof类型:number, for in 循环数组下标的typeof类型:string;
var southSu = ['苏南','深圳','18','男'];
for(var i=0;i<southSu.length;i++){
	console.log(typeof i); //number
	console.log(southSu[i]);// 苏南 , 深圳 , 18 , 男
}
var arr = ['苏南','深圳','18','男','帅气',"@IT·平头哥联盟-首席填坑官"];
for(var k in arr){
	console.log(typeof k);//string
	console.log(arr[k]);// 苏南 , 深圳 , 18 , 男 , 帅气,@IT·平头哥联盟-首席填坑官
}
  • 遍历对象时的异同:for循环 无法用于循环对象,获取不到obj.length; for in 循环遍历对象的属性时,原型链上的所有属性都将被访问,解决方案:使用hasOwnProperty方法过滤或Object.keys会返回自身可枚举属性组成的数组
Object.prototype.test = '原型链上的属性,本文由@IT·平头哥联盟-首席填坑官∙苏南分享';
var southSu = {name:'苏南',address:'深圳',age:18,sex:'男',height:176};
for(var i=0;i<southSu.length;i++){
	console.log(typeof i); //空
	console.log(southSu[i]);//空
}


for(var k in southSu){
	console.log(typeof k);//string
	console.log(southSu[k]);// 苏南 , 深圳 , 18 , 男 , 176 ,本文由@IT·平头哥联盟-首席填坑官∙苏南分享
}

5、给table表格中的每个td绑定事件,td数量为1000+,写一下你的思路(事件委托题):
<body class="container">
	<table id="table">
		<tr><td>我们是@IT·平头哥联盟</td><td>,我是首席填坑官</td><td>苏南</td><td>前端开发</td><td>优秀</td></tr>
		<tr><td>我们是@IT·平头哥联盟</td><td>,我是首席填坑官</td><td>苏南</td><td>前端开发</td><td>优秀</td></tr>
		<tr><td>我们是@IT·平头哥联盟</td><td>,我是首席填坑官</td><td>苏南</td><td>前端开发</td><td>优秀</td></tr>
		…………
	</table>
<script>
	let table =document.querySelector("#table");
	table.addEventListener("click",(e)=>{
		let {nodeName} = e.target;
		if(nodeName.toUpperCase() === "TD"){
			console.log(e.target);//<td>N</td>
		}
	},false);

</script>
</body>
6、js把一串字符串去重(能统计出字符重复次数更佳),列出你的思路(两种以上):
<script>
	let str = "12qwe345671dsfa233dsf9876ds243dsaljhkjfzxcxzvdsf本文由@IT·平头哥联盟-首席填坑官∙苏南分享";
	let array = str.split("");

	//方案一:
	array = [...new Set(array)].join("");
	array = ((a)=>[...new Set(a)])(array).join("");
	console.log(array);//12qwe34567dsfa98ljhkzxcv本文由@IT·平头哥联盟-首席填坑官∙苏南分享  只能过滤,不会统计

	//方案二:
	function unique (arr) {
		const seen = new Map()
		return (arr.filter((a) => !seen.has(a) && seen.set(a, 1))).join("");
	}
	console.log(unique(array)) // 12qwe34567dsfa98ljhkzxcv本文由@IT·平头哥联盟-首席填坑官∙苏南分享

	//方案三:
	function unique (arr) {
		let arrs=[];
		var news_arr = arr.sort();//排序能减少一次循环
		for(var i=0;i<news_arr.length;i++){
				if(news_arr[i] == news_arr[i+1] && news_arr[i]!= news_arr[i-1] ){
						arrs.push(arr[i]);
				};
 
		};
		return arrs.join("");
	}
	console.log(unique(array)) // 12qwe34567dsfa98ljhkzxcv本文由@IT·平头哥联盟-首席填坑官∙苏南分享

	//方案四:
	function unique (arr) {
		let obj={};
		for(var i=0;i<arr.length;i++){
			let key = arr[i];
			if(!obj[key] ){
					obj[key]=1;
			}else{
				obj[key]+=1;
			}
 
		};
		return obj;
	}
	console.log(unique(array)) // object 对应每个key以及它重复的次数 

</script>
7、项目上线前,你们做过哪些性能优化:
  • 图片预加载,css样式表放在顶部且link链式引入,javascript放在底部body结束标签前;
  • 使用dns-prefetch对项目中用到的域名进行 DNS 预解析,减少 DNS 查询,如: ; 
  • 减少http请求次数:图片静态资源使用CDN托管;
  • API接口数据设置缓存,CSS Sprites/SVG Sprites(如有疑惑:该如何以正确的姿势插入SVG Sprites? 这篇说的很详细), JS、CSS源码压缩、图片大小控制合适,使用iconfont(+ 字体图标)或SVG,它们比图片更小更清晰,网页Gzip压缩;
  • 减少DOM操作次数,优化javascript性能;
  • 减少 DOM 元素数量,合理利用:after、:before等伪类;
  • 避免重定向、图片懒加载;前后端分离开发,资源按需加载,最好能做到首屏直出(即服务端渲染); 
  • 避免使用CSS Expression(css表达式)又称Dynamic properties(动态属性) ;
  • 多域名分发划分内容到不同域名,解决浏览器域名请求并发数问题,同时也解决了请求默认携带的cookie问题;
  • 尽量减少 iframe 使用,它会阻塞主页面的渲染; 对所有资源压缩 JavaScript 、 CSS 、字体、图片等,甚至html;
  • 只想到这些,欢迎补充……
8、你对重绘、重排的理解?
  • 首先网页数次渲染生成时,这个可称为重排; 
  • 修改DOM、样式表、用户事件或行为(鼠标悬停、页面滚动、输入框键入文字、改变窗口大小等等)这些都会导致页面重新渲染,那么重新渲染,就需要重新生成布局和重新绘制节点,前者叫做"重排",后者"重绘"; 
  • 减少或集中对页面的操作,即多次操作集中在一起执行; 
  • 总之可以简单总结为:重绘不一定会重排,但重排必然为会重绘。 
  • 更详细的可以看阮老师分析
8、有用过promise吗?请写出下列代码的执行结果,并写出你的理解思路:
setTimeout(()=>{
		console.log(1);
}, 0);

new Promise((resolve)=>{
		console.log(2);
		for(var i = 1; i < 200; i++){
				i = 198 && resolve();
		}
		console.log(3);
}).then(()=>{
		console.log(4);
});
console.log(5);

// 结果:2、3、5、4、1;
  • 首先要讲一下,js是单线程执行,那么代码的执行就有先后; 
  • 有先后,那就要有规则(排队),不然就乱套了,那么如何分先后呢?大体分两种:同步、异步; 
  • 同步很好理解,就不用多说了(我就是老大,你们都要给我让路); 
  • 异步(定时器[setTimeout ,setInterval]、事件、ajax、promise等),说到异步又要细分宏任务、微任务两种机制, 
  • 宏任务:js异步执行过程中遇到宏任务,就先执行宏任务,将宏任务加入执行的队列(event queue),然后再去执行微任务; 
  • 微任务:js异步执行过程中遇到微任务,也会将任务加入执行的队列(event queue),但是注意这两个queue身份是不一样的,不是你先进来,就你先出去的(就像宫里的皇上选妃侍寝一样,不是你先进宫(或先来排队)就先宠幸的 ),真执行的时候是先微任务里拿对应回调函数,然后才轮到宏任务的队列回调执行的; 
  • 理解了这个顺序,那上面的结果也就不难懂了。

说细步骤如下:
setTimeout 是异步,不会立即执行,加入执行队列;
new Promise 会立即执行 输出 2、3,而在2、3之间执行了resolve 也就是微任务;
再到console.log(5)了,输出5;
然后异步里的微任务先出,那就得到4;
最后执行宏任务 setTimeout 输出 1;
如有错误欢迎纠正!

9、new SouthSu() 在这个过程中都做了些什么?
function SouthSu(){
 		this.name = "苏南";
 		this.age = 18;
 		this.address = "深圳";
 		this.address = "首席填坑官";
};

 let South = new SouthSu();
 console.log(South,South.__proto__ === SouthSu.prototype) //true 

执行过程:
创建一个空的对象
 let p1 = new Object();


设置原型链
	p1.__proto__ = SouthSu.prototype;

 构造函数 的this 指向 p1 这个空对象

	let funCall = SouthSu.call(p1);

处理 构造函数 的返回值:判断SouthSu的返回值类型,如果是值类型则返回obj,如果是引用类型,就返回这个引用类型的对象;
10、工作中如果让你使用js实现一个持续的动画,你会怎么做(比如转盘抽奖)??
  • js来实现动画,第一时间想到的就是定时器(setTimeout、setInterval); 
  • 后面想起来js有个 window.requestAnimationFrame ,当时只是说了记得有这么一个API,具体的细节没能答上,面试官直言想听的就是这个API的使用,好吧是我准备的不够充分,希望其他同学不再犯同样错误;

window.requestAnimationFrame() 方法告诉浏览器您希望执行动画并请求浏览器在下一次重绘之前调用指定的函数来更新动画。该方法使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用,回调的次数通常是每秒60次,是大多数浏览器通常匹配 W3C 所建议的刷新频率。在大多数浏览器里,当运行在后台标签页或者隐藏的<iframe> 里时,requestAnimationFrame() 会暂停调用以提升性能和电池寿命。

小结:以往项目开发中大数人可能都是第一时间选择JS定时器setInterval 或者setTimeout 来控制的动画每隔一段时间刷新元素的状态,来达到自己所想要的动画效果,但是这种方式并不能准确地控制动画帧率,因为这是开发者主动要求浏览器去绘制,它这可能会因为动画控制的时间、绘制的频率、浏览器的特性等而导致丢帧的问题; requestAnimationFrame 是浏览器什么时候要开始绘制了浏览器它自己知道,通过requestAnimationFrame告诉我们,这样就不会出现重复绘制丢失的问题。

//一个持续旋转的正方形,
<div class="angle-div"></div>
<script>
	let timer = null;
	let Deg = 0;
	let distance = 360;
	var _requestAnimationFrame_ = window.requestAnimationFrame || window.webkitRequestAnimationFrame;//本文由@IT·平头哥联盟-首席填坑官∙苏南分享
	let angleDiv = document.querySelector(".angle-div");
	cancelAnimationFrame(timer);
	let fn = ()=>{
		if(Deg < distance){ 
			Deg++;
		}else{
			Deg=0;
		};
		angleDiv.style.transform = `rotateZ(${Deg}deg) translateZ(0)`; 
		angleDiv.style.WebkitTransform = `rotateZ(${Deg}deg) translateZ(0)`;
		timer = _requestAnimationFrame_(fn);
	}
	timer = _requestAnimationFrame_(fn);
</script>

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

11、如何设置http缓存?

 1)、Expires

  • Expires的值为服务端返回的到期时间,响应时告诉浏览器可以直接从浏览器缓存中读取无需再次请求。
    缺点:返回的是服务端的时间,比较的时间是客户端的时间,如果时间不一致有可能出现错误。

 2)、Cache-Control

  • Cache-Control可设置的字段有:
  • private:客户端可以缓存
  • public:客户端和代理服务器都可以缓存
  • max-age=xxx:缓存内容在xxx秒后失效
  • no-cache:需要用另一种缓存策略来验证缓存(ETag,Last-Modified)
  • no-store:不进行缓存
  • Last-Modified:浏览器请求获得文件后,服务器返回该文件的最后修改时间Last-Modified,下一次请求会带上If-Modified-Since标识,如果If-Modified-Since等于服务器的文件修改时间,则表示文件没有修改,返回304状态码,浏览器从浏览器缓存中读取文件。如果If-Modified-Since小于服务端的文件修改时间,则浏览器会重新发送请求获取文件,返回状态码200。
  • ETag:服务器文件的一个唯一标识,例如对文件内容取md5值作为ETag的字段返回给浏览器。当文件变化时ETag的值也会发生变化。下次请求会带上If-None-Match即浏览器保留的ETag值,如果发送了变化,则文件被修改,需要重新请求,返回200状态码。反之浏览器就从缓存中读取文件,返回304状态码。

总结:——几者之间的关系

  • Cache-Control设置为max-age=xx并且同事设置Expires时,Cache-Control的优先级更高
  • ETagLast-Modified同时存在时,服务器先会检查ETag,然后再检查Last-Modified,最终决定返回304还是200
  • 该题由 本文由@it·平头哥联盟-成员(ZodiacSyndicate )补充
12、随机打乱一个数组
  • 思路:从数组的最后一项开始,随机选择前面的一个元素进行交换,然后一步步往前交换
//该题由 本文由@IT·平头哥联盟-成员(ZodiacSyndicate )补充
const shuffle = arr => {
  let end = arr.length - 1
  while(end) { // 当end为0时不需要交换
    const index = Math.floor(Math.random() * (end + 1))
    [arr[index], arr[end]] = [arr[end], arr[index]]
    end -= 1
  }
  return arr
}
13、用React实现一个显示鼠标位置的高阶组件
//该题由 本文由@IT·平头哥联盟-成员(ZodiacSyndicate )补充
const mousePosition = Component => class extends React.Component {
  state = {
    x: 0,
    y: 0,
  }

  handleMouseMove = e => {
    this.setState({
      x: e.clientX,
      y: e.clientY
    })
  }

  render() {
    const { x, y } = this.state
    return (
      <>
        <div onMouseMove={this.handleMouseMove}>
          <Component {...this.props} />
        </div>
        <span>x: {x}</span>
        <span>y: {y}</span>
      </>
    )
  }
}

文本将持续更新,整理收集自己/群友的面经分享给大家,觉得不错记得 Star、StarWatch 哦,感谢!

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮,公众号:honeyBadger8

作者:苏南 - 首席填坑官

链接:https://honeybadger8.github.io/blog/

交流群:912594095,公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明链接及出处。

如何给localStorage设置一个过期时间?

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8

引言

​  这个话题其实在上次分享<小程序填坑记里讲过了>已经讲过(大佬可绕过哦~),但后来群里/评论都有些同学,提到了一些疑问,问能否单独整理一篇更为详细的分享,讲解一下细节和完善提到的不足,如是有了下文👇。

这里是@IT·平头哥联盟,我是首席填坑官苏南,用心分享 做有温度的攻城狮。
公众号:honeyBadger8,群:912594095

思考点

  从我们接触前端起,第一个熟悉的存储相关的Cookie或者来分析我们生活中密切相关的淘宝、物流、闹钟等事物来说起吧,

  • Cookie从你设置的时候,就会给个时间,不设置默认会话结束就过期;
  • 淘宝购物 从你下单付款起,就会给这件货物设置一个收货期限时间,过了这个时间自动认为你收货(即订单结束);
  • 闹钟 你设置的提醒时间,其实也就是它的过期时间;
  • 再比如与您每天切身相关的产品需求,过完需求,你给出的上线时间,也就是这个需求的过期时间;
  • 再通俗点讲,您今年的生日过完到明年生日之间也是相当于设置了有效期时间;

以上种种,我们能得出一个结论任何一件事、一个行为动作,都有一个时间、一个节点,甚至我们可以黑localStorage,就是一个完善的API,为什么不能给一个设置过期的机制,因为sessionStorageCookie并不能满足我们实际的需求。

实现思路

  抱歉,黑localStorage不完善,有点夸张了,综合上述的总结,问题就简单了,给localStorage一个过期时间,一切就都so easy ?到底是不是,来看看具体的实现吧:

简单回顾

//示例一:
localStorage.setItem('test',1234567);
let test = localStorage.getItem('test');
console.log(typeof test, test); 

//示例二:
localStorage['name'] = '苏南';
console.log(localStorage['name']);
/*
输出:
"1234567" ,'苏南',
这里要注意,1234567 存进去时是number 取出来就成string了
*/

重写 set(存入) 方法:

  • 首先有三个参数 key、value、expired ,分别对应 键、值、过期时间,
  • 过期时间的单位可以自由发挥,小时、分钟、天都可以,
  • 注意点:存储的值可能是数组/对象,不能直接存储,需要转换 JSON.stringify
  • 这个时间如何设置呢?在这个值存入的时候在键(key)的基础上扩展一个字段,如:key+'expires',而它的值为当前 时间戳 + expired过期时间
  • 具体来看一下代码
set(key, value, expired) {
	/*
	* set 存储方法
	* @ param {String} 	key 键
	* @ param {String} 	value 值,
	* @ param {String} 	expired 过期时间,以分钟为单位,非必须
	* @ 由@IT·平头哥联盟-首席填坑官∙苏南 分享
	*/
	let source = this.source;
	source[key] = JSON.stringify(value);
	if (expired){
		source[`${key}__expires__`] = Date.now() + 1000*60*expired
	};
	return value;
}

重写 get(获取) 方法:

  • 获取数据时,先判断之前存储的时间有效期,与当前的时间进行对比;
  • 但存储时expired为非必须参数,所以默认为当前时间+1,即长期有效;
  • 如果存储时有设置过期时间,且在获取的时候发现已经小于当前时间戳,则执行删除操作,并返回空值;
  • 注意点:存储的值可能是数组/对象,取出后不能直接返回,需要转换 JSON.parse
  • 具体来看一下代码
get(key) {
	/*
	* get 获取方法
	* @ param {String} 	key 键
	* @ param {String} 	expired 存储时为非必须字段,所以有可能取不到,默认为 Date.now+1
	* @ 由@IT·平头哥联盟-首席填坑官∙苏南 分享
	*/
	const source = this.source,
	expired = source[`${key}__expires__`]||Date.now+1;
	const now = Date.now();

	if ( now >= expired ) {
		this.remove(key);
		return;
	}
	const value = source[key] ? JSON.parse(source[key]) : source[key];
	return value;
}

重写 remove(删除) 方法:

  • 删除操作就简单了,;
remove(key) {
	const data = this.source,
		value = data[key];
	delete data[key];
	delete data[`${key}__expires__`];
	return value;
}

优化点:

  • 记得上次有个同学,是这么评论的:「 删除缓存能放到constructor里面执行么,放到get里面 不取就一直在那是不是不太好?」;
  • 为什么不用for in而是 for ? for in循环遍历对象的属性时,原型链上的所有属性都将被访问,解决方案:使用hasOwnProperty方法过滤或Object.keys会返回自身可枚举属性组成的数组;
class storage {

	constructor(props) {
		this.props = props || {}
		this.source = this.props.source || window.localStorage
		this.initRun();
	}
	initRun(){
		/*
		* set 存储方法
		* @ param {String} 	key 键
		* @ param {String} 	value 值,存储的值可能是数组/对象,不能直接存储,需要转换 JSON.stringify
		* @ param {String} 	expired 过期时间,以分钟为单位
		* @ 由@IT·平头哥联盟-首席填坑官∙苏南 分享
		*/
		const reg = new RegExp("__expires__");
		let data = this.source;
		let list = Object.keys(data);
		if(list.length > 0){
			list.map((key,v)=>{
				if( !reg.test(key )){
					let now = Date.now();
					let expires = data[`${key}__expires__`]||Date.now+1;
					if (now >= expires ) {
						this.remove(key);
					};
				};
				return key;
			});
		};
	}
}

总结:

  以上就是今天为大家总结的分享,您GET到了吗?小程序、sessionStorage、localStorage,都适用,做些许调整即可哦,希望今天的分享能给您带来些许成长,如果觉得不错,记得关注下方公众号哦,每周第一时间为您推最新分享👇👇。

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8

更多文章:

作者:苏南 - 首席填坑官
链接:https://blog.csdn.net/weixin_43254766/article/details/83618630
交流群:912594095、公众号:honeyBadger8
本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

immutability因React官方出镜之使用总结分享!

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8

作者:首席填坑官∙苏南
公众号:honeyBadger8,群:912594095,本文原创,著作权归作者所有,转载请注明原链接及出处。

引言

  之前项目中遇到数据拷贝、引用之间数据层级嵌套过深,拷贝的值相互之间影响的问题,后来引入了immutability-helper,使用过程中的一些总结,跟大家分享下,至于为什么不是immutable,请看下文分解,这里是@IT·平头哥联盟,我是首席填坑官——苏南

​  相信大家在面试/工作中都遇到过js对象/数组的拷贝问题,面试官问你,你一般怎么做??在现在ES6盛行的当下,不会一点ES6都不好意思说自己是前端(其实我一般都说自己是攻城狮、切图崽😝),我们想的大多第一想法,如下:

  • Object.assign - 最方便;
  • [...] - 最有逼格;
  • JSON.parseJSON.stringify - 完美组合;
  • $.extend() - jQuery时代的引领潮流时尚前沿的API;
  • 最后想到的才是自己递归实现一个;

  但是通常我们使用的Object.assign属于浅拷贝,当数据嵌套层级较深时,就……呵呵了;而JSON.parse、stringify它应该是创建一个临时可能很大的字符串,然后又访问解析器,性能是比较慢的。于是后来发现了 immutable「不可变数据」,曾经我也一度特别喜欢它,但时间久了,慢慢发现,它过于有个性了些、凡事都都没有任何商量的余地,所有的数据,从创建、变更、插入、删除等操作,都要按它的套路来,对于我这种一生放荡不羁爱自由的人来说,长时间的约束,是不能忍的;都说两人如果三观不合,是无法长久下去的,可能也是缘份吧,在后来的某一天偶然的闲逛中邂逅了新欢 ————Immutability Helpers

  嗯,今天的主题就是给大家分享一下,Immutability Helpers的一些用法,会介绍API的使用操作、小技巧和注意的点,如有理解不对:
  

太兴奋了,差点忘了,补充一下,一个简单的拷贝:

  //实现一个简单的递归数据拷贝
  let customClone = (rawObj)=>{
    let copyObj = {};

    for (var key in rawObj) {
      if( typeof rawObj[key] === 'object' && Object.prototype.toString.call(rawObj[key]) !== '[object Array]'){
          copyObj[key] = customClone(rawObj[key]);
      }else{
          copyObj[key] = rawObj[key];
      };
    };
    return copyObj;
  };
  let objA =  {"name":"苏南","sex":"男","height":"176"};
  let objB =  customClone(objA);
      objB.signature = "宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮";

  console.log(objA);
  console.log(objB);

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8,展示Object.assign拷贝问题

  • 补充一个 Object.assign 的坑 :
  let data = {
    a:1,
    b:2,
    children:{
      name:"苏南",
      organization:"@IT·平头哥联盟",
      job:"首席填坑官",
      address:"ShenZhen",
      age:18
    }
  };
  let data2 = Object.assign({},data);
  data2.children.age = 28;
  data2.children.job = "首席甩锅官";
  data2.b = 666;
  console.log("我是原始数据 data:",data);
  console.log("我是复制后的数据 data2:",data2);

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8,展示Object.assign拷贝问题

immutable 最后的一次回顾

  都说有了新欢,忘了旧爱,但我不是那种无情无义的人,最后正式介绍一下 immutable,为我俩的……画上一个圆满的句号:

  再次强调,并不是觉得immutable不好,不够强大,只是自己个人观点,有些不喜欢而已,各位immutable粉勿喷,想了解更多的同学可以点击这里

Immutable data encourages pure functions (data-in, data-out) and lends itself to much simpler application development and enabling techniques from functional programming such as lazy evaluation.

使用示例:
  
  const list1 = List([ 1, 2, 3 ]);
  const list2 = List([ 4, 5, 6 ]);
  const array = [ 7, 8, 9 ];
  const list3 = list1.concat(list2, array);
  console.log(list3) // List {size: 9, _origin: 0, _capacity: 9, _level: 5, _root: null, …} 是不能直接获取到数据的,须使用get,-- list3.get(0)
  
  let data = fromJS({
    obj:{}
  });
  let data1 = {
    a:1,
    b:2,
    children:{
      name:"苏南",
    }
  };
  let data2 = data.mergeIn(['obj'],data1,{c:666});
  console.log("获取的数据:",data2.getIn(['obj','c']));
  console.log("这里是由formJS创建的数据:",data2.getIn(['obj','children','name']));//

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8,展示Object.assign拷贝问题

使用immutable后,所有数据都要类似选择器,一个一个往下选择,并不是说它不好、功能不够强大,只是自己有些不喜欢它类似JQuery选择器一样的语法,get、getIn、set、List等的使用方式,当然它也是可以使用 toJS方法转回来的。

Immutability Helpers出场

gitHub上它对自己的介绍很简单:Mutate a copy of data without changing the original source —— 在不更改原始源的情况下改变数据副本。

  与它结缘,是因为它在react官方文档中出镜,而被我所宠幸,真的 ,只是因为在人群中多看了它一眼再也没能忘掉, 它跟immutable不一样,不会有那么多条条框框约束你,给你自由、给你独立的空间、给你独立的**,让你想用即用、用之即走~~(泥马,怎么有点像张小龙说它的小程序一样😬),但您放心,它的坑真的比小程序少,API也很简洁,接下来来看一下,它的基本用法:

  • $push —— 数组;
  • $unshift —— 数组;
  • $splice —— 数组;
  • $set —— 替换/覆盖/合并原数据;
  • $toggle —— array of strings ,toggles a list of boolean fields from the target object;
  • $unset —— remove the list of keys in array from the target object;
  • $merge —— 合并对象;
  • $apply —— passes in the current value to the function and updates it with the new returned value;
  • $add —— 新增;
  • $remove —— 删除。

以上基本就是它全部的API了,下面一起来看看,具体用法吧:

$push 的使用 :

  • 看名字就知道它的作用了啦,跟原生的push一样,不过写法有一点点不一样;
  let arr = [1,2,3,4,5,66];
  let arr2 = update(arr,{
    $push : ["a","b","c"], //一定要 []号的形式哦,不可以 "a";
    [4]:{ // !!index ,可以指定修改下标的值
      $set:"我是替换过的"
    }
  });
  console.log(arr2);

$unshift 的使用 :

  • 一样,跟原生的unshift,在原数组开头处插入,同样写法是以一个数组的形式;
  let arr = [1,2,3,4,5,66];
  let arr2 = update(arr,{
    $unshift : ["a","b","c"],
    [4]:{
      $set:"我是首席填坑官∙苏南"  //这里需要注意,它的操作是在 unshift之前执行的,也就是在原 arr 上查找 第4个下标
    }
  });
  console.log("原始数组",arr);// [1, 2, 3, 4, 5, 66] 相互之间并不会影响
  console.log(arr2); //["a", "b", "c", 1, 2, 3, 4, "我是首席填坑官∙苏南", 66]

$splice 的使用 :

  • 注意 :数组套数组,start,end, 插入的数据……,;
  let arr = [1,2,3,4,5,66];
  let arr2 = update(arr,{
    $splice : [[1,2,[66788,99],{a:123,b:"苏南"}]], // or [0,1,"从我开始是插入的内容",88,89,90,"后面可以很多,是数组、对象、字符串都行"]
  });
  console.log(arr2); 

  //复杂一些的用法:
  let obj={
    name:"immutable",
    list :[1,2,[90,55,44,3,22,55],3,4,6,7,8]
  };
  let obj2 = update(obj,{
    list:{
      [2]:value=>update(value,{
        $splice:[[0,2]]  // [90,55,44,3,22,55] => [44, 3, 22, 55]
      })
    }
  });

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8,immutability-helper $splice的使用展示
本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8,immutability-helper $splice的使用展示,格式错误的警告

$set 的使用 :

  • 上面已经演示过了,其实有点替换的意思,当有重复的值时,就会覆盖,没有就新增,来展示复杂一点的场景,层级深的数据,也不会相互影响;
  let obj={
    name:"immutable",
    children:{
      address:"ShenZhen",
      hobby:"@IT·平头哥联盟-前端开发"
    }
  };
  let obj2 = update(obj,{
    $set : {name:"immutability-helper",other:"其他字段,如微信公众号:honeyBadger8,每周为你带来最新分享"}
  });
  let obj3 = update(obj,{
    name:{
      $set : "苏南"
    },
    children:{
      hobby:{
        $set:"首席填坑官 - javascript"
      }
    }
  });
  console.log("原始数据:",obj); 
  console.log("obj2:",obj2); 
  console.log("obj3",obj3); 

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8,immutability-helper $set的使用展示,1024请不要叫我程序园,我是有温度的攻城狮

$toggle 的使用:

  • 听名字,应该就能猜出来,开关切换的意思;
  • Boolean 布尔值的切换,如果你是强制要 Number 类型 的 0、1,那么使用引方法的时候就要注意了;
  let obj={
    name:"immutable",
    a:false,
    b:true,
    c:1,
    d:0
  };
  let obj2 = update(obj,{
    $toggle:['b','a',"c","d"],
  });
  console.log("原始数据:",obj);
  console.log("obj2:",obj2);

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8,immutability-helper $toggle的使用展示,1024请不要叫我程序园,我是有温度的攻城狮

$unset 的使用:

  • 它跟$set相反,有点remove的味道,但又貌似有不同的之处,当操作的对象为object时key是删除了;而数组array中它的值没有了,却保留了下标,不改变数组的长度,删除数组建议还是用$splice;请看下图:
  let arr = [1,2,3,4,5,6];
  let obj={
    name:"immutable",
    children:{
      address:"ShenZhen",
      hobby:"写博客"
    }
  };
  let obj2 = update(obj,{
    $unset : ["name"],
    children:{
      $unset:["address"]
    }
  });
  console.log("原始数据:",obj);
  console.log("obj2:",obj2);

  let arr2 = update(arr,{
    $unset : [1]
  });
  console.log("arr2:",arr2,arr2.length);

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8,immutability-helper $unset的使用展示,我是有温度的攻城狮

$merge 的使用:

  • $merge 跟我们最爱的Object.assign一样,做合并操作的,但它比assign优秀很多,深层次拷贝,不会相互影响 :
  let arr = [1,2,3,4,5,6];
  let obj={
    name:"immutable",
    children:{
      address:"ShenZhen",
      hobby:"写博客",
      array:["我不是程序员","切图崽了解一下"],
    }
  };
  let obj2 = update(obj,{
    $merge:{
      arr
    },
    children:{
      array:{
        $merge:{items:["从前有坐山","山里有个庙"]},
        $splice:[[3,0,"住着一个小和尚"]]
      }
    }
  });
  console.log("原始数据:",obj);
  console.log("obj2:",obj2);

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8,immutability-helper $merge的使用展示,我是有温度的攻城狮

$apply 的使用:

  • $apply 基于当前值进行一个函数运算,从而得到新的值 :
  • 注意 :它必须是一个 function 哦!
  let obj={
    name:"immutable",
    children:{
      items:["从前有一坐山"],
      array: [1,2,3,4,5,6],
    }
  };
  let obj2 = update(obj,{
    name:{
      $apply:(val)=>("首席填坑官")
    },
    children:{
      items:{
        $apply:(val)=>{
          console.log("旧值",val);
          return [3,0,"住着一个小和尚"]
        }
      },
      array:{
        $apply:(val)=>(val.reverse()) //必须是一个函数
      }
    }
  });
  console.log("原始数据:",obj);
  console.log("obj2:",obj2);

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8,immutability-helper $apply的使用展示,我是有温度的攻城狮
本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8,immutability-helper $apply的使用展示,必须是function

$remove 的使用:

  • $remove 一定一定 要是使用SetMap 创建的数组:
  • 要删除的值,必须是数组成存在的,如值不存在则忽略,$remove:[2,666],2会删除,6则会被忽略;
  • 这个api有点奇怪,正常普通的数组 [],这样的删除不了!!;
  • 常见错误如下图:
  let obj={
    name:"immutable",
    children:{
      array:new Set([1, 2, 3, 4, 4]),
    }
  };
  let obj2 = update(obj,{
    children:{
      array:{
        $remove:[2],
      },
    }
  });
  console.log("原始数据:",obj);
  console.log("obj2:",obj2);

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8,immutability-helper $remove的使用展示,必须是 new Set Map创建
本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8,immutability-helper $remove的使用展示,必须是function

$add 的使用:

  • $add 跟刚才的 $remove 一样要使用Map/Set,$add方法也跟 es6 Map/Set的 add方法一致:
  • 只是写的时候也要注意一些, [ [] ] ,嵌套!
  let obj={
    name:"immutable",
    array:new Map([["a",1],["b",2]]),
  };
  let obj2 = update(obj,{
    array:{
      $add:[["66",56]],
    },
  });
  console.log("原始数据:",obj);
  console.log("obj2:",obj2);
  console.log("获取key a:",obj2.array.get('a'));

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8,immutability-helper $add的使用展示,必须是 new Set Map创建

Immutability Helpers的高阶用法:

  • 还可以自定义方法,如 定义一个 $trinocular 方法,来判断数组中的值;
  • 只是一个简单的示例,更多复杂的用法,可以自己去探索哦 去官方 github 👈
  update.extend('$trinocular', function(proportion, original) {
    return  original > 88 ? (original/proportion ): (proportion+original);
  });
  let array =[56,33,55,777,322,444,61,12,34,52,245];
  let array2 = array.map((k,v)=>update(k,{
    $trinocular:2
  }))
  console.log("原始数据:",array);
  console.log("array2:",array2);

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8,immutability-helper 高阶用法

总结 :以上就是基础 API 的用法 ,添加了一些官方示例,没有讲到的组合使用,以及使用过程中,可能出现的一些错误,需要留意的地方,更多定制高级用法,有兴趣的同学可以自行了解一下。

  以上就是今天为大家带来的分享,它可能没有 immutable 那么多功能,但贵在简洁,不会有太多的约束,如理解有误之处,欢迎各位大佬纠正,毕竟我还只是个宝宝——新手上路中!🤪。

  下方是我弄的一个公众号,欢迎关注,以后文章会第一时间,在公众号上更新,原因是之前分享的有两篇文章,竟然被其他公众号抄袭了😭,前些天去更新发表的时候,微信提示我文章已经不是原创了检测到相同的文章,宝宝心里那个凉啊~,果断申诉告了对方(是一个培训学校公众号,好气哦),补了掘金发布的链接和截图日期,万幸最后胜诉了🤗!👇👇

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8

作者:苏南 - 首席填坑官
链接:https://honeybadger8.github.io/blog/
交流:912594095、公众号:honeyBadger8
本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

2018年文章汇总~

2018文章汇总,IT·平头哥联盟 主要分享前端、测试 等领域的积累,文章来源于(自己/群友)工作中积累的经验、填过的坑,希望能尽绵薄之力 助其他同学少走一些弯路,前端:前端开发、新手上路、HTML、CSS/CSS3、javascript、js;测试:自动化、性能、接口系列,公众号:honeyBadger8;鲁迅说:世上本无路,只是走的人多了,也就成了路; 汇聚我们的点滴 尽绵薄之力 助他人成长 —— 欢迎您加入我们,一起分享您过往的成长点滴,写下您的心灵历程,蜜獾(读音:mi huan;学名:Mellivora capensis)是鼬科蜜獾属下唯一一种动物,雄性平均体长98厘米,雌性平均体长91厘米,雄性肩高39厘米,雌性肩高35厘米,雄性体重9-14千克,雌性体重5-10千克。背部为灰色。它的皮毛松弛而且非常粗糙,体型和獾的体型相当,其寿命可达24岁,这个生物简直就是世间熊孩子大合集,突出一个能打和不怂,虽然长得有点可爱吧,苏南的专栏,IT平头哥联盟

1、Javascript系列

2、小程序系列

3、CSS/HTML系列

4、软件测试系列

5、程序员日常系列

6、周五不聊技术系列

##尾声:
从10月到现在的文章汇总,期待2019年能做的更好。

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:IT平头哥联盟

作者:苏南 - 首席填坑官

链接:https://blog.csdn.net/weixin_43254766

交流群:912594095[资源获取/交流群]、公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系IT平头哥联盟获得授权,非商业转载请注明原链接及出处。

动画一点点Canvas—手把手教你如何绘制一辆会跑车

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

作者:首席填坑官∙苏南
来源:@IT·平头哥联盟
交流群:912594095,公众号:honeyBadger8

前言

  灵感来源于前些天捡到钱了,就想着是时候给自己买辆车了,工作这么多年了应该对自己好一点,在网上搜索了一下看到这个车型。其实几年前是买过一辆的,但是不到一个月就被人偷了,伤心了好久。这次一定锁好,上三把锁保证小偷再也偷不走了,于是我拿着钱去买了些益力多,跟同事分享了,心情还是比较愉悦的。—— @IT·平头哥联盟,我是首席填坑官苏南(South·Su) ^_^~

  但想来作为一名程序(嗯,还是个菜鸟,专业首席填坑官哦😇),车基本是用不上的啦,为啥?因为有改不完的bug,记得刚毕业那时候最大的梦想是:“撩个妹子 携手仗剑天涯,惩奸除恶、劫富济贫,快意人生~”,无奈一入IT深似海,从此BUG改不完啊。所以还是多学习吧,这不就学着画了个车满足一下自己的心里安慰,在这里把大家一起分享一下,唉,有点扯偏了~,大家先来看一下最终的效果图吧!

本文由@IT·平头哥联盟-首席填坑官∙苏南分享
  

过程解析:

  效果已经看了到,有没有感觉很牛B??其实也就一般般啦~,接下来就让我带大家一起分解一下它的实现过程吧
  canvas中文名中:画布,它就跟我们在纸上画画一样,画某样东西之前,我们要先学会构思、拆解你要画的东西,就跟汽车、手机等东西一样,一个成品都是由很多零件组成的,当你拆解开来,一点点完成再组装的,就会变的容易的多。

  • 绘制地平线
    • 首先我们基于画布的高度取一定的比例,在底部画一条线;
    • 从观察动画,它还有几个点,这个是用于视差滚动的时候,来欺骗我们的眼睛的,直接一条线肯定再怎么动也没有用,点的移动可以形成一个动画的效果;
    • 再加一点修饰,几个点移动有点太单调了,大家可以想像一下,当你骑车的时候,车的速度与周围的事物、建筑、人产生一个交差,那种感觉是很刺激的,那么我们也来加一点东西,让动画看起来更丰富一些,我选择了 三条线,线本身有个渐变过渡的效果,比纯色要灵动些动画看起来更逼真,而且初始它是不在画布范围内的,这个点要注意一下;
    • 下面的两张图,第二张是生成gif工具里截出来的,它就是动画的分解,其实所谓的动画,也是由一张张静态图组成,然后快速过渡,让视觉形成了视差,最后欺骗了大脑,我看见动画了……
    • 知识点lineTostrokeStylestrokerestore等,这里不一一讲解了,如有不了解可自行查看 w3school API

本文由@IT·平头哥联盟-首席填坑官∙苏南分享
本文由@IT·平头哥联盟-首席填坑官∙苏南分享

  horizon(){
      /**
      * 轮子的底部,也称地平线:
      1.清除画布
      2.画一条直线,且高度6px
      本文@IT·平头哥联盟-首席填坑官∙苏南分享,非商业转载请注明原链接及出处
       */

      this.wheelPos = [];
      this.ctx.save();
      this.ctx.clearRect(0, 0, this.canvasW, this.canvasH);

      let horizonX = 0,horizonY = this.canvasH-100;
      this.ctx.beginPath();
      this.ctx.strokeStyle = this.color;
      this.ctx.lineWidth=6;
      this.ctx.moveTo(horizonX,horizonY);
      this.ctx.lineTo(this.canvasW,horizonY);
      this.ctx.closePath();
      this.ctx.stroke();

      Array.from({length:5}).map((k,v)=>{
          let dotProportion = (this.canvasW*0.49)*v-this.oneCent;
          this.wheelPos.push({x:dotProportion,y:horizonY-this.wheelRadius});
          let startX = dotProportion-(this.animateNum*2); //用于动画滚动移动
          this.ctx.beginPath();
          this.ctx.strokeStyle = "#f9f8ef";
          this.ctx.lineWidth=6;
          this.ctx.moveTo(startX,horizonY);
          this.ctx.lineTo(startX+5,horizonY);
          this.ctx.closePath();
          this.ctx.stroke();
      });
      this.ctx.restore();
      this.shuttle();
      // this.wheel();
  }
  shuttle(){
      /**
      * 画几根横线,有点视差,感觉骑车在飞速穿梭的感觉:
      本文@IT·平头哥联盟-首席填坑官∙苏南分享,非商业转载请注明原链接及出处
       */
      let shuttleX = this.canvasW+100,
              shuttleY = this.canvasH/6;
      let shuttleW = shuttleX+100;
      [0,40,0].map((k,v)=>{
          let random = Math.random()+2;
          let x = shuttleX+k-(this.animateNum*(2.2*random));
          let y = shuttleY+v*24;
          let w = shuttleW+k-(this.animateNum*(2.2*random));
          let grd=this.ctx.createLinearGradient(x,y,w,y);
          grd.addColorStop(0,"#30212c");
          grd.addColorStop(1,"#fff");
          this.ctx.beginPath();
          this.ctx.lineCap="round";
          this.ctx.strokeStyle = grd;
          this.ctx.lineWidth=3;
          this.ctx.moveTo(x,y);
          this.ctx.lineTo(w,y);
          this.ctx.stroke();
          this.ctx.closePath();

      });

  }
  • 绘制车轮

    • 接下来我们来画车的两个轮子,轮子的位置在哪里呢?我也是观察了有一会才发现的,其实刚才的地平线,两点的位置,就是车轮的中心点;
    • 所以在刚才绘制点的时候,就记录了5个点的坐标,这样就省去了一次计算,中间有两次是我们需要的
    • 知识点arcfill

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

  console.log(this.wheelPos);
  this.wheelPos = this.wheelPos.slice(1,3); //这里取1-3
  console.log(this.wheelPos);
  this.wheelPos.map((wheelItem,v)=>{
    let wheelItemX = wheelItem.x, 
    wheelItemY= wheelItem.y-this.wheelBorder/1.5;

    //外胎
    this.ctx.beginPath();
    this.ctx.lineWidth=this.wheelBorder;
    this.ctx.fillStyle = "#f5f5f0";
    this.ctx.strokeStyle = this.color;
    this.ctx.arc(wheelItemX,wheelItemY,this.wheelRadius,0,Math.PI*2,false);
    this.ctx.closePath();
    this.ctx.stroke();
    this.ctx.fill();


    //最后两轮胎中心点圆轴承
    this.axisDot(wheelItemX,wheelItemY);
    this.ctx.restore();
    
  });
  this.ctx.restore();
  • 同理,上面画好了两个圆,但车轮肯定有轴承,前后轮我做了些汪样的处理,后轮是实心的加了个填充;
  • 前轮是画了一点断点的圆,用于动画的转动,
  • 在外轮的半径上进行缩小一定比较,画内圈,这里我取了外圈的.94,作为内圆的半径,
  • 还加了两个半圆的描边修饰,让动画跑起来的时候,车轮有动起来的感觉,半圆 Math.PI 就是一个180,(Math.PI * degrees) / 180; degrees 就是我们想要绘制的起始/结束角度;
  • 从下图可以看出,圆的填充用了 放射性渐变,createRadialGradient-创建放射状/环形的渐变(用在画布内容上)

本文由@IT·平头哥联盟-首席填坑官∙苏南分享
本文由@IT·平头哥联盟-首席填坑官∙苏南分享
本文由@IT·平头哥联盟-首席填坑官∙苏南分享

  context.createRadialGradient(x0,y0,r0,x1,y1,r1);
  + createRadialGradient API 说明:
    x0 = 渐变的开始圆的 x 坐标
    y0 = 渐变的开始圆的 y 坐标
    r0 = 开始圆的半径
    x1 = 渐变的结束圆的 x 坐标
    y1 = 渐变的结束圆的 y 坐标
    r1 = 结束圆的半径

    详细使用请看下面代码的实例
  let scaleMultiple = this.wheelRadius*.94;
  let speed1 = this.animateNum*2; //外圈半圆速度
  let speed2 = this.animateNum*3; //内小圈半圆速度
  //后轮
  if(v === 0){
    
    //内圆
    this.ctx.beginPath();
    let circleGrd=this.ctx.createRadialGradient(wheelItemX,wheelItemY,18,wheelItemX,wheelItemY,scaleMultiple);
      circleGrd.addColorStop(0,"#584a51");
      circleGrd.addColorStop(1,"#11090d");
    this.ctx.fillStyle = circleGrd;
    this.ctx.arc(wheelItemX,wheelItemY,scaleMultiple,0,Math.PI*2,false);
    this.ctx.fill();
    this.ctx.closePath();

    //两个半圆线
    
    [
      {lineW:2,radius:scaleMultiple*.6,sAngle:getRads(-135+speed1) , eAngle:getRads(110+speed1)},
      {lineW:1.2,radius:scaleMultiple*.45,sAngle:getRads(45+speed2) , eAngle:getRads(-50+speed2)}
    ].map((k,v)=>{
      this.ctx.beginPath();
      this.ctx.lineCap="round";
      this.ctx.strokeStyle ="#fff";
      this.ctx.lineWidth=k.lineW;
      this.ctx.arc(wheelItemX,wheelItemY,k.radius,k.sAngle,k.eAngle,true);
      this.ctx.stroke();
      this.ctx.closePath();

    });
    this.ctx.restore();

  }
  • ** 拉下来我们就拿前轮开刀** :
  • 前轮也是画了几个半圆,大概就是以某个角度为起点,然后分别画几个半圆,整体是一个半径,中间有断开,如: eAngle = [0,135,270], sAngle = [-45,0,180];就能画出如下图的圆:

本文由@IT·平头哥联盟-首席填坑官∙苏南分享
本文由@IT·平头哥联盟-首席填坑官∙苏南分享

  • ** 具体实现请看下面代码 ** :
  //两个圆,再缩小一圈,画线圆
  Array.from({length:3}).map((k,v)=>{
    let prevIndex = v-1 <= 0 ? 0 : v-1;
    let eAngle = v*135, sAngle = -45+(prevIndex*45)+v*90;
    let radius = scaleMultiple*.75;
    let _color_ = "#120008";
    this.ctx.beginPath();
    this.ctx.lineCap="round";
    this.ctx.strokeStyle = _color_;
    this.ctx.lineWidth=3.5;
    this.ctx.arc(wheelItemX,wheelItemY,radius,getRads(sAngle+speed1),getRads(eAngle+speed1),false);
    this.ctx.stroke();
    this.ctx.closePath();

    if(v<2){
      //再缩小一圈
      let eAngleSmaller = 15+ v*210, sAngleSmaller = -30+v*90;
      let radiusSmaller = scaleMultiple*.45;
      this.ctx.beginPath();
      this.ctx.lineCap="round";
      this.ctx.strokeStyle = _color_;
      this.ctx.lineWidth=3;
      this.ctx.arc(wheelItemX,wheelItemY,radiusSmaller,getRads(sAngleSmaller+speed2),getRads(eAngleSmaller+speed2),false);
      this.ctx.stroke();
      this.ctx.closePath();
    }
    this.ctx.restore();
  });
  • 绘制车身车架

    • 车架,应该也是本次分享中较大的难点之一,刚开始我也是这么认为的,但认真冷静、冷静、静静之后分析也还好,
    • 最开始是用了最笨的办法,lineTOmoveTo、一根一根线的画,画到一半时发现画两个三角或者一个菱形即可,然后再把几根主轴重新画一下,于是两种方法都尝试了一下,
      • 先说三角的吧,配合下面画的一个图讲解一下,
      • 找到圆盘的中心点,介于后轮半径之上;
      • 分析车架的结构,我们可以看为是一个菱形,也可以看着是两个三角形,这里以三角为例,菱形可以看 carBracket2方法;
      • 首先算出三角形的起点、再算出三角形的角度、高度,请看下面示图;
      • 最后在后轮的中心点盖上一个圆点 用于遮挡三角的部分
    • 菱形 就要简单些的,但看起来逼格没有这么高端,就是用lineTo点对点的划线,
    • 以上就是车架的绘制过程,其实感觉菱形是是要简单、代码量也少些的,有兴趣的同学可以自己尝试一下,大家可以看下面的主要代码,新手上路,如果有更好的方式,欢迎老司机指点:

结论 :使用moveTo把画布坐标从O移动到A点 x/y,lineToA开始画到B结束,再从BC点,闭合,即一个三角完成

本文由@IT·平头哥联盟-首席填坑官∙苏南分享
本文由@IT·平头哥联盟-首席填坑官∙苏南分享
本文由@IT·平头哥联盟-首席填坑官∙苏南分享
本文由@IT·平头哥联盟-首席填坑官∙苏南分享

//方法二:三角形
  …………此处省略N行代码
  [
  {
    moveX:triangleX1,
    moveY:triangleY1,
    lineX1:coordinateX,
    lineY1:triangleH1,
    lineX2:discX,
    lineY2:discY,
  },
  {
    moveX:triangleX2+15,
    moveY:triangleY2,
    lineX1:triangleX1,
    lineY1:triangleY1,
    lineX2:discX,
    lineY2:triangleH2,
  },
  ].map((k,v)=>{
    this.ctx.beginPath();
    this.ctx.moveTo(k.moveX,k.moveY); //把坐标移动到A点,从A开始
    this.ctx.strokeStyle = this.gearColor;
    this.ctx.lineWidth=coordinateW;
    this.ctx.lineTo(k.lineX1,k.lineY1);//从A开始,画到B点结束
    this.ctx.lineTo(k.lineX2,k.lineY2); //再从B到C点,闭合
    this.ctx.closePath();
    this.ctx.stroke();
    this.ctx.restore();
  });
  ……

//方法一:菱形
  
  …………此处省略N行代码
  this.ctx.beginPath();
  this.ctx.strokeStyle = this.gearColor;
  this.ctx.lineWidth=coordinateW;
  this.ctx.moveTo(polygon1X,polygon1Y);
  this.ctx.lineTo(coordinateX,height);
  this.ctx.lineTo(discX,discY); 
  this.ctx.lineTo(polygon2X,polygon1Y+5);
  this.ctx.lineTo(polygon2X-5,polygon1Y);
  this.ctx.lineTo(polygon1X,polygon1Y);
  this.ctx.closePath();
  this.ctx.stroke();
  ……

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

  • 绘制车的豪华宝坐、扶手
    • 坐位一开始是比较懵逼的,不知道如何下手,圆也不圆、方也不方,后面又去复习一下canvas的API,发现了quadraticCurveTo能满足这个需求,—— 二次贝塞尔曲线
    • 画完之后,思考了很久,也没有发现什么技巧,或者规律,可能数学学的不好,没办法只能这样慢慢描了
    • 扶手也是一样的,开始尝试quadraticCurveTo,半天也没画成功,后面尝试去找了它邻居bezierCurveTo,—— 三次贝塞尔曲线
    • 提示:三次贝塞尔曲线需要三个点。前两个点是用于三次贝塞尔计算中的控制点,第三个点是曲线的结束点。曲线的开始点是当前路径中最后一个点
    • 知识点quadraticCurveTobezierCurveTocreateLinearGradient

本文由@IT·平头哥联盟-首席填坑官∙苏南分享
本文由@IT·平头哥联盟-首席填坑官∙苏南分享
本文由@IT·平头哥联盟-首席填坑官∙苏南分享

  //坐位
  this.ctx.restore();
  let seatX = (discX-85),seatY=discY-140;
  let curve1Cpx = [seatX-5,seatY+30,seatX+75,seatY+8];
  let curve2Cpx =[seatX+85,seatY-5,seatX,seatY]; 
  this.ctx.beginPath();
  // this.ctx.fillStyle = this.gearColor;
  let grd=this.ctx.createLinearGradient(seatX,seatY,seatX+10,seatY+60); //渐变的角度 
  grd.addColorStop(0,"#712450");
  grd.addColorStop(1,"#11090d");
  this.ctx.fillStyle = grd;
  this.ctx.moveTo(seatX,seatY);
  this.ctx.quadraticCurveTo(...curve1Cpx);
  this.ctx.quadraticCurveTo(...curve2Cpx);
  this.ctx.fill();

  //车前轴上的手柄
  let steeringX = lever1X-20,steeringY = lever1Y-45;
  let steeringStep1 = [steeringX+40,steeringY-10,steeringX+40,steeringY-10,steeringX+35,steeringY+15]
  let steeringStep2 = [steeringX+30,steeringY+25,steeringX+25,steeringY+23,steeringX+18,steeringY+23]
  this.ctx.beginPath();
  this.ctx.lineCap="round";
  this.ctx.strokeStyle = "#712450";
  this.ctx.lineWidth=coordinateW;
  this.ctx.moveTo(steeringX,steeringY); //40 60;
  this.ctx.bezierCurveTo(...steeringStep1);
  this.ctx.bezierCurveTo(...steeringStep2);
  this.ctx.stroke();
  this.ctx.closePath();
  • 绘制车的发动机、脚踏板
    • 到了这里,也快接近本文的尾声了,接下来要讲的是是车辆中最重要的部分,车中间齿轮盘,一辆车没有它,你做的再好也是白搭了;
    • 前面多次讲到齿轮的中心点,包括两个三角都是以它的中心计算的三角角度,知道了位置那就容易了,一样的先画几个圆,每个按一定的比例缩小;
    • 然后外围再画一圈锯齿,这样齿轮大概就画好了,齿轮的技巧在于以圆盘为中心点,画一圈线,它跟时钟的刻度原理是一样的;
    • 脚踏板,这个好理解,就是用lineTo画两跟线,其中一根进行一个90度的旋转就ok了,但重点是它在动画过程中的一个过程呢,我的分析过程是这样:
      • 竖着的这根轴是,以圆盘齿轮的中点为基点 N* (Math.PI / 180)转动;
      • 横着的这根轴,也就是脚踏板,它是以竖着的轴底部为Y轴中心点,以自身宽度的二分之一为X轴为中心点,同样以 N* (Math.PI / 180)rotate角度旋转。
    • 说了这么多,我们来看几张动态图吧,顺便贴上代码:

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

  discGear(coordinateX,coordinateY,coordinateW){
    //车中间齿轮盘 disc
    let discX = coordinateX,discY = coordinateY;
    let discRadius = this.wheelRadius*.36;//车轮的3.6;

    let discDotX = discX+discRadius+8,discDotY = discRadius/.98;
    this.ctx.restore();
    this.ctx.save();
    this.ctx.translate(discX,discY);
    // this.ctx.rotate(-(Math.PI/2));

    Array.from({length:30}).map((v,index)=>{
      let radian = (Math.PI / 15) ;
      this.ctx.beginPath();
      this.ctx.lineCap="round";
      this.ctx.strokeStyle = this.color;
      this.ctx.rotate(radian);
      this.ctx.lineWidth=3;
      this.ctx.moveTo(0,discDotY);
      this.ctx.lineTo(1.5,discDotY);
      // ctx.arc(discDotX,discDotY,6,0,Math.PI*2,false);
      this.ctx.closePath();
      this.ctx.stroke();

    });
    this.pedal(discX,discY,discRadius);
    this.pedal(discX,discY,discRadius,1);
    
    this.ctx.restore();
  }
  pedal(coordinateX,coordinateY,discRadius,turnAngle=0){

    //脚踏板,分两次初始化,一次在中心齿轮绘制之前,一次在之后,

    let pedalX = coordinateX, pedalY = coordinateY - discRadius*.7;
    let pedalW = 6,
        pedalH =  discRadius*1.9;
    let radian = (this.animateNum)*(Math.PI / 180) ;
    let radianHor = (this.animateNum)*(Math.PI / 180) ;
    let turnAngleNum = 1;
    let moveY = 28;
    if(turnAngle !== 0){
      this.ctx.rotate(-180*(Math.PI/180));
      turnAngleNum = (Math.PI/180);
    };
    this.ctx.beginPath();
    this.ctx.rotate(radian*turnAngleNum);
    this.ctx.lineCap="round";
    this.ctx.strokeStyle = this.gearColor;
    this.ctx.lineWidth=pedalW;
    this.ctx.moveTo(-1,moveY);
    this.ctx.lineTo(0,pedalH);
    this.ctx.closePath();
    this.ctx.stroke();
    
    this.ctx.save();
    let pedalHorW = pedalH/1.5,pedalHorH=pedalW;
    this.ctx.translate(0,pedalH);
    this.ctx.beginPath();
    this.ctx.rotate(-radianHor);

    this.ctx.lineCap="round";
    this.ctx.fillStyle = "#fff";
    this.ctx.strokeStyle = this.gearColor;
    this.ctx.lineWidth =2;
    this.ctx.roundRect(-pedalHorW/2,-2,pedalHorW,pedalHorH,5);
    this.ctx.closePath();
    this.ctx.fill();
    this.ctx.stroke();

    this.ctx.restore();
  }
  • 绘制车的链条
    • 链条用的是 bezierCurveTo ,cp1x,cp1y,cp2x,cp2y,x,y等参数画出来的,具体看下面代码吧,其实就是两个半椭圆的拼接……

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

  //链条

  let chainW = ( coordinateX+discRadius - this.wheelPos[0].x) / 2;
  let chainX = this.wheelPos[0].x +chainW-5 ;
  let chainY = coordinateY;
  this.ctx.save();
  this.ctx.translate(chainX,chainY+4.8);
  this.ctx.rotate(-2*(Math.PI/180));
  let r = chainW+chainW*.06,h = discRadius/2;
  this.ctx.beginPath();
  this.ctx.moveTo(-r, -1);
  this.ctx.lineWidth=3;
  this.ctx.strokeStyle = "#1e0c1a";
  this.ctx.bezierCurveTo(-r,h*1.5,r,h*4,r,0);
  this.ctx.bezierCurveTo(r,-h*4,-r,-h*1.5,-r,0);
  this.ctx.closePath();
  this.ctx.stroke();
  this.ctx.restore();

尾声

  以上就是今天@IT·平头哥联盟-首席填坑官苏南给你带来的分享,整个车的绘制过程,感觉车架部分应该还有更好的做法,如果您有更好的建议及想法,欢迎斧正,最后送上完整的示例图!
  文章源码获取👈
  想直接在线预览 👈

本文由@IT·平头哥联盟-首席填坑官∙苏南分享

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮,公众号:honeyBadger8

作者:苏南 - 首席填坑官

链接:https://honeybadger8.github.io/blog/

交流群:912594095,公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明链接及出处。

本文由@IT·平头哥联盟-首席填坑官∙苏南分享,@IT·平头哥联盟 主要分享前端、测试 等领域的积累,文章来源于(自己/群友)工作中积累的经验、填过的坑,希望能尽绵薄之力 助其他同学少走一些弯路

webpack4配置详解之逐行逐句分析

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8,webpack4,从0配置到项目搭建

前言

  经常会有群友问起webpackreactredux、甚至create-react-app配置等等方面的问题,有些是我也不懂的,慢慢从大家的相互交流中,也学到了不少。

​  今天就尝试着一起来聊聊Webpack吧,旨在帮大家加深理解、新手更容易上路,都能从0到1搭建配置自定属于自己的脚手架,或对已封装好的脚手架有进一步的巩固,接下来苏南会详细讲解webpack中的每一个配置字段的作用(部分为webpack4新增)。

近两年,前端一直在以一个高速持续的过程发展,常常会有网友在调侃老了、学不动了,

虽是在调侃却又间接阐述着无奈,迫于生活的压力,不得不提速前行,

因为没有谁为你而停留,公司不会、社会不会、同伴不会……,停下可能将意味着淘汰 —— 理想很丰满,现实很骨感,所以让我们一起进步,共同加薪,奋斗吧*年,加油。。

~~吐槽过了,接着聊正事~~。

  原谅我控制不住自己,想问下各位,昨天刚刚过去的双十一你脱单了吗?

以上为自定配置中使用频率较高的选项,公众号:honeyBadger8

  • 人生若只如初见,何事秋风悲画扇;
  • 等闲变却故人心,却道故人心易变;
  • 骊山语罢清宵半,夜雨霖铃终不怨。

各位大佬早安,这里是@IT·平头哥联盟,我是首席填坑官∙苏南,用心分享 做有温度的攻城狮。

公众号:honeyBadger8,群:912594095

entry

  • 这个不用解释了,看名字就是知道,它就是通往天堂/地狱的入口,一切的苦难从这里开始,也从这里结束。
  • 简单介绍几种写法:
//方式一:单文件写法
entry: {
    index: './src/pages/route.js',
    //about: './src/pages/about.js',
    //other:()=>{...}
}

//方式二:多文件写法
entry: {
    /*index:[
        'webpack-hot-middleware/client',
        './src/root.js'
    ],*/
    index: ['./src/root.js'],
    vendors : ['react','react-dom','redux','react-router','classnames'],
}

output - 输出

  • 它位于对象最顶级键(非常重要),如果说entry是一扇门,output就是审判官,决定着你是上天堂还是入地狱;
  • 指示 webpack 如何去输出、以及在哪里输出、输出的格式等;
  • path: 输出文件的目录,
  • filename:输出的文件名,它一般跟你entry配置相对应,如:js/[name].js name在这里表示的是[indexvendors],
  • chunkFilename:块,配置了它,非入口entry的模块,会帮自动拆分文件,也就是大家常说的按需加载,与路由中的 require.ensure相互应
  • publicPath:文件输出的公共路径,
  • pathinfo:即保留相互依赖的包中的注释信息,这个基本不用主动设置它,它默认 development 模式时的默认值是 true,而在 production 模式时的默认值是 false,
  • 主要的就是这些,还有一些其他的librarylibraryTargetauxiliaryComment等,感兴趣的可自行了解,
output: {
    path: path.resolve(__dirname, '../assets'),
    filename: 'js/[name].js',
    chunkFilename: 'js/[name].[chunkhash:8].js',
    publicPath: '/_static_/', //最终访问的路径就是:localhost:3000/_static_/js/*.js
    //pathinfo:true,
}

hash

  • 常用的有三种:
模板 描述
hash 模块标识符的hash,一般应用于filename:'[name].[hash].js'
chunkhash 按需分块内容的 hash,它是根据chunk自身的内容计算而来
contenthash 这个没有用过,看了下文档它是在提取css文件时根据内容计算而来的 hash ,结合ExtractTextWebpackPlugin插件使用
hash长度 默认20,可自定:[hash:8]、[chunkhash:16]

mode

  • 这个属于webpack4才新增的,4之前大家一般用DefinePlugin插件设置
  • mode:development``,productionnone
  • development : 开发模式,打包的代码不会被压缩,开启代码调试,
  • production : 生产模式,则正好反之。
//方法一
webpack --mode development/production

//方法二
……
mode:'development/production'
……

devtool

  • 控制是否生成,以及如何生成 source map文件,开发环境下更有利于定位问题,默认 false,
  • 当然它的开启,也会影响编译的速度,所以生产环境一定一定记得关闭;
  • 常用的值:cheap-eval-source-mapeval-source-mapcheap-module-eval-source-mapinline-cheap-module-source-map等等,更详细的可以去官方查看
  • 本人一般使用:eval-source-map较多,每个都有它不一样的特性,有兴趣的同学可以一一尝试,

以上为自定配置中使用频率较高的选项,公众号:honeyBadger8

optimization

  • optimization是webpack4新增的,主要是用来让开发者根据需要自定义一些优化构建打包的策略配置,
  • minimize:true/false,告诉webpack是否开启代码最小化压缩,
  • minimizer:自定js优化配置,会覆盖默认的配置,结合UglifyJsPlugin插件使用,
  • removeEmptyChunks: bool 值,它检测并删除空的块。将设置为false将禁用此优化,
  • removeEmptyChunks: bool 值,它检测并删除空的块。将设置为false将禁用此优化,
  • nodeEnv:它并不是node里的环境变量,设置后可以在代码里使用 process.env.NODE_ENV === 'development'来判断一些逻辑,生产环境UglifyJsPlugin会自动删除无用代码,
  • splitChunks :取代了CommonsChunkPlugin,自动分包拆分、代码拆分,详细默认配置:
  • 默认配置,只会作用于异步加载的代码块 —— chunks: 'async',它有三个值:all,async,initial
//环境变更也可以直接 在启动中设置
 //webpack --env.NODE_ENV=local --env.production --progress

//splitChunks 默认配置
splitChunks: {
  chunks: 'async',
  minSize: 30000,
  maxSize: 0,
  minChunks: 1,
  maxAsyncRequests: 5,
  maxInitialRequests: 3,
  automaticNameDelimiter: '~',
  name: true,
  cacheGroups: {
    vendors: {
      test: /[\\/]node_modules[\\/]/,
      priority: -10
    },
    default: {
      minChunks: 2,
      priority: -20,
      reuseExistingChunk: true
    }
  }
}
  • runtimeChunk: 提取 webpack 运行时代码,它可以设置为:boolean、Object
  • 该配置开启时,会覆盖 入口指定的名称!!!
optimization: {
    runtimeChunk:true,//方式一
  runtimeChunk: {
    name: entrypoint => `runtimechunk~${entrypoint.name}` //方式二
  }
}

以上为自定配置中使用频率较高的选项,公众号:honeyBadger8

resolve - 配置模块如何解析

  • extensions:自动解析确定的扩展,省去你引入组件时写后缀的麻烦,
  • alias:非常重要的一个配置,它可以配置一些短路径,
  • modules:webpack 解析模块时应该搜索的目录,
  • 其他 pluginsunsafeCacheenforceExtension,基本没有怎么用到,
//extensions 后缀可以省略,
import Toast from 'src/components/toast'; 

// alias ,短路径
import Modal from '../../../components/modal' 
//简写
import Modal from 'src/components/modal' 


resolve: {
  extensions: ['.js', '.jsx','.ts','.tsx', '.scss','.json','.css'],
  alias: {
    src :path.resolve(__dirname, '../src'),
    components :path.resolve(__dirname, '../src/components'),
    utils :path.resolve(__dirname, '../src/utils'),
  },
  modules: ['node_modules'],
},

module.rules - 编译规则,

  • rules:也就是之前的loaders,
  • test : 正则表达式,匹配编译的文件,
  • exclude:排除特定条件,如通常会写node_modules,即把某些目录/文件过滤掉,
  • include:它正好与exclude相反,
  • use -loader :必须要有它,它相当于是一个 test 匹配到的文件对应的解析器,babel-loaderstyle-loadersass-loaderurl-loader等等,
  • use - options:它与loader配合使用,可以是一个字符串或对象,它的配置可以直接简写在loader内一起,它下面还有presetsplugins等属性;
  • 具体来看一下示例:
module: {
    rules: [
        {
            test: /\.(js|jsx)$/,
            exclude: /node_modules/,
            use: [
                {
                    loader: 'babel-loader',
                    options: {
                        presets: [
                            ['env',
                            {
                                targets: {
                                browsers: CSS_BROWSERS,
                            },
                        }],'react', 'es2015', 'stage-0'
                        ],
                        plugins: [
                            'transform-runtime',
                            'add-module-exports',
                        ],
                    },
                },
            ],
        },
        {
            test: /\.(scss|css)$/,
            use: [
                'style-loader',
                {loader: 'css-loader',options:{plugins: [require('autoprefixer')({browsers: CSS_BROWSERS,}),],sourceMap: true}},
                {loader: 'postcss-loader',options:{plugins: [require('autoprefixer')({browsers: CSS_BROWSERS,}),],sourceMap: true}},
                {loader: 'sass-loader',options:{sourceMap: true}}
            ]
        },
        {
            test: /\.(png|jpg|jpeg|gif)$/,
            exclude: /node_modules/,
            use: [
                {
                    loader: 'url-loader?limit=12&name=images/[name].[hash:8].[ext]',
                },
            ],
        },
        {
            test: /\.(woff|woff2|ttf|eot|svg)$/,
            exclude: /node_modules/,
            use: [
                {
                    loader: 'file-loader?name=fonts/[name].[hash:8].[ext]',
                },
            ],
        },
    ],
},

项目中常用loader

  • babel-loader、awesome-typescript-loader js*/ts编译,
  • css-loader、postcss-loader、sass-loader、less-loader、style-loader 等css样式处理
  • file-loader、url-loader、html-loader等图片/svg/html等的处理,

plugins - 插件

  • UglifyJsPlugin
  • HotModuleReplacementPlugin
  • NoEmitOnErrorsPlugin
  • HtmlWebPackPlugin
  • ExtractTextPlugin
  • PreloadWebpackPlugin
  • 等等,很多很多,插件的详解会留在下一章节详细介绍,欢迎持续关注。

plugins/loader 区别

  • 新入门的一些同学可能会有些疑惑,不是有loader了吗?为什么还plugins呢,还要它做什么?
  • loader的作用在于解析文件,比如把ES6转换成es5,甚至ES3,毕竟还有万恶的IE嘛;把SassLess解析成CSS,给CSS自动加上兼容的前缀;对图片进行一个解析等等;
  • plugins呢?它在干啥?它在吹水、喝茶、嗑瓜子聊天,当然这是loader在没有把项目做完之前,loader下班时间就是plugins苦难的开始,它要对loader干的事情进行优化分类、提取精华(公共代码提取)、做压缩处理(js/css/html压缩)、输出指定的目录等……,反正也是很苦逼!

webpack-dev-server

  • 这个有些老生常谈了,新手上路一般都有用它,
  • 公司因为现在是结合了 微服务,整套流程是结合:Dockerfile、nodejs、express等一起在线构建编译的,所以大部分项目都不会走webpack-dev-server
  • 我们开发环境就是使用 express + webpack-dev-middleware + webpack-hot-middleware+ '...';
  • contentBase :告诉服务(dev server)在哪里查找文件,默认不指定会在是当期项目根目录,
  • historyApiFallback:可以是booleanobject,默认响应的入口文件,包括404都会指向这里,object见下面示例:
  • compress:启用 gzip 压缩,
  • publicPath:它其实就是 output.publicPath,当你改变了它,即会覆盖了output的配置,
  • stats: 可以自定控制要显示的编译细节信息,
  • proxy:它其实就是http-proxy-middleware,可以进行处理一些代理的请求。
//方式一:不配置方式二的内容
 webpack-dev-server --config webpack/webpack.config.dev.js
//指定 端口: --port=8080 
//开启热更新:--hot
//gzip: --compress

//方式二
devServer : 
    contentBase:'./assets',
    host: '0.0.0.0',
    port: 9089,
    publicPath: '/assets/',
    historyApiFallback: {
        index: '/views/index.html'
    },
    /*
    匹配路径,进入不同的入口文件,
    rewrites: [
            { from: /^\/$/, to: '/views/landing.html' },
            { from: /^\/subpage/, to: '/views/subpage.html' },
            { from: /./, to: '/views/404.html' }
        ]
    }
    */
    compress: true,
    noInfo: true,
    inline: true,
    hot: true,
    stats: {
        colors: true,
        chunks: false
    },
    proxy:{
        '/mockApi': 'https://easy-mock.com/project/5a0aad39eace86040263d' ,//请求可直接写成  /mockApi/api/login...
    }
}

webpack4删除的点:

  • module.loaders
  • NoErrorsPlugin
  • CommonsChunkPlugin
  • DefinePlugin
  • OccurenceOrderPlugin
  • 欢迎补充……,平时用到的大概就是这些

尾声:

  以上就是工作中react自定脚手架的配置总结,希望能对您有所帮助,webpack4的改动蛮大的,功能比之前强大了少,也简便了开发者很多的麻烦,效率大大提高,但同时也意味着我们对于底层的东西,了解的更少了,下一章节将为大家分享一些常用的插件/以及用法的分析,欢迎持续关注,记得点个赞哦,当然您能动动手指关注下方公众号就更棒了,谢谢支持!

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8

更多文章:

immutability因React官方出镜之使用总结分享!
小程序项目之做完项目老板给我加了6k薪资~
小程序项目之填坑小记
面试踩过的坑,都在这里了~
你应该做的前端性能优化之总结大全!
如何给localStorage设置一个过期时间?
动画一点点 - 如何用CSS3画出懂你的3D魔方?
动画一点点 - 手把手教你如何绘制一辆会跑车
SVG Sprites Icon的使用技巧

作者:苏南 - 首席填坑官

链接:https://blog.csdn.net/weixin_43254766/article/details/83758660

交流:912594095、公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

码农书籍 小程序,

  • 让你随时都能学习进步的小程序,欢迎体验

码农书籍小程序,webpack4配置详解之慢嚼细咽

这份优化清单,你都做了吗?

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8

引言

​ 大家好,这里是@IT·平头哥联盟,我是首席填坑官——苏南(South·Su),今天是国庆节的第二天,这个假期没有外出(不要问我为什么,自己脑补~😭),前些天分享了一篇前端面试汇总的文章,有些同学在群里问了其中的一些细节,其中大家最关心的性能优化这块,今天整理了公司项目中的一些认为不错的点,跟大家一起分享,如有理解错误,请纠正。

优化概括

1、 首先最基本的,CSS样式表放在页面头部Head内且link链式引入,javascript放在底部body结束标签前避免阻塞。

2、 js/html/css/图片都做压缩合并,图片预加载、懒加载,也是老生常谈了,在这里推荐一个图片无损极限压缩的工具,能压小60~80%左右,比较麻烦的是每次要手动操作——TinyPNG,有兴趣的同学了可以了解一下他们的API,自己封装一个服务调用压缩,不过免费次数有限制哦。

3、 减少DOM元素数量,减少DOM的操作:

  • 减少 DOM 元素数量,合理利用:after、:before等伪类,避免页面过深的层级嵌套;
  • 优化javascript性能,减少DOM操作次数(或集中操作),能有效规避页面重绘/重排;
  • 如何才算少?抱歉,这个没有办法给出一个标准精确的答案,只能说尽可能去做优化,如数据分页、首屏直出、按需加载等。

4、 静态资源CDN分发:

  • CDN的意图就是尽可能的减少资源在转发、传输、链路抖动等情况下顺利保障信息的连贯性;
  • 通俗的讲就是CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上———曾经人们都说距离产生美,后来变了都说距离产生小三,在这里距离产生的是用户跑路了,所以足以说明CDN的重要性
  • CDN采用各节点缓存的机制缓存很严重,当我们项目的静态资源(只是之前存放在cdn上的资源)修改后,如果CDN缓存没有做相应更新,则看到的还是旧的网页,解决的办法是刷新缓存,七牛云、腾讯云都可单独针对某个文件/目录进行刷新;
  • 广告常说:XX酒虽好,可不要贪杯哦,CDN托管也是如此,合理使用:图片、常用js组件、css重置样式等,即不常改动的文件即可走CDN,包括项目内的一些介绍页;
  • img标签要设置高宽,同样这么做它也能减少页面重绘/重排,使用 WebP 格式图片,它能对原图(png)做到近98%压缩,当然它也不是完美的:

WebP最初在2010年发布,目标是减少文件大小,支持无损、有损压缩,动态、静态图片,压缩比率优于 GIF、JPEG、JPEG2000、PNG 等格式,非常适合用于网络等图片传输,现在开始已经被越来越多的浏览器支持,当然 WebP 格式也有它的缺点,算法相对其他格式更加复杂,会在节省流量资源的同时会占用计算资源,对计算机造成更大的负担,WebP支持的像素最大数量是16383x16383。有损压缩的WebP仅支持8-bit的YUV4:2:0格式。而无损压缩(可逆压缩)的WebP支持VP8L编码与8-bit之ARGB色彩空间。又无论是有损或无损压缩皆支持Alpha透明通道、ICC色彩配置、XMP诠释数据,更详细支持说明:caniuse.com

优势

  • 体积小几乎可以毫不夸张的说,已经小的不能再小了;
  • 小而美的同时,还质量好,几乎看不出来与原图差别;
  • 曾经的动态图gif、jpeg压缩都会不清晰,但现在对它来说都是so easy~。

缺点/困难

  • 目前并不是所有浏览器都支持WebP,因此需要解决浏览器适配问题;
  • 对于已上线的项目,采用WebP需要替换大量图片,工作量太大(不确定后台程序是否能搞定)。

5、 域名拆分:

  • 什么叫拆分域名?很多公司初始项目搭建,都只申请了一个域名,站点的所有内容(html/php/jsp、js、css、img等都放在一个域名下),域名拆分主要为了增加浏览器资源请求的并行度即并发问题,让浏览器能同时发起更多的请求,也解决了请求默认携带的cookie问题,减少了数据传输字节;
  • 如何拆分?以现在前后端分离式开发为例,建议分为三大类:
  • 前端类 - 项目业务本身的htm、css、js、图标/片等;
  • 静态类 - 即上述提到的CDN资源类;
  • 动态类 - 可归为后端API接口类;

以下为各浏览器请求并发数,数据来源于chorme搜索,珍爱生命,远离某……🙏:

浏览器 HTTP/1.1 HTTP/1.0
Chrome 6 6
火狐 6 6
Safari 4 4
IE11 6 6
IE9 10 10
…… …… ……

6、 减少http请求次数

  • 是的,你没有看错,就是减少http请求次数,节省网络请求时间,但你可能又会问,前面不是让拆分域名吗??一个是部署拆分,一个是请求减少,没毛病哦;
  • 首先我们来了解一下http的请求过程(简单通俗的阐述一下):
  • DNS 域名解析 - 1. 拿出电话,找到某个接头人的号码;
  • 发起 TCP 的 3 次握手 - 2. 接通后暗号:A)、你好,你好,我是长江一号,请问能听到吗?B),你好,我是长江二号,能听到你讲话,你能听到我说什么吗?A)、能听到,我们开始讲正事吧……;
  • 正常数据传输中…… - 3. 聊的很嗨;
  • 结束传输断链的 4 次挥手 - 4. 聊完了,准备告别:A)、(可以是服务端,也可以是客户端)该说的我都说完了,你自己看着办吧;B)、好的我也说完了;B)、(B紧接着又跟A发了条信息),再见;A)、然后A收到B的话,而B那边已经放下手机挂了,A等了一下听B没有再说啥,也就挂了(挂个毛啊,婊子无情,戏子无义,陪你唠嗑这么久,都不给个好评~😂);
  • 当然,现在的HTTP/2.0的处理有所不同,2.0过程还有TLS/SSL的处理,HTTP是超文本传输协议,信息是明文传输,HTTPS则是具有安全性的SSL(Certificate Authority,申请证书)加密传输协议,HTTPS加密传输、身份认证的网络协议,内容传输经过完整性校验、内容经过对称加密,每个连接生成一个唯一的加密密钥、第三方无法伪造服务端(客户端)身份等众多优势,同时也有劣势因为做的事情多了中间对接的次数同样需要时间,这也是HTTPS更慢的根本原因。
  • 上两图吧,这样大家看着清晰一些,但暂时只列了HTTP/1.0的,HTTP/2.0的图下次有时间再补,是有一个大佬指点我的哦,说这样看起来更*气,大家会更喜欢,哈哈~:

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8 - 三次握手
本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8 - 四次挥手

结论:从上面的这个过程可以看出,每一次请求都这么复杂,减少http的请求次数是不是很有必要呢??答案是肯定的,我们会以以下几个维度来进行优化:

  • 合并 JS、CSS 文件;
  • 图片/图标 sprites 合并,或使用iconfont字体图标,或者SVG Sprites什么是Svg Sprites?
  • 资源按需加载,即当前页面用到什么,就加载什么,避免加载与当前页面无关的事情,这一点现在的React/Vue/Angular等MVVM框架,基于webpack编译打包工具,做的很好;
  • 前端数据的缓存(如:一个列表页,进入详情,再返回,这个用户的交互行为是很频繁的,可以对列表的数据进度一个缓存,不用每次返回都进行加载,比如5分钟更新一次。

7、 数据设置缓存,好累写不动了,http缓存的设置,之前的面试汇总👉如何设置http缓存?吧;
8、 站点服务端开启Gzip压缩,当然还可以了解一下Brotli 或 Zopfli ,据说 Brotli 比 Gzip 和 Deflate更有效,有兴趣的同学可以了解一下;
8、 避免重定向,尽量减少 iframe 使用,它会阻塞主页面的渲染;
9、 避免使用CSS Expression(css表达式)又称Dynamic properties(动态属性);
10、 合理使用dns-prefetch、prefetch、 preload、 defer、async:

  • dns-prefetch:使用dns-prefetch对项目中用到的域名进行 DNS 预解析,减少 DNS 查询,如: ;BAT各大巨头都是这么干的,请看下图,dns的详细解析过程今天先不讲了,码字码不动了,写分享比加班做项目还累,望体谅~;
  • prefetch: 它是一个优先级非常低的资源加载标识,浏览器会在空闲时(即主进程资源加载完成后)下载带有 prefetch标识的资源并缓存到disk,在后续模块使用到这个文件的时候,会直接从缓存读取;该功能webpack有个插件,配置后编译能自动插入到页面上;
  • preload:没错,它就是一个可以预加载资源的属性,详细说明请看官方API,一般情况下我们可能会对接下来的业务需要的audio、img、font、script等资源进行预先加载(甚至是下一个路由页面哦),这样能达到0秒打开页面的效果!
  • 暂时就想到这么多了,欢迎补充……

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8 - 阿里巴巴的天猫首页
本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8 - 京东首页
本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8

总结:

  • 推荐几个工具:WebPagetestLighthouseSpeedCurveNew Relic 等主动/被动监测工具,都能高效帮助我们分析发现问题的所在,从而对症下药;
  • DNS预解析的是非重要的,它是一个url到解析IP,到查询根服务器的一个过程,可能会在下一次单独总结出来分享,有兴趣的同学也可以自行先了解一下,
  • 要把一个项目做好,每一个细节都很重要,希望今天的分享能给大家的工作带来些许帮助,谢谢!

本文由@IT·平头哥联盟-首席填坑官∙苏南 分享,公众号:honeyBadger8

文章分享计划:

  最近一直在思考,如何有规化的分享工作中的积累,国庆这些天也一直看了很多大神写的博客,最后综合自身的能力及时间,决定先尝试写一个**# 动画 #**系列文章,动画可能主要包含(CSS/Canvas)两部分,欢迎大家持续关注!

  以上就是今天的分享,新手上路中,我会努力让自己变得更优秀、写出更好的文章,文章中有不对之处,烦请各位大神斧正。如果你觉得这篇文章对你有所帮助,请记得点赞哦~。

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8

作者:苏南 - 首席填坑官

链接:https://honeybadger8.github.io/blog/

交流群:912594095,公众号:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明链接及出处。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.