Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

工作杂记 #25

Open
evantianx opened this issue Apr 12, 2017 · 15 comments
Open

工作杂记 #25

evantianx opened this issue Apr 12, 2017 · 15 comments

Comments

@evantianx
Copy link
Owner

evantianx commented Apr 12, 2017

IDE & 构建工具

PhpStorm

  • 光标停留在<img>src属性上,按住shift即可显示图片

  • +
    打开nav bar 方便查找跳转项目内文件

  • 按住Alt,拖拽鼠标即可竖向选择

  • 双击然后按住,可以弹出侧边和底部的工具栏

  • +R同时打开搜索栏和替换栏,同理也可用在路径搜索(Shift++R)✔️

  • Alt++T
    为选中的代码选择包裹块(if之类的)

  • 若当前未选中任何代码,按下Ctrl+C会复制光标所在行的代码

  • 重构当前代码(变量名),可以按下Ctrl+T

  • +O 查找类
    Shift++O 查找文件
    Alt++delete 查找变量,方法
    Shift++A 查找动作(记不清快捷键的时候可以用)

    Shift++O
    搜索文件,在文件名后添加:+行号可以直接跳转到选定文件行
    1

  • Alt+F12
    打开终端

  • Webstorm在代码右上侧提供了浏览器预览按钮
    2
    直接点击和按住Shift预览的区别:
    3

  • F1
    查询相关文档

  • F12 聚焦于工具栏
    Esc 聚焦于编辑区
    Shift+Esc聚焦于编辑区且关闭当前工具栏

  • Shift++delete
    返回到上次修改的位置(内容不作变动)
    Shift+Alt+C
    列出最近所做的修改

  • Shift++V
    选择历史复制记录进行粘贴

  • Ctrl+Alt+R
    弹出run/debug菜单

  • 右键点击HTML标签,在弹出菜单中选择「show applied styles for tag」,即可查看标签所有样式

VS Code

  • 快速打开文件
    Cmd+P 输入文件名并选中即可前往所要查看的文件

  • 设定当前显示语言项

    + K + M

  • 命令行中用 VS Code 打开

    # open code with current directory
    code .
    
    # open the current directory in the most recently used code window
    code -r .
    
    # create a new window
    code -n
    
    # change the language
    code --locale=es
    
    # open diff editor
    code --diff <file1> <file2>
    
    # see help options
    code --help
    
    # disable all extensions
    code --disable-extensions .
  • lorem

    lorem + number 输出几个无意义字符

  • 状态栏
    Shift+Cmd+M 打开错误提示状态栏
    Cmd+K+M 打开文件语言类型选择栏

  • 文字编辑
    Shift+Alt+Up / Down 复制当前行到上或下行
    Alt+Up/Down 向上或向下移动当前行
    Cmd+Up /Down 快速到达代码第一行或最后一行

  • 快速跳转到与当前括号相匹配的另一个括号处
    Ctrl + Cmd + \

  • 关闭左侧编辑器导航

    explore.editor.visible:0

BrowserSync

指定入口文件:

browser-sync start --server --index bower.html --files="css/*.css"

Cannot GET/ #699

@evantianx
Copy link
Owner Author

evantianx commented May 3, 2017

['1', '2', '3'].map(parseInt)返回值为?


答案💯 : [1, NaN, NaN]

回顾📖 :

  • map()方法在调用 callback 时,会传递给它三个参数: 当前正在遍历的元素,元素索引及原数组本身。
    其中前两个参数一定会传给回调函数,而第三个可以忽略。

  • parseInt()方法可以有两个参数,第二个为进制数。

    在没有指定基数,或者基数为 0 的情况下,JavaScript 作如下处理:
    a. 如果字符串 string 以"0x"或者"0X"开头, 则基数是 16 (16 进制).
    b. 如果字符串 string 以"0"开头, 基数是 8(八进制)或者 10(十进制),那么具体是哪个基数由实现环境决定。ECMAScript 5 规定使用 10,但是并不是所有的浏览器都遵循这个规定。因此,永远都要明确给出radix 参数的值。
    c. 如果字符串 string 以其它任何值开头,则基数是 10 (十进制)。

解析✍️ :

'1' 和 0 分别作为字符串和进制数传给parseInt(),此时按照十进制转换 '1',得到数字 1;
'2' 和 1 分别作为字符串和进制数传给parseInt(),此时进制数非法,得到 NaN;
'3' 和 2 分别作为字符串和进制数传给parseInt(),此时按照二进制转换 '3',无法转换故得到 NaN;

