Wiki

Table of Contents

WIKI

JavaScript 中的 || 和 && 所遵循的短路现象

[2020-01-28 Tue 13:55]

|| 时,找到为 true 的分项就停止处理,并返回该分项的值,否则执行完,并返回最后的分项的值;

&& 时,找到为 false 的分项就停止处理,并返回该分项的值,否则执行完,并返回最后的分项的值。

刷新 DNS

[2020-01-28 Tue 13:54]

windows 下 刷新 DNS 的方法:打开 cmd → 输入 ipconfig /flushdns 。 Github 有时候,连接很慢,甚至有打不开的状况,此时,可以尝试刷新一下 DNS ,会有意象不到的效果哦。

滚动懒加载的实现

[2020-01-28 Tue 13:55]

→ 参考链接

什么时候需要懒加载呢?数据量大,一页显示不完,网页渲染事件长,影响体验。如何解决?分页,或数据懒加载。

先设定了基础前提,假设视窗可以显示 30 数据,总共有 56 条数据要展示。

如何实现数据懒加载呢?先来看三个属性:

  • scrollHeight ,元素总高度,包含滚动条中的内容,只读;
  • scrollTop ,当元素出现滚动条时,向下拖动滚动条时,内容向上滚动的距离,可读写;
  • clientHeight ,元素内容及其边框所占的空间大小,即可视区域大小高度。

如何判断滚动条到底部了呢?很显然,当 scrollHeight - scrollTop - clientHeight = 0 时,滚动条就到底部了。

来看代码,在第一次请求数据的时候,先设置一个变量来记录请求次数(其实后台也是做分页的处理):

// 初始化首页页码
let currentPage = 1;            // this.currentPage = 1

// 获取首页数据,apiGetTableData 为定义的获取数据的接口
// data 为请求参数
this.apiGetTableData(data).then(res => {
    $this.totalPage = res.totalPage; // 这里需要知道总页数
    $this.tableData = res.data;      // 表格数据
})

监听表格 DOM 对象的滚动事件:

let DOM = document.querySelector(targetDom);

DOM.addEventListener('scroll', function() {
    let scrollDistance = DOM.scrollHeight - DOM.scrollTop - DOM.clientHeight;

    if(scrollDistance <= 0) {                      // 为 0 证明滚动条已经到底,可以请求接口
        if(this.currentPage < this.totalPage) {   // 当前页数小于总页数继续请求
            this.currentPage++;                   // 当前页数自增

            // 请求接口代码
            // data 为请求参数
            this.apiGetTableData(data).then(res => {
                this.tableData = $this.tableData.concat(res.data); // 将请求回来的数据和当前展示的数据合并
            })
        }
    }
})

如此,就实现表格滚动下拉时的数据懒加载。

FormData

→ 参考链接

FormData 类型是什么? FormData 类型是在 XMLHttpRequest Level 2 定义的,它为序列化表单以及创建与表单格式相同的数据(用于 XHR 传输)提供便利。

如何初始化一个 formData 对象实例呢?如下:

  • 创建一个空对象实例;
  • 使用已有表单来初始化一个对象实例。

1. 创建一个空对象实例

var formData = new FormData();

后续,可以调用 append() 方法来添加数据。

2. 初始化已有表单创建实例

假设已有表单如下:

<form id="myForm" action="" method="post">
  <input type="text" name="name" />名字
  <input type="password" name="psw" />密码
  <input type="submit" value="提交" />
</form>

下面是用这个表单元素作为初始化参数,来实例化一个 formData 对象,如下:

// 获取页面已有的 form 表单
let form = document.getElementById('myForm');
// 用表单来初始化
let formData = new FormData(form);

// 还可以根据 name 来访问表单中的字段
let name = formData.get('name'); // 获取名字
let psw = formData.get('psw');   // 获取密码

// 还可以在此基础上,继续添加其他数据
formData.append('token', 'otherdata...');

3. 操作方法

