月归档:三月 2017

在 Tmux 中开启鼠标选择与复制

Tmux 高效的快捷键和屏幕分割功能可以显著提高操作效率,但是默认进行内容选择与复制的操作有些繁琐。有时其他同事帮忙调试时很不适应,会不自然的用鼠标去拖选内容复制。在 Tmux 中开启鼠标模式并不复杂,只是常见的文档里并未列出。 在 tmux.conf 中加入下列设置(tmux 2.1 之前的版本): set -g mode-mouse on set -g mouse-resize-pane on set -g mouse-select-pane on set -g mouse-select-window on 在 tmux 2.1 中,对鼠标模式进行了重写,因此新版只需要增加一段设置即可: set -g mouse on 这样在 macOS 中随意滚动进入选择模式后,按住 option 键就用直接用鼠标选择文字,然后再按鼠标中键就能直接复制内容到系统剪切板中了。 -- EOF --

发表在 软件技巧 | 标签为 , | 19 条评论

使用 .toLocaleString() 轻松实现多国语言价格数字格式化

最近在项目中遇到了多语言价格格式化的需求(即 $2399 => $2,399 的转换)。在过去做大陆站时显然是没有这种需求的,因为千位分隔符(group separator)是为了方便快速看懂大数字位数,根据英语的千位分位方式(千、百万、十亿、万亿)而设置的。中文虽然国标规定四位以内的整数可以不分节,但所有主流网站对更大的数字也都没有进行数字分节。因为千位分隔符对中国人来说本身就是没有卵用的东西,中文即便使用数字分位,也是万位分位方式(万、亿、兆)。 那么用代码对数字进行格式化,显然不是逢三位加逗号这么简单。比如印度在数字分位符号上的处理,就堪称业界奇葩: 印度的数字读法用“拉克”(十万)和“克若尔”(千万),数字标法用不对称的数位分离,即小数点左侧首先是三位分隔,然后继续向左都是两位分隔。如:三千万(3 克若尔)会写成 3,00,00,000。 —— 维基百科 简单的暴利处理无法满足多语言支持,此时使用 Number.prototype.toLocaleString() 进行数字格式化处理再好不过。 使用 .toLocaleString() 在 JavaScript 中,数字对象的 .toLocaleString() 方法如果不传参数,则采用宿主环境的系统语言进行分位处理。 var price = 1024; price.toLocaleString(); // => "1,024" 使用 locales 参数 在 ECMA-402 标准的实现中,增加了.toLocaleString() 方法对 locales 的支持,语法为 numObj.toLocaleString([locales [, options]]),locales 参数接收 BCP 47 语言标签格式的字符串或数组。 那么将数字强制转化为印度格式就变的简单: var price = 1669999; price.toLocaleString('en-IN'); // => "16,69,999" 这样就可以轻松处理多语言的自动格式化了,只要根据 <html lang="en-IN"> 中的 lang 属性动态读取就可以了。 var price = 1669999; var lang = document.querySelector('html').getAttribute('lang'); price.toLocaleString(lang); // 中文页面下 => "1,669,999" 使用 options 参数 如果仅仅是做到多语言自动格式化数字,显然还不够细腻。通过 .toLocaleString() 方法的 options 参数,可以做到转化至相应语言的货币格式。 在我的项目之前的实现中,多国语言的货币符号是通过模板渲染时读取配置文件完成转换的。如果使用.toLocaleString()  展示或加工展示所有货币数字,则无需这一步骤: var price = 2499; price.toLocaleString('en-IN', { style: 'currency', currency: 'INR' }); // => "₹ 2,499.00" 如果不想要显示末尾的小数「.00」,只要设置一下最小分位 minimumFractionDigits 即可(默认是 2): var price = 2499; price.toLocaleString('en-IN', { style: 'currency', currency: 'INR', minimumFractionDigits: 0 }); // => "₹ 2,499" 这样一个完美的价格格式化功能就完成了。options 对象参数接收一系列样式属性,常用的有: style:可选值为 decimal(小数)、currency(货币)或 percent(百分比); currency:设置为货币样式时使用的符号,支持列表在这里; useGrouping:布尔值,是否显示数字分位。 关于 locales 参数和 options 参数支持的其它属性,例如上面使用的 minimumFractionDigits,可以查阅 MDN,我刚把最新的英文版翻译了一遍。 兼容性 所有现代浏览器都支持 locales 参数,因此在移动端使用是安全无痛的。桌面端的支持则是 IE11 及以上。 另外,如果想在后端直接对不同页面直接输出对应的货币符或者做分位转换等操作,只要用 node.js 做一个转换就行了。 想到这里,我已经忍不住要萌萌哒了,去优化我们的工作流啦。JavaScript,FTW! 相关链接 MDN: Number.prototype.toLocaleString() MDN: Intl.NumberFormat 维基百科:小数点 为何数字分隔符三位一隔? -- EOF --

