Giter Site home page Giter Site logo

my-blog's Introduction

my-blog's People

Contributors

jslinsir avatar

Watchers

 avatar

my-blog's Issues

H5 css 样式重置

去除浏览器默认的样式

字体

常用标签类

长按类

长按图片保存

禁止长按 文本复制

1px 问题

一些样式重置

*,
:after,
:before {
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0)
}

blockquote,
body,
dd,
div,
dl,
dt,
fieldset,
form,
h1,
h2,
h3,
h4,
h5,
h6,
input,
legend,
li,
ol,
p,
td,
textarea,
th,
ul {
    margin: 0;
    padding: 0
}

table {
    border-collapse: collapse;
    border-spacing: 0
}

fieldset,
img {
    border: 0
}

li {
    list-style: none
}

caption,
th {
    text-align: left
}

q:after,
q:before {
    content: ""
}

input:password {
    ime-mode: disabled
}

:focus {
    outline: none
}

body,
html {
    min-height: 100%
}

body {
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none
}

a,
img {
    -webkit-touch-callout: none
}

H5 禁用图片保存

如何禁用H5 长安图片保存

第一种

此css 属性作用在微信客户端浏览器,也就是腾讯内核的浏览器

img {
  pointer-events:none;
}

注意:此css属性同时也会禁用掉图片的点击事件,如果同时要支持图片点击,外层套个div 事件绑定到外层div上

第二种

img{
   user-select:none;
   -webkit-touch-callout:none;
   -webkit-user-select:none;
   -moz-user-select:none;
   -ms-user-select:none;
}

注意:-webkit-touch-callout主要用于禁止长按菜单。针对iOS webkit内核的浏览器。
user-select属性是css3新增的属性,用于设置用户是否能够选中文本

第三种

加一层遮罩如下:

<div class="imgBox">
    <div class="imgMask"></div>
    <img src="xx.png"/>
</div>
<style>
 .imgBox{
    position: relative;
    width: 100%;
    margin: 0 auto;
      .imgMask{
	    position: absolute;
	    z-index: 100;
	    left: 0;
	    right: 0;
	    top: 0;
	    bottom: 0;
	    opacity: 0;
	  }
	  img{
		  display: block;
		  width: 100%;
	 }
}
</style>
 

第四种

设置图片为背景图

总结

通过浏览器的模拟器,第二种是生效的,遮罩视乎在浏览器中模拟器不生效

平淡的迎来30岁

30岁?

  • 30岁经历了啥?
  • 30岁做了啥?
  • 30岁以后如何过下去?

平淡的迎来30岁

93年人,今天踏进30岁的大门。
没有祝福,没有蛋糕。
从小到大也没有几次正儿八经的过几次,对我也不那么重要
重要的是30岁,这个年龄担子上的责任

过往

成熟不是不会到来,可能来的会慢些;

回想下,这几年也经历了不少事情,自己扛不过来的时候也放声大哭过
有时候也抱怨生活为什么会那么难?生活为什么会有那么多挫折?
这就是生活,为了心爱的人,为了心疼的人,为了牵挂的人值得你去爱,值得你去付出;
咬咬牙,你这个年纪注定不安逸,一切都会好起来的!
懂感恩,懂责任,懂付出,不去计较,这是你这个角色应当承担的!

6年的深漂

16年11月份来的深圳,刚来就爱上了这里
干净的街道,宽阔的马路,琳琅满目的大厦,蓝蓝的天空 埋下了留深的种子
这6年,换了三家公司

  • 金证股份 这里是我入行的开始,感谢老东家能够收留我这个应届生,也感谢那些帮助过我的同事们,谢谢你们
  • 菜鸟理财 这里我认识了我的爱人,虽然现在公司已经不在了,但是要感谢这里的所有人,你们真的很友好。
  • 天虹股份 这里我见证了公司的发展,从一百来号人的团队到三百多人的团队,从十几个前端到将近50个的前端,也见证了子公司 灵智的发展,从刚成立,到武汉分部,我想我可能还会在这里继续下去,因为它给我了归属感!

往后余生

越往后,就是大龄程序员,听到这个词,确实很让人焦虑 难道搬一辈子砖?
内心焦虑的时候不如:
路慢慢的走,踩实了走,一步一个脚印 不急于求成,稳中求胜

壬寅年四月十七

20022年5月17日

优雅的处理 人民币单位

需求如下

当输入数字的时候,显示数字的最大单位
如: 1,000 在下方展示 千

实现思路

  • 设置单位常量
  • 定位输入数字属于哪一阶段