formData 里面存储的数据形式是什么?一对 key/value 组成一条数据, key 是唯一的,一个 key 可能对应多个 value 。如果是使用表单初始化,每一个表单字段对应一条数据,它们的 HTML name 属性即为 key 值, value 属性对应 value 值。

key value
k1 [v1, v2, v3]
k2 v4

可以用如下方法操作数据:

  • 获取数据,通过 get(key)/getAll(key) 来获取对应的 value 值;
  • 添加数据,通过 append(key, value) 来添加数据,若 key 不存在会新增,若 key 已存在会添加到数据末尾;
  • 修改数据,通过 set(key, value) 来设置数据,若 key 不存在会新增,若存在会修改对应的 value 值;
  • 判断是否该数据,通过 has(key) 来判断是否对应的 key 值;
  • 删除数据,通过 delete(key) ,来删除数据;
  • 遍历,通过 entries() ,来获取一个迭代器,每条用一次 next() 返回一条数据,如此可以遍历所有的数据。
formData.get('name');       // 获取 key 为 name 的第一个值
formData.getAll('name');    // 返回一个数据,获取 key 为 name 的所有值

通过 XHR 来发送数据,如下:

let xhr = new XMLHttpRequest();
xhr.open('post', 'login');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(formData);

小程序跳转 H5 时 url 参数截断

[2020-01-28 Tue 13:57]

→ 参考链接

先来看一个例子,原来的 url 为 https://ultimavip.cn/m/mposter.html?source=gxw_001_t_mposter ,跳转后变为 https://ultimavip.cn/m/mposter.html ,参数 ?source=gxw_001_t_mposter 丢失了,为什么呢?编码问题。

// 跳转到 H5 页面的小程序代码
targetUrl: function() {
    console.log(this.data.mod_textUrl);
    wx.navigateTo({
        url: '../webview/webview?url=' + encodeURIComponent(this.data.mod_textUrl) // 此处需要编码,因为有 '?' ,可能浏览器不认 
    })
}

// 跳转到的 H5 页面进行解码
onLoad: function(options) {
    this.setData({
        targetUrl: decodeURIComponent(options.url); // 用 decodeURIComponent 进行解码
    })
    console.log(options.url);
}

时间日期的格式化

[2020-01-28 Tue 13:58]

// 该插件用来格式化当前输入的时间/日期

// xxxx/xx/xx xx:xx:xx
const formatTime = (date) => {
    let year = date.getFullYear(),
        month = date.getMonth() + 1,
        day = date.getDate(),
        hour = date.getHours(),
        minute = date.getMinutes(),
        second = date.getSeconds();

    return [year, month, day].map(formatNumber).join('/') +
           ' '  +
           [hour, minute, second].map(formatNumber).jon(';');
}

// xxxx-xx-xx
const formatDate = (date) => {
    let year = date.getFullYear(),
        month = date.getMonth() + 1,
        day = date.getData();

    return [year, month, day].map(formatNumber).join('-');
}

const formatNumber = (n) => {
    n = n.toString();

    return n[1] ? n : '0' + n;  // 如 8 -> 08
}

// 导出方法
module.exports = {
    formatTime: formatTime,
    formatDate: formatDate
}

JS 获取 DPI

[2020-01-28 Tue 13:59]

//获取DPI
function js_getDPI() {
    var arrDPI = new Array();
    if ( window.screen.deviceXDPI != undefined ) {
        arrDPI[0] = window.screen.deviceXDPI;
        arrDPI[1] = window.screen.deviceYDPI;
    }
    else {
        var tmpNode = document.createElement( "DIV" );
        tmpNode.style.cssText = "width:1in;height:1in;position:absolute;left:0px;top:0px;z-index:99;visibility:hidden";
        document.body.appendChild( tmpNode );
        arrDPI[0] = parseInt( tmpNode.offsetWidth );
        arrDPI[1] = parseInt( tmpNode.offsetHeight );
        tmpNode.parentNode.removeChild( tmpNode );
    }
    return arrDPI;
}

// 将 px 转成 mm
let mm = pxValue/dpi*2.54*10;   // dpi 是上面获取的,注意对应 XY 轴