发表在 前端开发 | 标签为 , | 留下评论

[译] JavaScript 数组方法:变异 vs. 非变异

本文翻译自:JavaScript Array Methods: Mutating vs. Non-Mutating JavaScript 提供了许多方式去增加、删除和替换数组中的元素,有些会作用到原数组本身,有些则不是——它们会返回一个新数组。 接下来,我会分别列举如何使用变异或非变异方法来实现这三个操作。文章末尾还会展示如何通过非变异方法 array.map() 来遍历数组并转化其中的元素。 虽然在这我没有列举一个详尽的列表,但是下面基本包含了数组所有的基础操作方式。 注意:接下来的内容中,当需要使用非变异方法时,我会使用 const 来声明数组,否则会用 let。尽管你可以改变一个用 const 声明的数组而且也不会抛错,但我还是喜欢用 const 显式地告诉大家这个值不会改变。 警告:看这篇文章的时候,要特别留意它们的区别: array.splice() 会改变原始数组,而 array.slice() 则不会改变原始数组。 增加元素:变异方法 为数组增加元素的变异方法是 array.push() 和 array.unshift()。 // since the array will be mutated, // use 'let' rather than 'const' let mutatingAdd = ['a', 'b', 'c', 'd', 'e']; mutatingAdd.push('f'); // ['a', 'b', 'c', 'd', 'e', 'f'] mutatingAdd.unshift('z'); // ['z', 'a', 'b', 'c', 'd', 'e'] 上面的代码: array.push() 增加一个元素到数组末尾 array.unshift() 增加一个元素到数组开头 增加元素:非变异方法 有两个办法可以在不改变原始数组的情况下增加元素。 第一个是 array.concat()。 // since we will not be mutating, // use const const arr1 = ['a', 'b', 'c', 'd', 'e']; const arr2 = arr1.concat('f'); // ['a', 'b', 'c', 'd', 'e'. 'f'] console.log(arr1); // ['a', 'b', 'c', 'd', 'e'] 第二个方法需要借助 JavaScript 的展开运算符。展开运算符是数组前的三个点(...)。 // since we will not be mutating, // use const const arr1 = ['a', 'b', 'c', 'd', 'e']; const arr2 = [...arr1, 'f']; // ['a', 'b', 'c', 'd', 'e', 'f'] const arr3 = ['z', ...arr1]; // ['z', 'a', 'b', 'c', 'd', 'e'] 向上面这样使用展开运算符时,将会从原数组中拷贝所有元素放到新的数组中。 在第 5 行,我们从 arr1 取得了所有元素的拷贝,然后放到了新数组中,最后把 'f' 放在末尾。 在第 6 行,过程与上面一样,只不过新元素 'z' 放在了数组中其它元素的前面。 删除元素:变异方法 为数组删除元素的变异方法是 array.pop() 和 array.shift()。 // since the array will be mutated, // use 'let' rather than 'const' let mutatingRemove = ['a', 'b', 'c', 'd', 'e']; mutatingRemove.pop(); // ['a', 'b', 'c', 'd'] mutatingRemove.shift(); // ['b', 'c', 'd'] 上面的代码: array.pop() 删除数组中的最末的元素 array.shift() 删除数组中开头的元素 array.pop() 和 array.shift() 方法都返回被删除的元素。所以你可以抓取删除的元素并存到一个变量上。 let mutatingRemove = ['a', 'b', 'c', 'd', 'e']; const returnedValue1 = mutatingRemove.pop(); console.log(mutatingRemove); // ['a', 'b', 'c', 'd'] console.log(returnedValue1); // 'e' const returnedValue2 = mutatingRemove.shift(); console.log(mutatingRemove); // ['b', 'c', 'd'] console.log(returnedValue2); // 'a' 还可以用 array.splice() 来删除数组中的多个元素。 let mutatingRemove = ['a', 'b', 'c', 'd', 'e']; mutatingRemove.splice(0, 2); // ['c', 'd', 'e'] 这里的 mutatingRemove.splice(0, 2) 使用了两个参数(也可以是多个参数,下面还会再提到它)。 第一个参数是 splice 的起始索引位置。 第二个参数是想要删除的数量。 在上面的例子里,从 mutatingRemove 数组中删除了两个(第二个参数)元素,删除的元素起始于索引 0(第一个参数)。 就像 array.pop() 和 array.shift() 一样,array.splice() 方法同样返回被删除的元素。 let mutatingRemove = ['a', 'b', 'c', 'd', 'e']; let returnedItems = mutatingRemove.splice(0, 2); console.log(mutatingRemove); // ['c', 'd', 'e'] console.log(returnedItems) // ['a', 'b'] 删除元素:非变异方法 JavaScript 中的 array.filter() 方法会从原数组中创建一个新数组,但是这个新数组只包含符合特定要求的元素。 // since we will not be mutating, // use const const arr1 = ['a', 'b', 'c', 'd', 'e']; const arr2 = arr1.filter(a => a !== 'e'); // ['a', 'b', 'd', 'f'] // OR const arr2 = arr1.filter(a => { return a !== 'e'; }); // ['a', 'b', 'd', 'f'] 上面的代码中,条件是「!== 'e'」,所以新数组(arr2)跟原始数组类似,只是仅包含符合「 !== 'e'」条件的元素。 *一些箭头函数的特性: 在单行箭头函数(第 5 行)中,「return」关键字是隐式存在的,所以不需要显式写出来。 但是,在多行箭头函数(第 7~9 行)中,你需要显式的返回一个值。 另一种删除数组元素的非变异方法是使用 array.slice()(不要跟 array.splice() 搞混了)。 array.slice() 接受两个参数。 第一个参数是开始拷贝的起始索引位置。 第二个参数是拷贝结束的索引位置。结束位置的元素并不会包含进去(前开后闭)。 // since we will not be mutating, // use const const arr1 = ['a', 'b', 'c', 'd', 'e']; const arr2 = arr1.slice(1, 5) // ['b', 'c', 'd', 'e'] const arr3 = arr1.slice(2) // ['c', 'd', 'e'] 上面的第 4 行(const arr2 = arr1.slice(1, 5)),arr2 是由自 arr1 的索引 1 起,到 5 之前(例如索引 4)的元素拷贝而来。 第 5 行(const arr3 = arr1.slice(2))是一种常见的方式。如果使用 array.slice() 没有传入第二个参数,那么该方法会从传入的索引起一直拷贝到数组结束。 替换元素:变异方法 如果你知道要替换的元素索引,那么可以直接用 array.splice() 去替换。 所以,我们需要至少三个参数来完成它。 第一个参数是开始替换的索引位置。 第二个参数是想要删除的元素个数。 第三个之后的参数是想要插入到数组中的元素。 // since the array will be mutated, // use 'let' rather than 'const' let mutatingReplace = ['a', 'b', 'c', 'd', 'e']; mutatingReplace.splice(2, 1, 30); // ['a', 'b', 30, 'd', 'e'] // OR mutatingReplace.splice(2, 1, 30, 31); // ['a', 'b', 30, 31, 'd', 'e'] 第 4 行(mutatingReplace.splice(2, 1, 30))将 'c' 替换为 30。 第 6 行(mutatingReplace.splice(2, 1, 30, 31))删除了 'c',然后又插入了 30 和 31 两个元素。 替换元素:非变异方法 我们可以使用 array.map() 来创建一个新数组,同时我们还能检查每一个元素或者按照特定要求来替换元素。 // since we will not be mutating, // use const const arr1 = ['a', 'b', 'c', 'd', 'e'] const arr2 = arr1.map(item => { if(item === 'c') { item = 'CAT'; } return item; }); // ['a', 'b', 'CAT', 'd', 'e'] 上面的代码基于 arr1 创建了一个新数组,并把所有的 'c' 都替换成了 'CAT'。 通过 array.map() 转换数据 array.map()是一个强大的方法,可以在不影响原始数据的前提下做数据转换。 // since we will not be mutating, // use const const origArr = ['a', 'b', 'c', 'd', 'e']; const transformedArr = origArr.map(n => n + 'Hi!'); // ['aHi!', 'bHi!', 'cHi!', 'dHi!', 'eHi!'] // OR const transformedArr = origArr.map(n => { return n * 2; })// ['aHi!', 'bHi!', 'cHi!', 'dHi!', 'eHi!'] console.log(origArr); // ['a', 'b', 'c', 'd', 'e']; // orignal array is intact -- EOF --

发表在 前端开发 | 标签为 , , | 留下评论