Bonus👏🏻 :

function returnInt (ele) {
  return parseInt(ele, radix)
}

['1', '2', '3'].map(returnInt) // 返回[1, 2, 3]

关于 ES6 模块

ECMAScript 6 入门 #module
ECMAScript modules in browsers
待补充

小技巧

  • toggle 两个值

    // 一般写法
    if (x === a) {
      x = b
    } else if (x === b) {
      x = a
    }
    // 简洁写法
    x = a ^ b ^ x
  • 检测两个数值是否正负一致

    if ((x ^ y) >= 0) {
      // ...
    }
  • 替代 Math.floor() 的方法

    Math.floor(4.9)  // 4
    4.9 | 0  // 4
  • 对小数取整

    浮点数是不支持位运算的,所以会先直接去除小数部分,转成整数再进行位运算,就好像是对浮点数向下求整
    ~~可以进行类型转换,位运算会默认将非数字类型转换成数字类型再进行运算

    ~~(5.2) == 5;

    看尤大写的 HN 源码习来

rel=noopener的作用

当我们设置一个链接target='_blank'的时候,在新打开的页面上window.opener是指向前一个页面的,也就是说我们可以获取前一个页面的信息,这是非常危险的!
如何解决?
添加rel=noopener或者rel=noreferrer

About rel=noopener What problems does it solve?

JS 判断是否为 IE 浏览器的方法

方法来源

/**
 * 利用 IE 的注释 hack 判断 IE 浏览器版本号,也可以不传参仅判断是否为 IE
 *
 * @param    {number}  version    要检测的 IE 版本号
 */

var isIE = function(ver){
  var b = document.createElement('b')
  b.innerHTML = '<!--[if IE ' + ver + ']><i></i><![endif]-->'
  return b.getElementsByTagName('i').length === 1
}

Don't use switch

遗漏 break 关键字的时候容易造成不易发现的 bug。

建议写成:

var tokenActions = {
  '{': handleOpen,
  '[': handleOpen,
  ']': handleClose,
  '}': handleClose
};

function processToken(token) {
  if (typeof tokenActions[token] !== 'function') {
    throw new Error('Invalid token.');
  }
  return tokenActions[token](token);
}

Why is getElementsByTagName() faster than querySelectorAll()?

总结下:

getElementsByTagName() 获取到的是 live NodeList;而 querySelectorAll() 获取到的是 static NodeList
Static NodeList 比较慢的原因在于它要求获取当前 DOM 的一个快照,找到所有符合要求的元素; 而 live NodeList 则无需这样.

为什么 getElementsByTagName 比 querySelectorAll 方法快
简单讨论 querySelectorAll Vs getElementsByTagName 区别

NPM SCRIPTS: TIPS EVERYONE SHOULD KNOW

关于 npm script 的很多技巧

TEMPORAL DEAD ZONE (TDZ) DEMYSTIFIED

let / const 变量在声明之前不能访问并不是因为两者不存在声明提前,只是 TDZ!

The variables are created when their containing Lexical Environment is instantiated [...] but may not be accessed in any way until the variable’s LexicalBinding is evaluated.

Why Mapping a Constructed Array in JavaScript Doesn’t Work

const arr = Array(100).map((_, i) => i);
console.log(arr[0] === undefined);  // true

solution:

const arr = [...Array(100)].map((_, i) => i);
console.log(arr[0] === 0); // true

sparse array

An adventure in sparse arrays

几个要点:

  • trailing comma 不会为数组添加一个 hole

  • 数组中逗号之间为空时会形成 hole:

    [ 1, ,2 ]  // hole at index(1)
  • 检测 hole 的唯一方法是 array.hasOwnProperty(index)

    [ 1, ,2 ].hasOwnProperty(1) // false
  • 数组中的遍历方法如 map, forEach, every 等都不会在 hole 位置调用回调函数

    const a = new Array(1000);
    let ctr = 0;
    a.forEach(() => ctr++);
    console.log(ctr);  // 0 - the callback was never called
    
    [ 1, ,2 ].map(x => x*x) // [ 1, <empty>, 4]
    
    [ 1, , 2].filter(x => true) // [1, 2]

    keys 和 values 遍历是可以在 hole 位置触发回调的:

    const a = [ 'a', , 'b' ]
    for (let [index, value] of a.entries()) {
      console.log(index, value)
    }
    /* logs:
     * 0 'a'
     * 1 undefined
     * 2 'b'
     */

    由于 ES6 中的数组展开底层实现其实也是遍历,所以展开 sparse array 时会将 hole 变为 undefined

    [...[ 'a', , 'b' ]]  // [ 'a', undefined, 'b' ]
  • 对于大型 sparse array 的构建来说, new Array() 要快于 Array.from()