CSS 换行

[2020-01-28 Tue 13:59]

→ 参考链接

文本换行有很多方式:

  • <br/> 标签元素,能够强制使得所在位置文本换行;
  • <p> 元素, <div> 设定宽度,都可以对文本内容实现自适应换行;
  • 对于长单词或链接,默认不会断开换行,方式 2 就不能够在这些文本内部进行换行,此时需要 word-wrap: break-word;word-break: break-all; 实现强制断行。

1. 强制不换行

div {
    white-space: nowrap;
}
/*
white-space:
- normal  默认
- pre     换行和其他空白字符都将受到保护
- nowrap  强制在同一行内显示所有文本,直到文本结束或者遭遇 <br> 对象
*/

2. 控制文本换行

div {
    word-break: normal;
    word-break: break-all;
    word-break: keep-all;
}
/*
word-break:
- normal        依据亚洲语言与非亚洲语言的文本规则,允许在字内换行
- break-all     该行为与亚洲语言的 normal 相同,也允许非亚洲语言文本行的任意字内断开,该值适合包含一些非亚洲文本的亚洲文本
- keep-all      与所有非亚洲语言的 normal 相同,对于中文、韩文、日文,不允许字断开,适合包含少量亚洲文本的非亚洲文本
*/

3. 强制单词内或链接内断行

div {
    word-wrap: break-word;
}
/*
word-wrap:      属性用来表明是否允许浏览器在长单词和链接内进行断句
- normal        只在允许的断字点换行
- break-word    在长单词或 URL 地址内部进行换行
*/

input 中 placeholder、disabled 状态样式修改

[2020-01-28 Tue 14:00]

问题场景:

  • 有时按业务需求更改 inputplaceholder 样式和 disabled 状态下的样式;
  • IOS 和安卓移动端样式兼容性问题,样式不一致。

处理如下:

input::-webkit-input-placeholder {
    color: #ccc;
    -webkit-text-fill-color: #ccc;
    opacity: 1;
    -webkit-opacity: 1;
}

input:disabled {
    background: none;
    color: #333;
    -webkit-text-fill-color: #333;
    opacity: 1;
    -webkit-opacity: 1;
}

input:disabled::-webkit-input-placeholder {
    color: #ccc;
    -webkit-text-fill-color: #ccc;
    opacity: 1;
    -webkit-opacity: 1;
}

相关延伸:

  • ::-webkit-input-placeholder {} 使用 webkit 内核的浏览器
  • :moz-placeholder {} Firefox 版本 4-18
  • ::moz-placeholder {} Firefox 版本 19+
  • -ms-input-placeholder {} IE 浏览器

git 比较两次 commit 之间的差异

[2020-01-28 Tue 14:00]

→ 参考链接

如何使用 git 比较两次 commit 之间的差异文件呢?可以按下述步骤进行:

  • 通过 git log 查看提交历史,获取提交 hash 码,如 hash1、hash2;
  • 通过 git diff hash1 hash2 --stat ,查看这两次提交的差异文件,如 test1、test2;
  • 通过 git diff hash1 hash2 test1 ,查看指定差异文件 test1 具体修改的代码;
  • 通过 git diff hash1 hash2 test1 > patch_file ,可以将 test1 的差异部分提取成补丁文件;
  • 通过 git diff hash1 hash2 test1 test2 > patch_file ,可以将多个文件的差异生成到同一个补丁文件。

生成补丁后,到相关目录下可以打补丁,如 pathc -p1 < patch_file ,其中 -p1 是代表忽略当前目录下的几级目录。

Tagging

[2020-01-28 Tue 14:01]

Command Description
git tag Listing your tags
git tag -l "v1.8.5" Listing the 1.8.5 series
git show v1.2 Show you've tagged the commit
git tag -a v1.4 -m "my version 1.4" Annotated tags
git tag -a v1.2 9fceb02 Tagging later
git tag -a v1.2 9fceb02 -m "my version 1.2" Tagging later and Annotated it
git push origin v1.5 Sharing Tags
git push origin --tags Push a lot of tags at once
git tag -d v1.4 Deleting tags
git push origin --delete <tagname> Deleting a remote tag
git checkout 2.0.0 Checking out tags
git checkout -b version2 v2.0.0 Switched to a new branch 'version2'