10 = 10*1 == 1e1
100 = 10*10 == 1e2
1000 = 10*10*10 == 1e3
Math.log10(10) == 1
Math.log10(100) == 2
Math.log10(1000) == 3

根据上面分析10 的幂运算 和对数运算 对应关系
我们定义一个常量

 const charCn = ['个','十','百','千','万','十万','百万','千万','亿','十亿','百亿','千亿','兆','十兆','百兆','千兆','京']

获取值的单位下标

 Math.floor(Math.log10(1))   // 向下取整(取10的对数) 得到的既是 对应值的下标

最后,我们封装个函数

function getCharName(value) {
      const charCnIndex = Math.floor(Math.log10(value)) 
      return charCn[charCnIndex]
    }

谈谈前端开发过程中bug率较高问题

问题产生

行业内卷,公司绩效也不是太好,这个时候部门互怼开始,产品怼技术,技术怼产品,技术互怼...

前端的角色

前端相比其他工种,比较特殊,对接的工种也比较多

  • 对接UI,UE,
  • 对接接口
  • 对接测试

问题的出现

我们在开发过程中,是对接环节比较多的一个工种,如果UI,UE 不完善,那我们就可能出现 页面,或者交互问题,如果接口Mock没有覆盖到位,就有可能出现数据回显,以及状态处理问题等!
对接的多,就需要我们多沟通,有时候别人回的信息不及时,你这个问题就会耽搁,同时也会缩短你的开发时间。
在开发周期固定的情况下,如何快速的交付?这个时候前端同学们就会 老老实实切图,也不会去关心产品逻辑,只关心功能的实现。

错误问题

  • UI边界问题
  • 校验,提示 交互问题
  • 接口数据回显问题
  • 代码逻辑问题
  • 需求理解偏差

总结

在我看来,我不认同不是前端同学们不够细心导致的,代码是人写的,人写的肯定会出错,在周期短的情况下,以及其他工种不够完整的情况下就会出现 上述情况;
当然啦,细心肯定是要有的,这个是职业素养。
问题的出现,不是一个工种的问题,而是整个团队配合的问题。出现问题,不要相互指责,也不要归结到一个工种上;如果这样做,团队氛围也不会好,也不会拧成一股绳 往前冲,而是各组相互吃瓜...

青年失业率与选择创业 - 摘抄自《阮一封的网络日志》

青年失业率与选择创业

现在的青年失业率非常高。官方统计[2],今年7月份的16岁~24岁青年失业率达到了19.9%。

image

前景也不乐观。明年的高校毕业生创新高,超过1000万人加入求职大军。而且,市场上还有很多大龄失业者,也在找工作。

这样严峻的就业形势意味着,最终有相当一部分人会考虑创业。

我以前一直赞成创业,但是这几年想法有变化,认为创业有三个条件, 只有满足条件,才适合创业。

我最近读过一篇文章[3],作者是美国最大的创业孵化器 Y Combinator[4] 的创始人之一杰西卡·利文斯顿(Jessica Livingston)。她是四个创始人里面唯一的女性。

她回忆了自己为什么创业,文章的最后一段,她这样说:
你是一块特殊形状的拼图。你可以改变自己的形状,适应公司现有的空缺。那是传统的方案。 但是,还有另一种对你和世界通常都更好的方案:围绕你自己的形状,发展出一幅新的拼图。这就是我所做的,我是一个非常奇怪的形状

她的意思是,你为别人打工,就必须变成别人要求的样子。但这并不是你内心想要的,如果你想顺应自己的内心和天赋,就应该创业。

这话没错,但是有一个前提才能成立:你已经定型了,很难被外界塑造了。 这个时候,你走自己的路,内心满意度会高一些。我觉得这是创业的第一个条件。

据我观察,大部分的**年轻人,达不到这个条件。他们都没有定型,人生观和世界观还在发展中。典型的表现就是,说不出自己想做什么,也不知道自己的竞争力在哪里。

这种情况下,你不是一块特殊形状的拼图,而是没有自己的形状,还在塑造中。如果这样去创业,你的想法可能随着外界的变化,而不断变化,今天想东,明天想西,这是大忌。

反而是给别人打工,公司明确告诉你成为什么形状,你就往这个方向努力。公司把你塑造成型,适合公司的需求,融合进公司的拼图。这就是为什么,大部分创业者都是离职后才创业,因为只有到了这个时候,他们才定型。

  • 创业的第二个条件:
    要有可行的项目, 不能先注册公司,再找项目。而且,你的项目最好是用户愿意付费的,有的同学的创业项目是拍短视频和直播,我觉得不靠谱。

  • 创业的第三个条件是:
    能够承受负的现金流。 刚开始创业,很可能没有或很少收入,每天却要支出,压力巨大。