原型

reduce

重写 reduce

const reduce = (fn, acc, arr) => {
  if (arr.length === 0) return acc
  const [ head, ...tail ] = arr
  return reduce(fn, fn(acc, head), tail)
}

分配数组

将用户中的男性和女性分别放到不同的数组里:

const users = [
  { name: "Adam", age: 30, sex: "male" },
  { name: "Helen", age: 27, sex: "female" },
  { name: "Amy", age: 25, sex: "female" },
  { name: "Anthony", age: 23, sex: "male" },
];
const partition = (arr, isValid) => 
  arr.reduce(([male, female], cur) => 
    isValid(cur) ? [ [ ...male, cur ], female ] : [ male, [...female, cur] ]
  , [])

const isMale = item => item.sex === 'male'

const [ male, female ] = partition(users, isMale) 

cssText

用cssText批量修改样式踩的坑

如何禁止弹出层背景滚动

由弹出层引发对滚动原理的讨论

如何避免条件语句 hell

5 Tips to Write Better Conditionals in JavaScript

Replacing switch statements with Object literals

JavaScript 复杂判断的更优雅写法

const actions = ()=>{
  const functionA = ()=>{/*do sth*/}
  const functionB = ()=>{/*do sth*/}
  const functionC = ()=>{/*send log*/}
  return new Map([
    [/^guest_[1-4]$/,functionA],
    [/^guest_5$/,functionB],
    [/^guest_.*$/,functionC],
    //...
  ])
}

const onButtonClick = (identity,status) => {
  let action = [ ...actions() ].filter(([key,value]) => (key.test(`${identity}_${status}`)))
  action.forEach(([key,value]) => value.call(this))
}

利用 map 正则匹配,实现更好地解耦

可以预测的 JS 对象属性值顺序

Why Facebook's api starts with a for loop

了解所谓的 JSON hijacking

npm

列出项目直接依赖真正版本号(if use semver)

npm list --depth=0 

查看某个包的信息(维护者,依赖项等)

npm view vue 

Tricks of Resting and Spreading JavaScript Objects

  • 动态删除某个对象的属性

    const removeProp = prop => ({ prop, ...rest }) => rest
    // eg
    const removeName = removeProp('name')
    
    removeName({ id: 1, name: 'John', age: 25 }) // { id: 1, age: 25 }

@evantianx
Copy link
Owner Author

evantianx commented May 4, 2017

制作一个 iOS 风格的 switch button

demo

今天业务需求制作一个 switch button,把制作思路简单梳理下:

首选标签为<input type="checkbox">,因为我们可以根据:checked伪类来进行 CSS Transition 变换;

其次,选择<label>标签作为主战场,因为点击<label>区域即相当于点击对应的<input>标签。利用伪类:before:after制作切换按钮的两个部分:按钮和内部区域。

有了这个思路就好办了,步骤如下:

  1. 构造基本 HTML 结构
    <div class="switch">
      <input id="btn" type="checkbox">
      <label for="btn"></label>
    </div>
  2. 设置样式使<input>消失,从而不影响后续的样式
    * {
      box-sizing: border-box; /* 方便样式计算 */
    }
    .switch {
      input {
        display: none;
      }
    }
  3. <label>设置基本样式
    .switch {
      input + label {
        display: block;
        position: relative;
        width: 120px;
        height: 60px;
        cursor: pointer;
        outline: none;
        padding: 2px;
        background-color: #ddd;
        border-radius: 60px;
      }
    }
  4. 添加伪类样式
    .switch {
      input + label {
        &:before, &:after {
          content: '';
          position: absolute;
          top: 1px;
          left: 1px;
          bottom: 1px;
        }
        /* <label>内部区域样式 */
        &:before {
          right: 1px; /* 将:before伪类撑满整个<label> */
          background-color: #f1f1f1;
          border-radius: 60px;
          transition: background 0.8s;
        }
        /* 圆形按钮样式 */
        &:after {
          width: 58px;
          background-color: #fff;
          border-radius: 100%;
          box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
          transition: margin 0.4s;
        }
      }
      input:checked + label {
        &:before {
          background-color: #8ce196;
        }
        &:after {
          margin-left: 60px;
        }
      }
    }