Java 中的接口方法为什么必须是 public

[2020-02-05 Wed 22:35]

子类重写父类方法时,方法的访问权限不能小于原访问权限。接口是一种约束和规范,是一种 更加抽象的抽象类 ,在接口中,方法的默认权限就是 public ,所以子类重写后只能是 public

接口中没有变量(既然是约束和规范,怎么能够定义一个大家都可以改的东西呢),只能是常量,默认修饰符为 public static final

  • 接口必须要具体类实现才有意义,所以必须是 public
  • 接口中的属性对所有实现类只有一份,所以是 static
  • 要使实现类向上转型成功,所以必须使 final 的。

JavaScript JSON.stringify()

[2020-02-27 Thu 09:02]

JSON.stringify() 方法用于将 JavaScript 值转换为 JSON 字符串。语法如下:

JSON.stringify(value[, replacer[, space]])

参数说明:

  • value ,必需,要转换的 JavaScript 值(通常为对象或数组);
  • replacer ,可选,用于转换结果的函数或数组;
  • space ,可选,文本添加缩进、空格和换行符。

其中,对于 replacer ,如果它为 函数 ,则 JSON.stringify 将调用该函数,并传入每个成员的键和值。使用返回值而不是原始值。如果此函数返回 undefined ,则派出成员。根对象的键是一个空字符串: "" 。如果 replacer 是一个 数组 ,则仅转换该数组中具有键值的成员,成员的转换顺序与键在数组中的顺序一样。

其中,对于 space ,如果它是一个 数字 ,则返回值文本在每个级别缩进指定数组的空格,如果 space 大于 10 ,则文本缩进 10 个空格。 space 也可以使用 非数字 ,如 \t

var str = {"name":"菜鸟教程", "site":"http://www.runoob.com"}

// 只有一个参数的情况
str_pretty1 = JSON.stringify(str)
// → {"name":"菜鸟教程","site":"http://www.runoob.com"}

// 使用参数情况
str_pretty2 = JSON.stringify(str, null, 4)
// 
// {
//     "name": "菜鸟教程",
//     "site": "http://www.runoob.com"
// }

如何设置终端 256 色

[2020-02-28 Fri 11:37] https://stackoverflow.com/questions/63950/how-to-make-emacs-terminal-colors-the-same-as-emacs-gui-colors?r=SearchResults

设置 TERM.bashrc 文件中,如下:

export TERM=xterm-256color

如此,便设置好了。

加入我们使用在终端中使用 Emacs ,执行 M-x list-colors-display ,便可以看到 256 色已经全部激活,如此,终端下使用 Emacs 和 Emacs GUI 的颜色便相差无几了。

Emacs 宏操作

[2020-02-28 Fri 12:02] https://www.jianshu.com/p/6ad946eb8ebc

Key/Command Description
C-x ( 开启宏记录
C-x ) 关闭宏记录
C-x e 执行刚录制的宏
C-u n C-x e 执行 n 次刚录制的宏
M-x name-last-kbd-marco 给刚记录的宏命名
M-x insert-kbd-marco 把刚命名的宏记录写入到文件中

可以设置一个专门的文件(如 ~/.emacs.d/macro.el )来记录宏,然后在 init.el 中加载改文件( (load-file "~/.emacs.d/macro.el") ), 如此便可以实现持久化。

如这个例子:用宏定义了下翻 15 行和上翻 15 行的快捷键。

;; macro.el
(fset 'next-lines
    "\C-u15\C-n")
(fset 'previous-lines
    "\C-u15\C-p")
;; init.el