只有满足上面三个条件,我认为,才适合创业。

显而易见,刚毕业的学生不容易满足这些条件。前几年,有一种论调鼓励学生创业,这是不正确的。

我的意思不是劝退创业,而是希望大家在越是困难时刻,越不要盲目。 面对失业率上升,你要做的第一位的事情,就是尽快把自己锻造成型,形成稳定的心智和人格,磨练自己的技能。

ios 渐变色问题

问题出现

ios 渐变色 会出现黑色
如下代码:

  background-image: linear-gradient(180deg, rgba(0, 0, 0, 0), 1%, #f6f6f6);

解决

  background-image: linear-gradient(180deg, rgba(246, 246, 246, 0), 1%, #f6f6f6);

产生原因

Safari在渐变中对颜色的处理是同时渐变rgba()中的每一个参数,因此该例子中实际上是在渐变从黑色到颜色,从全透明到不透明。因此,中间出现了灰色。

解决方法

将rgba()中的前三个参数,设置成背景色的颜色值即可。

解锁小程序中使用SVG新姿势

SVG 的优势

  • 清晰度: 可以进行放大,而不失真
  • 更小的文件体积
  • 可扩展性,可以动态颜色
  • 动效 可以添加动效

在小程序中使用

目前小程序 的image标签已经支持了 svg 的显示

 <image src="./xx.svg"/>

如何动态的改变 svg 属性呢?

大体思路:把svg转成 base64 然后通过 image标签 src设置图片,再动态赋值svg颜色

  1. 把svg转成base64
  • 如下一个svg 代码文件
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="24 24 48 48"><animateTransform attributeName="transform" type="rotate" repeatCount="indefinite" from="0" to="360" dur="1400ms"></animateTransform><circle cx="48" cy="48" r="20" fill="none" stroke="#eeeeee" stroke-width="2" transform="translate\(0,0\)"><animate attributeName="stroke-dasharray" values="1px, 200px;100px, 200px;100px, 200px" dur="1400ms" repeatCount="indefinite"></animate><animate attributeName="stroke-dashoffset" values="0px;-15px;-125px" dur="1400ms" repeatCount="indefinite"></animate></circle></svg>
  • 转成base64,其实就是 对这个svg进行 encodeURIComponent 得到 如下代码
%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%2224%2024%2048%2048%22%3E%3CanimateTransform%20attributeName%3D%22transform%22%20type%3D%22rotate%22%20repeatCount%3D%22indefinite%22%20from%3D%220%22%20to%3D%22360%22%20dur%3D%221400ms%22%3E%3C%2FanimateTransform%3E%3Ccircle%20cx%3D%2248%22%20cy%3D%2248%22%20r%3D%2220%22%20fill%3D%22none%22%20stroke%3D%22%23eeeeee%22%20stroke-width%3D%222%22%20transform%3D%22translate%5C(0%2C0%5C)%22%3E%3Canimate%20attributeName%3D%22stroke-dasharray%22%20values%3D%221px%2C%20200px%3B100px%2C%20200px%3B100px%2C%20200px%22%20dur%3D%221400ms%22%20repeatCount%3D%22indefinite%22%3E%3C%2Fanimate%3E%3Canimate%20attributeName%3D%22stroke-dashoffset%22%20values%3D%220px%3B-15px%3B-125px%22%20dur%3D%221400ms%22%20repeatCount%3D%22indefinite%22%3E%3C%2Fanimate%3E%3C%2Fcircle%3E%3C%2Fsvg%3E
  • 拼接base64
   data:image/svg+xml;charset=utf-8,encodeURIComponent后的代码
  1. 在对应svg属性上动态设置颜色,比如这里用到的是填充颜色
    在js文件 data中定义 color 状态
    在wxml中动态渲染
 <image src="data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%2224%2024%2048%2048%22%3E%3CanimateTransform%20attributeName%3D%22transform%22%20type%3D%22rotate%22%20repeatCount%3D%22indefinite%22%20from%3D%220%22%20to%3D%22360%22%20dur%3D%221400ms%22%3E%3C%2FanimateTransform%3E%3Ccircle%20cx%3D%2248%22%20cy%3D%2248%22%20r%3D%2220%22%20fill%3D%22none%22%20stroke%3D%22%23{{color}}%22%20stroke-width%3D%222%22%20transform%3D%22translate%5C(0%2C0%5C)%22%3E%3Canimate%20attributeName%3D%22stroke-dasharray%22%20values%3D%221px%2C%20200px%3B100px%2C%20200px%3B100px%2C%20200px%22%20dur%3D%221400ms%22%20repeatCount%3D%22indefinite%22%3E%3C%2Fanimate%3E%3Canimate%20attributeName%3D%22stroke-dashoffset%22%20values%3D%220px%3B-15px%3B-125px%22%20dur%3D%221400ms%22%20repeatCount%3D%22indefinite%22%3E%3C%2Fanimate%3E%3C%2Fcircle%3E%3C%2Fsvg%3E" />

注意:这里的颜色 由于是已经被编码了,所以# 已经被转义了 %23, 直接写颜色数字即可
当然你也可以 去掉%23 自己实现一个内部方法

 if (color && color.startsWith('#')) {
    return `%23${color.slice(1)}`;
  }

这样其实就实现了 svg的动态渲染,可是这种写法,写在wxml中 不是特别的优雅,那么如何重构下让我们的代码看起来更优雅呢?

  • 把 svg 单独存放 支持动态返回
  • 动态复制 image src 属性

svg 动态函数

loading.svg.js 文件

export const loadingSvg = (color='#ddd') =>{
  const svgXml = `<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="24 24 48 48"><animateTransform attributeName="transform" type="rotate" repeatCount="indefinite" from="0" to="360" dur="1400ms"></animateTransform><circle cx="48" cy="48" r="20" fill="none" stroke="${color}" stroke-width="2" transform="translate\(0,0\)"><animate attributeName="stroke-dasharray" values="1px, 200px;100px, 200px;100px, 200px" dur="1400ms" repeatCount="indefinite"></animate><animate attributeName="stroke-dashoffset" values="0px;-15px;-125px" dur="1400ms" repeatCount="indefinite"></animate></circle></svg>`
  return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`
}

逻辑层引入,setData

  onLoad(){
    const { loadingSvg } = require('./loading.svg.js')
    const svgImg = loadingSvg('#eee')
    this.setData({svgImg})
  },

渲染层使用

  <image src="{{svgImg}}"/>

这样看起来舒服多了!!!

H5 如何判断是否横屏呢?

如何判断 H5 是否 运行在横屏设备上?

通过CSS 的媒体查询方式

orientation 原理:

  • 屏幕方向
  • portrait: viewport 处于纵向,即高度大于等于宽度。
  • landscape : viewport 处于横向,即宽度大于高度。
@media screen and  (orientation: landscape) {
   /* 横屏 css*/
  body {
    flex-direction: row;
  }
}

@media screen and  (orientation: portrait) {
 /*竖屏 css*/
  body {
    flex-direction: column;
  }
}

orientation 存在的问题

此属性不等价于设备的屏幕旋转方向。在许多设备上,当屏幕方向为纵向时,打开软键盘将导致视口 viewport 的宽度大于高度,从而导致浏览器突然改用横向样式,而不是保持纵向。

通过 js 判断 横竖屏

     const _body = document.body
     const _html = document.documentElement
     const clientWidth = _html.clientWidth || _body.clientWidth || window.innerWidth
     const clientHeight = _html.clientHeight || _body.clientHeight || window.innerHeight
     const viewport = clientWidth > clientHeight ? 'landscape' : 'portrait'

此种方式存在的问题点和 媒体查询一样,当键盘弹起的时候,高度会变化,这个时候判断就会不准确

通过 根节点 旋转的方式

 /*给根节点设置旋转属性*/
body{
        -webkit-transform:rotate(-90deg);
        -moz-transform: rotate(-90deg);
        -ms-transform: rotate(-90deg);
        transform: rotate(-90deg);
        width: 100vh;
        height: 100vh;
    }

注意问题点

通过旋转屏幕设置 屏幕横向,这个时候如果使用 vw vh适配的话,要注意旋转后的 vw 即是 vh

参考

H5游戏开发:横屏适配

关于 window.addEventListener & window.dispatchEvent 的使用

window.addEventListener 的解释

EventTarget.addEventListener() 方法将指定的监听器注册到 EventTarget 上,当该对象触发指定的事件时,指定的回调函数就会被执行。 事件目标可以是一个文档上的元素 Element,DocumentWindow或者任何其他支持事件的对象 (比如 XMLHttpRequest)。

window.addEventListener('sendMsg',function(){
	console.log('who dispatch this event?')
}, false);

var res = window.dispatchEvent(new Event('sendMsg'))

Web Components 学习

Web Components

Web Components 用原生 js 的方式 构建模块化组件

Web Components 三板斧

  • Custom elements(自定义元素):允许您定义custom elements及其行为,然后可以在您的用户界面中按照需要使用它们
  • Shadow DOM(影子DOM):用于将封装的Shadow DOM树附加到元素(并控制其关联的功能。可以将CSS样式与外部隔开,防止外部的样式影响,类似Vue的组件私有样式。
  • HTML templates(HTML模板):<template><slot> 元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用,使用过Vue和React等热门框架的应该熟悉。

组件的声明

声明一个 class 继承 HTMLElement

 class Demo extends HTMLElement {
    constructor() {
      super()
    }
  } 

组件的注册

  • 自主定制元素:独立元素; 它们不会从内置HTML元素继承。
  • 自定义内置元素:这些元素继承自 - 并扩展 - 内置HTML元素
    customElements.define(name, constructor, options)
  • 参数:
    • name: 自定义元素名
    • constructor: 自定义元素构造器
    • options(可选) 如果有 options 则是自定义内置元素
      // 存在浏览器兼容问题
      customElements.define(name, constructor, {extens:'div'})

影子节点封装

调用 attachShadow 将一个shadow DOM附加到自定义元素上。使用通常的DOM方法向shadow DOM中添加子元素、事件监听器等等

 class Demo extends HTMLElement {
    constructor() {
      super()
      const shadowRoot = this.attachShadow({ mode: "closed" })
      shadowRoot.innerHTML = `<div>我是 web components </div>`
     this.shadow = shadowRoot

    }
  } 

影子节点添加子元素方式

innerHTML 方式

innerHTML 方式 向影子节点 赋值 一个字符串式的标签

 ...
 shadowRoot.innerHTML = `<div></div>`
 this.shadow = shadowRoot

appendChild 方式

appendChild 方式 向影子节点块后增加一个 element 节点

 const pElem = document.createElement('p');
 shadowRoot.appendChild(pElem);

template 方式

  • 通过html 的方式
  1. 在 html中创建一个模板
<template id="person-template">
 <div>
   <h2>Personal ID Card</h2>
   <slot name="person-name">NAME MISSING</slot>
   <ul>
     <li><slot name="person-age">AGE MISSING</slot></li>
     <li><slot name="person-occupation">OCCUPATION MISSING</slot></li>
   </ul>
 </div>
</template>
  1. 使用模板
class Demo extends HTMLElement {
   constructor() {
     super();

     const template = document.getElementById('person-template');
     const templateContent = template.content;

     const shadowRoot = this.attachShadow({mode: 'open'});

     shadowRoot.appendChild(templateContent.cloneNode(true));
   }
}
  • 通过 createElement 创建的方式
const template = document.createElement('template')
template.innerHTML = `<div>test</div>`
class TestComponents extends HTMLElement {
 constructor() {
   super()
   const shadowRoot = this.attachShadow({ mode: "close" })
   shadowRoot.appendChild(template.content.cloneNode(true))
 }
}
customElements.define('test-components', TestComponents)

向影子节点添加CSS

createElement 的方式

 const style = document.createElement('style')
 style.textContent = `
          .wrapper {
            color: red;
          }`
shadow.appendChild(style)

adoptedStyleSheet 的方式

const style2 = new CSSStyleSheet();
style2.replaceSync(`.wrapper {font-weight:bold;}`)
shadow.adoptedStyleSheets = [style2]

注意adoptedStyleSheet与style标签混合使用都会生效,互相影响

生命周期

  • connectedCallback: 当元素被添加到文档的时候调用
  • disconnectedCallback:当元素从文档删除的时候调用
  • adoptedCallback: 当元素被移动到新文档的时候调用
  • attributeChangedCallback: 当元素属性添加,删除,修改的时候调用 ,需搭配observedAttributes()使用

JavaScript 数据类型

javaScript的类型 包含了 ‘基本数据类型’ 和 ‘引用数据类型’

基本数据类型

  • String
  • Number
  • Boolean
  • Symbol
  • BigInt
  • Null
  • Undefined

引用数据类型 (Object)

  • Object (普通对象)
  • Array (数组对象)
  • Date (日期对象)
  • RegExp(正则)
  • Function (函数)
  • Math(数据函数)
  • ...等

基本数据类型 和 引用 数据类型的存储方式

  • 基本数据类型存储在栈内存(后进先出),被引用或拷贝时,会创建一个完全相等的变量;
  • 引用类型存储在堆内存(先进先出),存储的是地址,多个引用指向同一个地址。

如何判断 数据类型

  • typeof 可以准确检测基本数据类型 除 null(值为'object') 之外
  • instanceof 方法去判断 这个对象是否是之前那个构造函数生成的对象
let Car = function() {}
let benz = new Car()
benz instanceof Car // true
  • 通过 Object.prototype.toString 官网说明 去判断数据类型
    原理:
    当 toString 方法被调用的时候,下面的步骤会被执行:
    1. 如果 this 值是 undefined,就返回 [object Undefined]
    2. 如果 this 的值是 null,就返回 [object Null]
    3. 让 O 成为 ToObject(this) 的结果
    4. 让 class 成为 O 的内部属性 [[Class]] 的值
    5. 最后返回由 "[object " 和 class 和 "]" 三个部分组成的字符串
 console.log(Object.prototype.toString.call(undefined)) // [object Undefined]
 console.log(Object.prototype.toString.call(null)) // [object Null]

var date = new Date();
console.log(Object.prototype.toString.call(date)) // [object Date]

var number = 1;          // [object Number]
var string = '123';      // [object String]
var boolean = true;      // [object Boolean]
var und = undefined;     // [object Undefined]
var nul = null;          // [object Null]
var obj = {a: 1}         // [object Object]
var symbol = symbol(1)  // [object Symbol ]
var array = [1, 2, 3];   // [object Array]
var date = new Date();   // [object Date]
var error = new Error(); // [object Error]
var reg = /a/g;          // [object RegExp]
var func = function a(){}; // [object Function]

console.log(Object.prototype.toString.call(Math)); // [object Math]
console.log(Object.prototype.toString.call(JSON)); // [object JSON]


function a() {
    console.log(Object.prototype.toString.call(arguments)); // [object Arguments]
}
a();

如何实现一个 instanceof

function myInstanceof(left, right) {
  // 这里先用typeof来判断基础数据类型,如果是,直接返回false
  if(typeof left !== 'object' || left === null) return false;
  // getProtypeOf是Object对象自带的API,能够拿到参数的原型对象
  let proto = Object.getPrototypeOf(left);
  while(true) {                  //循环往下寻找,直到找到相同的原型对象
    if(proto === null) return false;
    if(proto === right.prototype) return true;//找到相同原型对象,返回true
    proto = Object.getPrototypeof(proto);
    }
}
// 验证一下自己实现的myInstanceof是否OK
console.log(myInstanceof(new Number(123), Number));    // true

判断对象是否为空 EmptyObject

function isEmptyObject( obj ) {

        var name;

        for ( name in obj ) {
            return false;
        }

        return true;
}

关于BigInt 的出现解释

在 JavaScript 中,语言所能够保证“安全”(精确)地进行计算的最大整数是 2^53 - 1 ,也就是 9007199254740991 (常量 Number.MAX_SAFE_INTEGER)超过了这个数值,JS 就会产生一些意想不到的问题。比如:

9007199254740991 + 1 // => 结果是 9007199254740992
9007199254740991 + 2 // => 结果也是 9007199254740992

BigInt的提出,解决超过最大整数计算问题, n: 表示超过最大精度的运算

9007199254740991n + 1n // => 结果是 9007199254740992n
9007199254740991n + 4n // => 结果是 9007199254740995n

实现一个类型校验工具

function getType(obj) {
  const lowerCaseTheFirstLetter = (str) => str[0].toLowerCase() + str.slice(1);
  const type = typeof obj;
  if (type !== 'object') {
    return type;
  }

  return lowerCaseTheFirstLetter(
    Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1')
  );
}

getType([]); // "array"
getType('123'); // "string"
getType(null); // "null"
getType(undefined); // "undefined"
getType(); // "undefined"
getType(function () {}); // "function"
getType(/123/g); // "regExp"
getType(new Date()); // "date"
getType(new Map()); // "map"
getType(new Set()); // "set"

小程序中 如何适配 IPhone X 系列

苹果 websites 设计规范

安全区示意图

329554c7855a238a

小程序中适配

padding-bottom: constant( safe-area-inset-bottom); /* 兼容 iOS < 11.2 */
padding-bottom: env( safe-area-inset-bottom); /* 兼容 iOS >= 11.2 */

注意:env() 跟 constant() 需要同时存在,而且顺序不能换

使用 @supports 隔离兼容样式

@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) {
.iphone-x {
      padding-bottom: constant(safe-area-inset-bottom);
      padding-bottom: env(safe-area-inset-bottom);
   }
}

效果展示

WeChatefd0056ba6fd0feec80568f20a12a18c

同样也支持 calc 写法

非x 系列设备,距离底部距离

@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) {
.iphone-x {
      padding-bottom: calc(10rpx + constant(safe-area-inset-bottom));
      padding-bottom: calc(10rpx  + env(safe-area-inset-bottom));
   }
}

dom-to-image 的使用

介绍

正如官网所描述的那样:dom-to-image 可以将任意dom节点转换为用JavaScript编写的矢量(SVG)或(PNG或JPEG)图像。

使用

  • 可以先把要生成的dom节点 用div高度为0 的 块进行包裹
  • 生成后的图片可以填充到另外一个块中
import domtoimage from 'dom-to-image';
var node = document.getElementById('my-node');

domtoimage.toPng(node)
    .then(function (dataUrl) {
        var img = new Image();
        img.src = dataUrl;
        document.body.appendChild(img);
    })
    .catch(function (error) {
        console.error('oops, something went wrong!', error);
    });

关于失真问题的处理

createImg() {
      Toast.loading({
        duration: 10*1000,
        message: "资料生成中...",
        forbidClick: true
      });
      const node = document.getElementById("sheet-dom-id");
      const scale = window.devicePixelRatio
      console.log("node:", node);
      domtoimage
        .toPng(node, { 
            height: node.offsetHeight * scale,
            width: node.offsetWidth * scale,
             style: {
             transform: `scale(${scale})`,
             transformOrigin: 'top left',
             width: `${node.offsetWidth}px`,
             height: `${node.offsetHeight}px`
        }
            })
        .then(dataUrl => {
          console.log("dataUrl:", dataUrl);
          const img = new Image();
          img.src = dataUrl;
          img.style.width = "100%"
          document.getElementById("sheet-show-container").appendChild(img);
        })
        .catch(function(error) {
          console.error("oops, something went wrong!", error);
        })
        .finally(()=>{
             Toast.clear()
        })
    }

生成后的图片可以 ,设置宽度100%,这样不会出现滚动的情况

实现 base64图片的压缩?

原理

通过 cavas的方式 把图片进行压缩

/**
 * 压缩base64 图片
 * @param {*} quality  压缩系数0-1之间
 */
export const compressBase64Img = ({quality=0.6,base64Img}) => {
    return new Promise((revose,reject)=>{
        const newImage = new Image()
        newImage.src = base64Img
        newImage.setAttribute("crossOrigin", 'Anonymous')
        newImage.onload = function () {
            const canvas = document.createElement('canvas')
            const ctx = canvas.getContext("2d")
            canvas.width = this.width
            canvas.height = this.height
            ctx.clearRect(0, 0, canvas.width, canvas.height)
            ctx.drawImage(this, 0, 0, canvas.width, canvas.height)
            const newBase64 = canvas.toDataURL("image/jpeg", quality)
            revose(newBase64) 
        }
        newImage.onerror = function () {
            reject('图片加载出错')
        }

    })
  
 
}

答辩反思

沉浸自己的开发圈

作为开发者,当然是在不断的追求技术上的造诣,不断的沉底自己的技术;
走技术可能是条死路,因为你不可能玩到天花板级别,所以你怎么办?

升职答辩

今天的升职答辩,领导的一些问题,值得去反思

  • 问:你知道企微的自开发,和代开发和第三方开发有什么区别吗?
  • 问:企微相关的更新你们是否留意?对我们是否有影响?有些功能实现上你们是否能够给产品决定权?更好的推动产品
    这个问题,我确实挺懵的。因为平时只关注着专业技能上的范围,突然问一些产品级别的问题,而且和我们经常打交道却没有真正搞懂这些东西,确实挺惭愧的!
    私下自己很是抱怨,为什么问我产品相关的?我要是懂,那我去当产品好了?

反思

既然领导这样提要求了,为何不去了解上游领导的需求?帮他们更好的实现?这样不更好?更有话语权?

  • 所以当我们从事一件事的时候,来龙去脉搞清楚很重要
  • 去了解产品拓展自己的世界,站出去看看,了解下外面的世界,不能封锁了自己的视野
  • 螺丝钉多的是,当然换一个螺丝钉也很容易
  • 不要太过安逸,越安逸越危险

2022-06-24 周五


原生js 如何实现跨页面通信?

实现原理,监听 storage

 // 监听 storage 变化
          window.addEventListener('storage',   (e)=>{
            console.log('e:',e)
            if (e.key === 'xxxx') {
                const params = JSON.parse(e.newValue);
         
            }
        });

触发 storage,这里必须 window.localStorage.setItem 才生效

   window.localStorage.setItem('xxxx',JSON.stringify({
               name:'1111',
              age:'18'
            }))

react 遇到短路操作的渲染问题

react 遇到短路操作的渲染问题

问题产生

今天组内同学发现了个问题,代码如下:

   {
       0 && <div>xxxx<div> 
   }

这种短路操作符写法,如果第一个为 假,则返回 第一个值,所以页面就会渲染 0

产生原因

  • react 中的 jsx 是一个 表达式,当采用 短路写法的时候 如果的一个 值为 0 为假,则 会返回 0

  • a && b ,如果a 我假,则返回 a

  • a && b ,如果b 我假,则返回 b

    如何规避?

    • 尽量用三目运算符书写
    • 如果想用这种短路写法,需要明确几点:

    数组,最好 list.length>0 && <>xxxx</>
    数字, 最好 String(a) && <>xxxx</>
    字符串为空,就渲染空,可以不做处理
    对象 总为真

CSS 变量

CSS 变量

描述: 可以使用变量的形式 使用 css 属性值,变量声明大小写敏感

变量的声明

全局变量声明

:root{
   --theme-color: #4d4e53;
}

局部变量声明

body {
   --color: #7F583F;
}

var() 函数的使用

  • 可以通过 var () 函数进行变量读取
div{
   background-color: var(--theme-color)
   color:  var(--color)
}
  • var 函数还可以使用第二个参数,表示变量的默认值。如果该变量不存在,就会使用这个默认值。
div{
   background-color: var(--theme-color,  #FFFFFF)
}
  • var 函数还可以用在变量的声明
  :root {
      --primary-color: red;
      --logo-text: var(--primary-color);
  }

需要注意的问题是:变量值只能用作属性值,不能用作属性名

.foo {
  --side: margin-top;
  /* 无效 */
  var(--side): 20px;
}

关于变量值的类型

如果变量值是一个字符串,可以与其他字符串拼接。

--bar: 'hello';
--foo: var(--bar)' world';

如果变量值是数值,不能与数值单位直接连用。

.foo {
  --gap: 20;
  /* 无效 */
  margin-top: var(--gap)px;
}

上面代码中,数值与单位直接写在一起,这是无效的。必须使用calc()函数,将它们连接。

.foo {
  --gap: 20;
  margin-top: calc(var(--gap) * 1px);
}

如果变量值带有单位,就不能写成字符串

/* 无效 */
.foo {
  --foo: '20px';
  font-size: var(--foo);
}

/* 有效 */
.foo {
  --foo: 20px;
  font-size: var(--foo);
}

参考

滚定区域内,把子元素滚动到 父元素中间位置(如:可滚动横向 tab 滚动到中间位置)

// parentEl代表父元素,也就是设置了overflow为可滚动的元素
    // childEl代表需要滚动到父元素正中间的直接子元素

    // 水平滚动
    let x = childEl.offsetLeft - parentEl.clientWidth + parentEl.clientWidth/2 + childEl.clientWidth/2;
    parentEl.scrollTo({
        left: x,
        behavior: "smooth",
    });

    // 垂直滚动
    let y = childEl.offsetTop - parentEl.clientHeight + parentEl.clientHeight/2 + childEl.clientHeight/2;
    parentEl.scrollTo({
        top: y,
        behavior: "smooth",
    });

用 Object.entries() 解构出对象的键值对

我们可能会碰到一些这种场景,就是根据对象的键值对来处理逻辑的需求

通常,我会用 Object.keys 或者 Object.values 但是这两个方法只能迭代出 键的数组 或值的数组

Object.entries 有个优点就是可以迭代出 键值对数组

const oj = {
    name:'jslin',
    age:'16',
    sex:'男',
    bag:'xxx',
    0:'xxxx'
}
Object.entries(oj)

image

实践中,我们可以用 这个键值对数组更快捷高效的去完成特殊场景需求
如:

Object.entries(oj).map(([key,val])=>{
   console.log('key:',key,'val:',val)
})

Object.entries(oj).forEach(([key,val])=>{
   console.log('key:',key,'val:',val)
})

for(const [key,val] of Object.entries(oj)){
    console.log('key:',key,'val:',val)
    
}

base64 转 流文件

base64转文件流

/**
 * Base64编码转换成blob, (data:image/png;base64,xxxx)
 * @param {*} base64
 * @return {*}
 */
 export function base64ToBlob(base64) {
  const parts = base64.split(';base64,')
  const contentType = parts[0].split(':')[1] // image/png
  const raw = atob(parts[1]) // base64数据
  const rawLength = raw.length
  const uInt8Array = new Uint8Array(rawLength)
  for (let i = 0; i < rawLength; ++i) {
    uInt8Array[i] = raw.charCodeAt(i)
  }
  const blobFile = new Blob([uInt8Array], {
    type: contentType,
  }) 
  return new File([blobFile],`${new Date().getTime()}.${contentType.replace(/image\//g,'')}`,{
    type: contentType,
  })
}

文件流上传

export function uploadImage(file) {
 const formData = new FormData()
  formData.append('file', file)
  formData.append('xxx', 'xxx') //接口入参
 
 
  return request('xxxxx', formData)
}

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.