为列表元素添加间距

通常会使用::not(first-child)之类的选择器来避免首尾元素产生不必要的间距或者其他样式。
而如果使用兄弟选择器则完全可以使得代码更为简洁:

li {
  background: powderblue;
}

li + li {
  margin-top: 20px;
}

former_element + target_element { style properties }

然而某些需求极为严格,要求在占满一页时最后一个元素不显示 border-bottom, 在未占满时最后一个元素显示 border-bottom.

/* 假设一页最多可摆放五个列表
    此时 0 1 2 3 序号的元素正常显示底线,>= 5 的不显示 👍
*/
li:nth-child(-n+4) {
  border-bottom: 1px solid blue;
}

position: fixed失效的情况

fixed不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed 属性会创建新的层叠上下文。当元素祖先的 transform 属性非 none 时,容器由视口改为该祖先。

position: fixed失效的奇怪现象

Sticky as a Local Fixed?

制作一个宽高比为固定值的 div

Constant width to height ratio

主要利用 padding-top 和伪元素

Updated:

Keeping aspect-ratio with HTML and no padding tricks

Maintaining Aspect Ratio with CSS Grid

利用 SVG 和 Grid 实现

  • SVG knows how to maintain aspect ratio
  • CSS grid knows how to make overlapping items affect each other’s size

如何阻止 modal 背后的内容滚动?

  • 纯 CSS 方法
  • JS
    const bodyEl = document.body
    let top = 0
    
    function stopBodyScroll (isFixed) {
     if (isFixed) {
       top = window.scrollY
       bodyEl.style.position = 'fixed'
       bodyEl.style.top = -top + 'px'
     } else {
       bodyEl.style.position = ''
       bodyEl.style.top = ''
       window.scrollTo(0, top) // 回到原先的top
     }
    }

Chrome 表单自动填充默认样式修改

Time-saving CSS techniques to create responsive images

@evantianx
Copy link
Owner Author

evantianx commented May 9, 2017

如何用 CSS 隐藏滚动条但保持可滚动状态?

webkit 下只需要为滚动元素添加下列代码:

element::-webkit-scrollbar {
  display: none;
}

其他相关信息参见 Stackoverflow 上一篇回答: Hiding the scrollbar on an HTML page

@evantianx
Copy link
Owner Author

evantianx commented May 10, 2017

CSS 实现文本超出显示省略号

超出某个宽度则显示省略号:

span {
  white-space: nowrap;
  text-overflow: ellipsis;
  width: 100px;
  display: block;
  overflow: hidden;
}

超出某行数则显示省略号:

比较兼容的方法,将高度设置为行高的 n 倍( n 即为你要 n 行后省略),此时开始省略行文末显示为渐变白 + 省略号。

.fade {
  display: block;
  position: relative;
  width: 100px;
  height: 3.6em;
  line-height: 1.2em;
  overflow: hidden;
}
.fade:after {
  content: "...";
  position: absolute;
  bottom: 0;
  right: -6px;
  width: 70%;
  height: 1.2em;
  text-align: center;
  background: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1) 50%);
}

webkit 方法:

<div class="module line-clamp">
  <p>
    <!-- 此处省略一大坨文本 -->
  </p>
</div>
.module {
  border: 1px solid #CCC;
  width: 250px;
  margin: 0 0 1em 0;
  overflow: hidden;
}
/* 必须设置为 0 ,否则会扰乱布局 */
.module p {
  margin: 0;
  padding: 0;
}
.line-clamp {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical; 
}

demo by Vesa Piittinen

@evantianx
Copy link
Owner Author

evantianx commented May 18, 2017

面试题

下述 div 高度为多少?

<div></div>
div {
  width: 200px;
  padding-top: 60%;
}

JS

function Foo() {
  getName = function () { alert (1); };
  return this;
}
Foo.getName = function () { alert (2);};
Foo.prototype.getName = function () { alert (3);};
var getName = function () { alert (4);};
function getName() { alert (5);}
 
//请写出以下输出结果:
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();