;; ...
;; 加载 macro.el
(load-file "~/.emacs.d/macro.el")
;; 绑定快捷键
(global-set-key (kbd "C-x n RET") 'next-lines)
(global-set-key (kbd "C-x p RET") 'previous-lines)

Axios 为什么需要实例

[2020-03-09 Mon 10:18]

默认会导出实例 axios ,通常只需使用这个 axios 就可以了。

但有时你可能需要创建多个实例,比如你需要访问多个服务地址,而这些服务请求和响应的结构都完全不同,那么,你就可以通过 axios.create 创建不同的实例来处理。

比如 axios1 是用 http 状态码确定响应是否正常,而 axios2 是服务器自己定义的状态码,又或者它们请求头不同,支持的 Content-Type 不同,那么可以单独为 axios1axios2 写拦截器。

npm 安装是 –save 和 –save-dev 的区别1

[2020-03-09 Mon 10:42]

在生产环境中需要使用到的包安装时添加 --save ,只在开发环境中用到的包安装时添加 --save-dev

以 npm 安装 vue 为例。

1. npm install vue

  • 会把 vue 包安装到 node_modules 目录中;
  • 不会修改 package.json 文件;
  • 之后运行 npm install 命令时,不会自动安装 vue 。

2. npm install vue –save

  • 会把 vue 包安装到 node_modules 目录中;
  • 会在 package.json 文件中的 dependencies 属性下添加 vue ;
  • 之后运行 npm install 命令时,会自动安装 vue 包到 node_modules 目录中;
  • 之后运行 npm install --production 或者注明 NODE_DEV 变量值为 production 时,不会自动安装 vue 到 node_modules 目录中。

3. npm install vue –save-dev

  • 会把 vue 包安装到 node_modules 目录中;
  • 会在 package.json 文件中的 devDependencies 属性下添加 vue ;
  • 之后运行 npm install 命令时,会自动安装 vue 包安装到 node_modules 目录中;
  • 之后运行 npm install --production 或者注明 NODE_DEV 变量值为 production 时,不会自动安装 vue 包安装到 node_modules 目录中。

4. npm install vue –global

  • 会把 vue 包安装到全局环境中而不是当前项目的 node_modules 目录中(其实是全局环境中的 node_modules 啦);
  • 不会修改 package.json 文件;
  • 之后运行 npm install 命令时,不会自动安装 vue 。

JavaScript indexOf

[2020-03-19 Thu 09:18]

indexOf() 方法可返回指定的字符串值在字符串中 首次 出现的位置:

  • 如果没有找到匹配的字符串则返回 -1 ;
  • indexOf() 方法区分大小写。
let str = 'Hello world, welcome to the universe.';
let n = str.indexOf('welcome');  // → 13
let m = str.indexOf('e', 5);     // → 14
let v = str.indexOf('none');     // → -1

具体语法如下:

string.indexOf(searchvalue, start)
参数 描述
searchvalue 必需,规定需检索的字符串值
start 可选的整数参数,规定在字符串中开始检索的位置。它的合法值是 0 到 string Object.length - 1 。如果省略该参数,则将从字符串的首字符开始检索。

与之相似的还有 lastIndexOf() 方法,可返回一个指定的字符串值在字符串中 最后一次 出现的位置。

#. Array includes()

延伸一下,我们来看一下 JavaScript Array includes() 方法。

includes() 方法用来判断一个数组是否包含一个指定的值,如果是返回 true ,否则 false

[1, 2, 3].includes(2);     // true
[1, 2, 3].includes(4);     // false
[1, 2, 3].includes(3, 3);  // false
[1, 2, 3].includes(3, -1); // true
[1, 2, NaN].includes(NaN); // true

具体语法如下:

arr.includes(searchElement)
arr.includes(searchElement, fromIndex)
参数 描述
searchElement 必须,需要查找的元素
fromIndex 可选,默认为 0 。从该索引出开始查找 searchElement 。如果为负值,则按升序从 array.length + fromIndex 的索引处开始搜索

Footnotes:

Date: 2020-01-28 Tue 14:02

Author: Jack Liu

Created: 2020-04-03 Fri 19:39

Validate