分析

@evantianx
Copy link
Owner Author

evantianx commented May 23, 2017

移动端

@evantianx
Copy link
Owner Author

background-position取不同数值类型时其相对坐标是如何定位的?

  • 对于 px, rem 之类的单位,以图片左上角为相对坐标
  • 对于百分比值,以图片本身百分比所对应的坐标为相对坐标

闲扯 background-position 的单位属性值

@evantianx
Copy link
Owner Author

evantianx commented Aug 21, 2017

判断某个元素是否进入可视区域?

  • 通过 clientHeight, scrollTop 以及 offsetTop 来判断

    function isInSight(el) {
      const viewportHeight = window.innerHeight
                             || document.documentElement.clientHeight
                             || document.body.clientHeight; // 视口高度
      const scrollTop = document.scrollTop  // 滚动条高度,即视口顶端据文档顶端的距离
      const elHeight = el.offsetTop  // 元素高度,即元素顶端据文档顶端的距离
      
      return (elHeight-scrollTop) <= viewportHeight
    }
  • 通过 getBoundingClientRect 来判断

    function isInSIght(el) {
      const viewportHeight  // 获取视口高度同上,代码省略
      const bound = el.getBoundingClientRect()
    
      return viewportHeight >= bound.top
    }

    会造成大量的重绘(repaint)

  • 通过 IntersectionObserver API 来判断

    var io = new IntersectionObserver(callback, option)
    // 开始观察
    io.observe(document.getElementById('example'))
    // 停止观察
    io.unobserve(element)
    // 关闭观察器
    io.disconnect()

    IntersectionObserver API 使用教程
    IntersectionObserver
    使用 IntersectionObserver 和 registerElement 打造 Lazyload

@evantianx
Copy link
Owner Author

如何实现单行居中,多行靠左显示效果?

<div>
  <p><span>啦啦啦</span></p>
  <p><span>啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦</span></p>
</div>
div {
  width: 200px;
}

p {
  text-align: center;
}
p span {
  display: inline-block;
  text-align: left;
}

整体思路就是父级添加 text-align: center 属性,子级改变 displayinline-block 并且添加 text-align: left 属性。

@evantianx
Copy link
Owner Author

evantianx commented Sep 4, 2017

font-size:0 来清除 inline-block 间距

inline-block 的元素之间会受空白区域的影响,也就是元素之间差不多会有一个字符的间隙。如果在同一行内有 4 个 25% 相同宽度的元素,会导致最后一个元素掉下来。你可以利用元素浮动 float ,或者压缩html,清除元素间的空格来解决。但最简单有效的方法还是设置父元素的 font-size 属性为 0(在子元素中设置 font-size )

你不知道的 CSS

@evantianx
Copy link
Owner Author

evantianx commented Sep 5, 2017

maxlength 属性在 <input type="number"> 上不起作用

If the value of the type attribute is text, email, search, password, tel, or url, this attribute(maxlength) specifies the maximum number of characters (in Unicode code points) that the user can enter; for other control types, it is ignored.

所以 type="number" 的输入框会忽视 maxlength 这个属性,可以这样写:

<input type="text" pattern="\d*" maxlength="18">

maxlength ignored for input type=“number” in Chrome

@evantianx
Copy link
Owner Author

evantianx commented Sep 6, 2017

如何用纯 CSS 构造 skeleton screen ?

作者利用了渐变来创建 skeleton screen 中的局部块,不依赖除父级外 HTML 元素,同时使用 css 自定义属性,代码可读性和重用性很高,赞!

:empty 也是一个亮点

Building Skeleton Screens with CSS Custom Properties
Demo

@evantianx
Copy link
Owner Author

关于 <input type="date"> 的一系列衍生品

Prefilling a Date Input

@evantianx
Copy link
Owner Author

@evantianx
Copy link
Owner Author

evantianx commented Dec 3, 2018

Interview

JS

async function async1() {
  console.log("async1 start");
  await async2();
  console.log("async1 end");
}

async function async2() {
  console.log("async2");
}

console.log("script start");

setTimeout(function() {
  console.log("setTimeout");
}, 0);

async1();

new Promise(function(resolve) {
  console.log("promise1");
  resolve();
}).then(function() {
  console.log("promise2");
});

console.log("script end");

输出顺序为:

script start
async1 start
async2
promise1
script end
promise2
async1 end
setTimeout

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant