无法注册原因

  • 此电话号码无法用于进行验证

解决思路

  • 通过其他页面或方式进入谷歌注册入口,如通过 Google Voice 或 Google Analysis 等进入

  • 用安卓手机自带的电子邮件客户端申请

  • 在选择邮箱时,切换 “改用我目前的邮件地址” 为 “注册新的 Gmail 邮箱”

  • 选择适当的语言以及模式(页面左下角语言设置)

  • Chrome 语言设置为 English-United States

成功案例

  • 2019/08/06 小米手机-使用自带的电子邮件客户端-用国内手机号-QQ 邮箱-注册成功

  • 2020/01/05 小米手机-使用自带的电子邮件客户端-用国内手机号-注册新的 Gmail 邮箱-注册成功

  • 2020/01/19 苹果手机-使用自带的邮件客户端-国内手机号-注册新的 Gmail 邮箱-注册成功

  • 2020/12/29 苹果手机-使用自带的邮件客户端-国内手机号(已被使用过)-注册新的 Gmail 邮箱-注册成功

  • 2021/04/06 w10-谷歌浏览器 + WebRTC Leak Prevent插件(在无痕模式下启用 + IP handling policy:Disabled non-proxied UDp(froce proxy) )-国内手机号(已被使用过)-注册新的 Gmail 邮箱-注册成功

https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/addEventListener

添加事件

// 语法
target.addEventListener(type, listener[, useCapture])
// type: 事件的类型: click mouseover 字符串类型,不带 on
// listener: 函数,每次点击,执行这个函数
// useCapture: 可选,true: 事件在捕获阶段执行,false: 事件在冒泡阶段执行(默认)

target.addEventListener(type, listener[, options])

options 可选,可用的选项如下:
capture: Boolean,默认 false,等价于以前的 useCapture 参数
once: Boolean,默认 false,如果是 true,表示 listener 在添加之后最多只调用一次。 listener 也会在其被调用之后自动移除
passive: Boolean,默认 false,设置为 true 时,表示 listener 永远不会调用 preventDefault() 如果 listener 仍然调用了这个函数,客户端将会忽略它并抛出一个控制台警告。

浏览器无法预先知道一个监听器会不会调用 preventDefault(),它能做的只有等监听器执行完后再去执行默认行为,而监听器执行是要耗时的,有些甚至耗时很明显,这样就会导致页面卡顿

.passive 修饰符尤其能够提升移动端的性能
vue .passive 事件修饰符

移除事件

removeEventListener

在第三个参数是布尔值的时候,addEventListener(“foo”, listener, true) 添加的监听器,必须用 removeEventListener(“foo”, listener, true) 才能删除掉, 因为这个监听器也有可能还注册在了冒泡阶段, 如果第三个参数为 false 则直接通过 removeEventListener(“foo”, listener) 就可以删除

通过 addEventListener(“foo”, listener, {capture: true}) 添加的监听器删除时也同样需要添加 {capture: true} 来删除,当然 {capture: true} 换成 true 也可以

通过 addEventListener(“foo”, listener, {passive: true}) 添加的监听器直接通过 removeEventListener(“foo”, listener) 就可以删除了
因为一个监听器同时是 passive 和非 passive(以及同时是 once 和非 once)是说不通的,如果你添加了多个,那么后添加的会忽略

removeEventListener(“foo”, listener, {capture: true}) // {capture: true} 必须加,当然 {capture: true} 换成 true 也可以

原生 js abort() 方法

let A = $.ajax({})
A.abort()

Axios 提供了一个 CancelToken 的函数,这是一个构造函数,该函数的作用就是用来取消接口请求的

methods: {
getMsg () {
let CancelToken = axios.CancelToken
let that = this
axios.get('', {
cancelToken: new CancelToken(function executor(c) {
that.cancel = c
console.log(c)
// 这个参数 c 就是 CancelToken 构造函数里面自带的取消请求的函数,这里把该函数当参数用
})
params: {}
}).then(res => {
this.items = res.data
}).catch(err => {
console.log(err)
})
},
cancelGetMsg () {
this.cancel()
}
}

1. ios 移动端页面对点击事件有 300ms 延时

使用 fastclick 库 https://github.com/ftlabs/fastclick

使用 FastClick 的时候,在需要使用的层上,实例化它。我们使用 document.body 是因为希望所有的按钮和链接都获得快速点击

import FastClick from 'fastclick'
FastClick.attach(document.body)

2. ios 滚动卡顿

div {
-webkit-overflow-scrolling: touch; /* 当手指从触摸屏上移开,会保持一段时间的滚动 */
/* -webkit-overflow-scrolling: auto; */ /* 当手指从触摸屏上移开,滚动会立即停止 */
}

3. ios 1px border 变宽

以 dpr = 2 为例:
你拿到一张标准的基于 iphone6 的设计稿(750px)
你看到它设计的一个 border 宽度是 1px
你兴致勃勃地写下了 border: 1px solid #000;
然而 iphone6 实际渲染像素是 375px,那么设计需要 border 的其实是 border: 0.5px solid #000;
然后你的是 1px
不是 1px 变粗了,只是实际只是需要 0.5px 而已

<meta name="viewport" content="width=device-width"> 意思是将物理设备的宽度设置给当前浏览器

在使用 table 标签设置 border: 1px 并使用 border-collapse: collapse; 合并边框后,发现 td 之间的边框宽度并不是 1px,而是比 1px 宽,大概为 1.5px

4. webapp 软键盘弹起时问题

其他参考链接 https://segmentfault.com/a/1190000010693229
https://github.com/ioing/IOING

页面放大:

<meta name="viewport" content="user-scalable=no" />

输入框被遮挡,看不见输入的内容: document.activeElement.scrollIntoView()

页面自动上移,但收回软键盘时页面没有恢复原样少了一截

fixed 定位效果失效: ios 弹出软键盘的时候, webview 的高度没有变化导致超出屏幕范围,并且不会触发 resize 事件

scrollIntoView 与 scrollIntoViewIfNeeded

Element.scrollIntoView(option) 方法让当前的元素滚动到浏览器窗口的可视区域内
option 如果为 true,元素的顶端将和其所在滚动区的可视区域的顶端对齐, 默认
option 如果为 false,元素的底端将和其所在滚动区的可视区域的底端对齐

element.scrollIntoViewIfNeeded() 用来将不在浏览器窗口的可见区域内的元素滚动到浏览器窗口的可见区域。 如果该元素已经在浏览器窗口的可见区域内,则不会发生滚动

var scrollHeight = document.documentElement.scrollTop || document.body.scrollTop || 0
var clientHeight = document.documentElement.clientHeight || document.body.clientHeight
var innerHeight = window.innerHeight
// 键盘弹起时 scrollHeight innerHeight 发生变化
<input @focus="input(1)" @blur="input(2)" />
input (num) {
var u = navigator.userAgent
if (u.indexOf('Android') > -1 || u.indexOf('Linux') > -1) {
// 安卓手机通过 resize 事件监听键盘事件,因为部分手机手动关闭键盘时并不会失焦
} else if (u.indexOf('iPhone') > -1) {
// 苹果手机
if (num === 1) {
// 键盘弹起
document.activeElement.scrollIntoView()
} else {
// 键盘隐藏
var scrollHeight = document.documentElement.scrollTop || document.body.scrollTop || 0
// window.scrollTo(0, Math.max(scrollHeight - 1, 0))
window.scrollTo(0, 0)
}
}
}

附:安卓手机监听 resize

data () {
return {
originalHeight: document.documentElement.clientHeight || document.body.clientHeight,
resizeHeight: document.documentElement.clientHeight || document.body.clientHeight
}
},
watch: {
resizeHeight (val) {
var u = navigator.userAgent
if (u.indexOf('Android') > -1 || u.indexOf('Linux') > -1) {
// var detail = document.querySelector('.detail')
if (this.resizeHeight - 0 < this.originalHeight - 0) {
// detail.style.paddingBottom = '260px'
document.activeElement.scrollIntoView({ behavior: 'auto', block: 'start' })
} else {
// detail.style.paddingBottom = '0'
}
}
}
},
mounted () {
const that = this
window.onresize = () => {
return (() => {
window.resizeHeight = document.documentElement.clientHeight || document.body.clientHeight
that.resizeHeight = window.resizeHeight
})()
}
}

5. 手机端页面文件上传兼容性问题

6. 移动端和 PC 端中的 hover 处理 移动端点击时会有 pc 端 hover 效果

百度一下给出的方式是注册 touchstart 事件

document.body.addEventListener('touchstart', function() {})

但经过测试并没有解决该问题

7. 移动端 touch 时,会触发 pc 端的 mouseenter mouseleave 事件

在事件中通过判断屏幕宽度解决

8. ios a 链接 input type=”file” 等在点击时会出现灰色(touch 高亮)

-webkit-tap-highlight-color: transparent;

9. 禁用浏览器自动调整字体大小

移动端浏览器切换橫向模式时会调整字体大小(字体变大),解决方式:

html {
-webkit-text-size-adjust: none; /* 或 100% */
}

谷歌浏览器已不支持这个属性了,不能通过该方式实现小于 12px 的字体,可使用缩放(transform:scale(0.8))来实现小于 12px 的字体

10. appearance 属性

normal|icon|window|button|menu|field
所有主流浏览器都不支持 appearance 属性

-webkit-appearance: none; 去除默认样式,使 ios 端和安卓端显示效果一样,但有一个问题,input 的 checkbox 和 radio 类型在安卓端可能无法正常显示

11. 禁止长按

在 iOS 上,当你触摸并按住触摸的目标,比如长按一个链接,浏览器将显示链接有关的系统默认菜单,
长按图像弹出选项存储或者拷贝图像,长按文字弹出选择文字菜单

可通过如下方式禁止这些行为

禁止长按图片保存

img {
-webkit-touch-callout: none;
pointer-events: none; // 像微信浏览器还是无法禁止,加上这行样式即可
}

禁用长按复制

user-select: none;

禁止长按呼出菜单

div {
-webkit-touch-callout: none;
}

12. 点击穿透

假如页面上有两个元素 A 和 B。B 元素在 A 元素之上。我们在 B 元素的 touchstart 事件上注册了一个回调函数,该回调函数的作用是隐藏 B 元素。我们发现,当我们点击 B 元素,B 元素被隐藏了,随后,A 元素触发了 click 事件。
这是因为在移动端浏览器,事件执行的顺序是 touchstart > touchend > click。而 click 事件有 300ms 的延迟,当 touchstart 事件把 B 元素隐藏之后,隔了 300ms,浏览器触发了 click 事件,但是此时 B 元素不见了,所以该事件被派发到了 A 元素身上。如果 A 元素是一个链接,那此时页面就会意外地跳转。
跨页面点击穿透问题 点击页内按钮跳转至新页,然后发现新页面中对应位置元素的 click 事件被触发了

13. 移动端 video 播放时不弹出页面层

<video x5-playsinline="" playsinline="" webkit-playsinline=""></video>

14. vue 移动端监听 scroll

mounted () {
document.querySelector('.list').addEventListener('scroll', () => {
this.scroll = document.querySelector('.list').scrollTop
})
}

15. vue 移动端列表保存滚动位置

beforeRouteEnter (to, from, next) {
next((vm) => {
// console.log(vm.$route.meta.scrollTop)
if (vm.$route.meta.scrollTop) {
document.querySelector('.list').scrollTop = vm.$route.meta.scrollTop
}
})
},

beforeRouteLeave (to, from, next) {
if (to.name === 'invite') {
this.$store.commit('removeIncludeComponent', 'staff')
// next()
}
if (to.name === 'staffDetail') {
let top = document.querySelector('.list').scrollTop
console.log(top)
this.$route.meta.scrollTop = top
}
next()
}

16. 移动端去除 type 为 number 的箭头

input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none !important;
margin: 0;
}

17. 设置状态栏的背景颜色(IOS)

设置状态栏的背景颜色,只有在”apple-mobile-web-app-capable” content=”yes”时生效

<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />

content 参数:

default :状态栏背景是白色。
black :状态栏背景是黑色。
black-translucent :状态栏背景是半透明。 如果设置为 default 或 black ,网页内容从状态栏底部开始。
如果设置为 black-translucent ,网页内容充满整个屏幕,顶部会被状态栏遮挡。

18. 弹出数字键盘

<!-- 有"#" "*"符号输入 -->
<input type="tel" />

<!-- 纯数字 -->
<input pattern="\d*" />

打开原生应用

某些浏览器会禁用此协议,比如微信内部浏览器(除非开了白名单)

<a href="weixin://">打开微信</a>
<a href="alipays://">打开支付宝</a>
<a href="alipays://platformapi/startapp?saId=10000007">打开支付宝的扫一扫功能</a>
<a href="alipays://platformapi/startapp?appId=60000002">打开支付宝的蚂蚁森林</a>

解决 IOS下 active 伪类失效

给 body 注册一个空事件即可

<body ontouchstart></body>

最简单的 rem 实现

@media (min-width: 640px) {
html {
font-size: calc(640px / 3.75);
}
}
@media (min-width: 320px) and (max-width: 640px) {
html {
font-size: calc(100vw / 3.75);
}
}

better-scroll 解决移动端滚动问题

https://github.com/ustbhuangyi/better-scroll/

iphone X 适配 - 安全区域(safe area)

参考:https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/adaptivity-and-layout/

在 iOS 11 中采用了 viewport-fit 的 meta 标签作为适配方案

viewport-fit 取值

auto 默认:页面内容显示在 safe area 内
cover 页面内容充满屏幕,可以通过添加边距保证网页主要内容处于 safe area 中不被裁剪

iOS 11 的 webview 引入了 constantenv 来处理 viewport-fit=cover 属性,以及一组四个预定义的常量:safe-area-inset-left, safe-area-inset-right, safe-area-inset-topsafe-area-inset-bottom,分别表示 safe area 和可视窗口 viewport 顶部,右边,左边,底部的间距,可以用于设置 margin 和 padding 或者绝对定位时 left 和 top,这四个常量只有在 viewport-fit=cover 时有效

建议使用 viewport-fit=cover 因为会使用 auto 会造成屏幕四周出现白边

<meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
/*  top 为 0 的 fixed 定位的 heade */
header {
position: fixed;
top: 0;
/* ... */
/* Status bar height on iOS 10 */
padding-top: 20px;
/* Status bar height on iOS 11.0 */
padding-top: constant(safe-area-inset-top);
/* Status bar height on iOS 11+ */
padding-top: env(safe-area-inset-top);
}
body {
padding-top: constant(safe-area-inset-top); // 为导航栏+状态栏的高度 88px
padding-left: constant(safe-area-inset-left); // 如果未竖屏时为0
padding-right: constant(safe-area-inset-right); // 如果未竖屏时为0
padding-bottom: constant(safe-area-inset-bottom); // 为底下圆弧的高度 34px
}

类型识别

获取数据类型,返回结果为 Number、String、Object、Array 等

// 返回数据类型
function getRawType(value) {
return Object.prototype.toString.call(value).slice(8, -1)
}

// 正则 => RegExp
// 时间对象 => Date
// 字符串 => String
// 对象 => Object
// 数组 => Array

判断变量是不是字符串类型

Object.prototype.toString.call('str') // '[object String]'
typeof 'str' // 'string'

判断变量是不是引用类型

例如: arrays, functions, objects, regexes, new Number(0),以及 new String(‘’)

function isObject(value) {
let type = typeof value
return value != null && (type == 'object' || type == 'function')
}

判断变量是不是 Object 类型的数据

function isPlainObject(value) {
return Object.prototype.toString.call(value) === '[object Object]'
}

判断变量是不是数组类型

function isArray(arr) {
return Object.prototype.toString.call(arr) === '[object Array]'
}

function isArray(arr) {
return Array.isArray(arr)
}

将 isArray 挂载到 Array 上

Array.isArray = Array.isArray || isArray

格式转换

数字格式化:小于 10 的数值前面加上 0

/**
* @param {number} num 要格式化的数值
* @return {string} 把小于10的数值前面加上0
*/
function prefix_zero(num) {
return num >= 10 ? num : '0' + num
}

千分位格式化数字

(1234567 => 1,234,567.00)

/**
* @param {number} price 价格
* @returns {string} 1234567 => 1,234,567.00
*/
function formatPrice(price) {
if (typeof price !== 'number') return price
return String(Number(price).toFixed(2)).replace(/\B(?=(\d{3})+(?!\d))/g, ',')
}

// \b 匹配单词边界
// \B 匹配非单词边界

其他方式

let a = 123456789 // a 为number类型
a.toLocaleString('en-US') // '123,456,789'

let b = 123456789 // b 可为number类型或string类型
Intl.NumberFormat().format(b) //'123,456,789'

手机号格式化:隐藏中间四位数字

/**
* @param {string} mobile 手机号
* @returns {string}
*/
function formatMobile(mobile) {
mobile = String(mobile)
if (!/\d{11}/.test(mobile)) {
return mobile
}
return mobile.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
}

手机号格式化:3-4-4 分割

watch: {
phoneNum(newValue, oldValue) {
this.phoneNum = newValue.length > oldValue.length ? newValue.replace(/\s/g, '').replace(/(\d{3})(\d{0,4})(\d{0,4})/, '$1 $2 $3') : this.phoneNum.trim()
}
}

进制转换

parseInt(str, radix) // 任意进制转换为 10 进制整数值

Number.toString(radix) //返回表示该数字的指定进制形式的字符串

检测平台(设备)类型

isWechat = /micromessenger/i.test(navigator.userAgent)
isWeibo = /weibo/i.test(navigator.userAgent)
isQQ = /qq/i.test(navigator.userAgent)
isIOS = /(iphone|ipod|ipad|ios)/i.test(navigator.userAgent)
isAndroid = /android/i.test(navigator.userAgent)

数组顺序上移下移

// 对象数组顺序上移下移
// arr: 目标数组

// 上移
arr[index] = arr.splice(index - 1, 1, arr[index])[0]

// 下移
arr[index] = arr.splice(index + 1, 1, arr[index])[0]

快速创建 a 标签

let a = '超链接'.link('https://wqdy.top')
console.log(a) // <a href="https://wqdy.top">超链接</a>

正则进阶:

捕获括号:

匹配 'wqdy' 并且记住匹配项
/(wqdy)/

非捕获括号:

匹配 'wqdy' 但是不记住匹配项
/(?:wqdy)/

先行断言:

匹配'wqdy'仅仅当'wqdy'后面跟着'top'
/wqdy(?=top)/

后行断言:

匹配'top'仅仅当'top'前面是'wqdy'
/(?<=wqdy)top/

正向否定查找:

匹配'wqdy'仅仅当'wqdy'后面不跟着'gkd'
/wqdy(?!gkd)/

判断是否有滚动条

function isScroll() {
return window.innerWidth - $(document).width() !== 0
}

mixin 混合

可以在 mixin 中使用类选择器和 id 选择器

.bgc 定义了一个属性集,在任何需要使用 .bgc 属性集的选择器中,只需像下面这样调用:(小括号是可选的)

.bgc {
background-color: #ccc;
}
div {
color: #f00;
.bgc();
}

编译后的 CSS 代码为:

.bgc {
background-color: #ccc;
}

div {
color: #f00;
background-color: #ccc;
}

总结:mixin 其实就是一种嵌套,简单的讲,mixin 就是规则级别的复用

mixin 的定义也会被原封不动的输出到编译生成的 CSS 代码中

如果希望编译生成的 CSS 代码中不包含 mixin 的定义,在定义 mixin 时,只需在 class、id 的后面添加一对小括号即可。如:

.bgc() {
background-color: #ccc;
}
div {
.bgc;
}

编译后的 CSS 代码为:

div {
background-color: #ccc;
}

mixin 可以包含选择器

.hover() {
&:hover {
background-color: #ccc;
}
}
div {
.hover;
}

编译后的 CSS 代码为:

div:hover {
background-color: #ccc;
}

命令空间 Namespaces

如果想要在一个更复杂的选择器中混合属性,可以堆叠多个 id 或类

可以将 mixin 置于 id 选择器之下,这样可以确保它不会和另一个库冲突

#bgc {
.inner() {
color: red;
}
}

div {
#bgc.inner;
}

!important 关键字

在 mixin 后使用 !important 关键字,将会标记调用所有继承的属性为!important

.bgc {
background-color: #ccc;
}

div {
.bgc !important;
}

// 编译后 css 为
div {
background-color: #ccc !important;
}

带参数的 Mixin

mixin 还可以接受参数,这些参数在混合时传递给选择器块

从上面的代码可以看出:mixin 其实就是一种嵌套,简单的讲,mixin 就是规则级别的复用。除了类选择器外,你也可以使用 id 选择器来定义 mixin。

高阶函数

高阶函数定义:将函数作为参数或者返回值是函数的函数
常见的 sort、reduce 等函数就是高阶函数

function add(a) {
return function(b) {
return a + b
}
}

// es6写法
let add = (a) => (b) => a + b

var sum = add(1)(2) // 3

柯里化

wiki 的柯里化定义: 把接受多个参数的函数变换成接受一个单一参数的函数,并且返回(接受余下的参数而且返回结果的)新函数的技术

柯里化后,将第一个参数变量存在函数里面了(闭包),然后本来需要 n 个参数的函数变成只需要剩下的(n - 1 个)参数就可以调用

let add = (a) => (b) => a + b
let add1 = add(1)
add1(2) // 1 + 2 = 3

add 函数按照定义可以理解成只柯里化了一次,n 个连续箭头组成的函数实际上就是柯里化了 n - 1 次
前 n - 1 次调用,其实是提前将参数传递进去,并没有调用最内层函数体,最后一次调用才会调用最内层函数体,并返回最内层函数体的返回值

所以多个连续箭头函数就是多次柯里化的 es6 写法

应用:

函数懒执行
函数式编程

柯里化函数使用场景:

减少重复传递不变的参数

function discount(price, discount) {
return price * discount
}

// 每次都要重复传入 discount 参数,可以将这个函数柯里化
function discount(discount) {
return (price) => {
return price * discount
}
}
const tenPercentDiscount = discount(0.9)
const twentyPercentDiscount = discount(0.8)

// 现在每次计算价格只需要:
tenPercentDiscount(500) // 500 * 0.9
twentyPercentDiscount(1000) // 1000 * 0.8

柯里化实现

function curry(func) {
return function curried(...args) {
if (args.length >= func.length) {
return func.apply(this, args)
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2))
}
}
}
}

function sum(a, b, c) {
return a + b + c
}

let curriedSum = curry(sum)
console.log(curriedSum(1, 2, 3)) // 6
console.log(curriedSum(1)(2, 3)) // 6

偏函数

快速删除 node_modules 文件夹

系统命令

# cmd
# /q 直接删除,不需要二次确认
# /s 允许删除非空目录
rd /q/s node_modules

# powershell
rmdir -r -Force node_modules
# 或
rm -r -Force node_modules

使用 npm 包

npm i rimraf -g
rimraf node_modules

npm i -g dlf
dlf node_modules

一次执行多条命令

# cmd 使用 && 连接多个命令
cd vue && npm i
# powershell 使用 | 连接多条命令
cd vue | npm i

删除一个文件夹内字节小于 10kb 的文件

# 输出所有大小小于10k的文件
# find ./ -size -10k > NoNeedSite.txt
find ./ -size -10k -exec rm {} \

Window.history 是一个只读属性,提供了操作浏览器会话历史(浏览器地址栏中访问的页面,以及当前页面中通过框架加载的页面)的接口。HTML5 引入了 history.pushState() 和 history.replaceState() 方法,它们分别可以添加和修改历史记录条目。这些方法通常与 window.onpopstate 配合使用。

参考

https://developer.mozilla.org/zh-CN/docs/Web/API/History_API

https://developer.mozilla.org/zh-CN/docs/Web/API/Window/history

在 history 中跳转

window.history.back() // 向后跳转 相当于点击浏览器回退按钮
window.history.forward() // 向前跳转 相当于点击了前进按钮
window.history.go(-1) // 跳转 历史中的某一特定页面(go(-1) 等同于调用 back())

可以通过查看长度属性的值来确定的历史堆栈中页面的数量

window.history.length
history.pushState(stateObject, title, url)

状态对象(stateObject)–stateObject 是一个 JavaScript 对象,通过 pushState 方法可以将 stateObject 内容传递到新页面中。

标题(title)–几乎没有浏览器支持该参数,但是传一个空字符串会比较安全。

地址(url)–新的历史记录条目的地址(可选,不指定的话则为文档当前 URL);浏览器在调用 pushState()方法后不会加载该地址;传入的 URL 与当前 URL 应该是同源的,否则,pushState()会抛出异常。

history.pushState()主要是在不刷新浏览器的情况下,创建新的浏览记录并插入浏览记录队列中

假设在 http://mozilla.org/foo.html 中执行了以下 JavaScript 代码:

let stateObj = {
foo: 'bar'
}
history.pushState(stateObj, 'page 2', 'bar.html')

这将使浏览器地址栏显示为 http://mozilla.org/bar.html,但并不会导致浏览器加载 bar.html ,甚至不会检查 bar.html 是否存在

history.replaceState() 的使用与 history.pushState() 非常相似,区别在于 replaceState() 是修改了当前的历史记录项而不是新建一个

Apache 安装

centos

# yum install httpd  (centos之下,Apache的名字叫httpd,和Apache的主程序 httpd.exe 同名)

打开并测试 Apache

  • 先确保,云服务器的 80 端口,是允许外网访问的。

  • 开启 Apache 服务

service httpd start
# 查看状态
service httpd status
  • 测试 Apache 是否正常运行

浏览器输入: 外网 IP:80,如果能正常显示 Apache 的内置主页,则说明 Apache 服务已正常开启。

修改 Apache 的配置文件

主配置文件 /etc/httpd/conf/httpd.conf

修改如下键值兼容 php

键:DirectoryIndex
值:index.html index.php

默认站点主目录:/var/www/html/

https://www.cnblogs.com/smbin/p/6946210.html

安装证书

  1. 安装 ssl 模块
# yum install mod_ssl -y

Ps:安装完成后,会在/etc/httpd/conf.d/下生成一个 ssl.conf 配置文件。

建一个目录用来放 ssl 证书文件

# mkdir /etc/httpd/ssl/

编辑 ssl 配置文件

# vim /etc/httpd/conf.d/ssl.conf

修改以下几行,去掉前面的“#”注释;

<VirtualHost>
#网页文件路径
DocumentRoot "/var/www/html"
#改为自己的域名
ServerName cuilongjin.top:80
#启用SSL功能
SSLEngine on
#填写证书文件路径
SSLCertificateFile /etc/httpd/ssl/cert-1541656252121_cuilongjin.top.key
#填写私钥文件路径
SSLCertificateKeyFile /etc/httpd/ssl/cert-1541656252121_cuilongjin.top.key
#填写证书链文件路径
SSLCertificateChainFile /etc/httpd/ssl/cert-1541656252121_cuilongjin.top_chain.crt
</VirtualHost>

重启服务器

# service httpd restart

Nginx 的安装与配置

CentOS 下安装:

通过安装包安装

# 安装所需环境
yum install gcc-c++
yum install -y pcre pcre-devel
yum install -y zlib zlib-devel
yum install -y openssl openssl-devel

# 官网下载 nginx https://nginx.org/
yum install wget
wget -c https://nginx.org/download/nginx-1.17.4.tar.gz
# 解压
tar -zxvf nginx-1.17.4.tar.gz
cd nginx-1.17.1

# 配置
./configure

# 编译安装
make
make install

# 查找安装路径:
whereis nginx

# 启动、停止 重启 nginx
cd /usr/local/nginx/sbin/
./nginx # 启动
./nginx -s stop # 此方式相当于先查出nginx进程id再使用kill命令强制杀掉进程
./nginx -s quit # 此方式停止步骤是待nginx进程处理任务完毕进行停止
./nginx -s quit && ./nginx # 重启 nginx

# 重新加载配置文件
# 配置文件 nginx.conf 修改后,要想让配置生效需要重启 nginx,使用 -s reload 不用先停止 nginx 再启动即可将配置信息在 nginx 中生效,如下:
./nginx -s reload

# 查询 nginx 进程
ps aux|grep nginx

# 开机自启动
在 rc.local 增加启动代码
vi /etc/rc.local
# 增加一行 /usr/local/nginx/sbin/nginx
# 设置执行权限
chmod 755 rc.local

# 添加 nginx 为系统服务

centos 下,yum 源不提供 nginx 的安装,可以通过切换 yum 源的方法获取安装

yum -y install nginx

主站点目录/usr/share/nginx/html

配置 Nginx:

Nginx 的配置文件默认位置为:/etc/nginx/nginx.conf

server {
listen 80; #监听80端口,接收http请求
server_name localhost; #就是网站地址
root /usr/share/nginx/html; # 准备存放代码工程的路径
#路由到网站根目录www.example.com时候的处理
location / {
index index.php index.html index.htm;
}

#当请求网站下php文件的时候,反向代理到php-fpm
location ~ \.php$ {
include fastcgi.conf; #加载nginx的fastcgi模块
fastcgi_intercept_errors on;
fastcgi_pass 127.0.0.1:9000; #nginx fastcgi进程监听的IP地址和端口
}
}

自定义 Nginx 站点配置文件存放目录

/etc/nginx/conf.d/

默认站点目录/usr/share/nginx/html

安装 php

yum install php php-fpm

配置 php.ini

/etc/php.ini

cgi.fix_pathinfo=1

配置 php-fpm

/etc/php-fpm.d/www.conf

user = nginx

group = nginx

chkconfig php-fpm on #设置 php-fpm 自启动

service nginx restart #重新启动 nginx

service php-fpm start #启动 php-fpm

sudo iptables -I INPUT -p tcp -m tcp –dport 80 -j ACCEPT

sudo iptables -I INPUT -p tcp -m tcp –dport 443 -j ACCEPT

iptables -L -n

/usr/sbin/nginx

查询 nginx 进程

ps -ef | grep nginx

nginx 配置

#
# HTTPS server configuration
#

server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl;
server_name _;
root /usr/share/nginx/html;

ssl_certificate ssl/cuilongjin.top.pem;
ssl_certificate_key ssl/cuilongjin.top.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;

location / {
}
location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}

error_page 404 /404.html;
location = /40x.html {
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
#
# The default server
#

server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;

# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;

location / {
}
location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}

error_page 404 /404.html;
location = /40x.html {
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}

ubuntu 下安装

安装 nginx

sudo apt-get install nginx

Ubuntu 安装之后的文件结构大致为:

  • 所有的配置文件都在/etc/nginx 下,并且每个虚拟主机已经安排在了/etc/nginx/sites-available 下
  • 程序文件在/usr/sbin/nginx
  • 日志文件在/var/log/nginx
  • 并已经在/etc/init.d/下创建了启动脚本 nginx
  • 服务器配置文件在/etc/nginx/sites-available/
  • 默认主站点目录 /var/www/html,(有的可能在/var/www), 请参考/etc/nginx/sites-available 里的配置

安装 php

apt-get install php

配置 php.ini /etc/php/7.2/cli/

cgi.fix_pathinfo=1

配置 php-fpm

启动 nginx

/etc/init.d/nginx restart
/etc/init.d/nginx stop
/etc/init.d/nginx start

删除 nginx

sudo apt-get --purge remove nginx
# –-purge 包括配置文件

arch 下安装 nginx

pacman -S nginx

启动 Nginx 服务,运行以下命令:

# systemctl start nginx

要 Nginx 服务开机时启动,运行以下命令:

# systemctl enable nginx

默认页面是:

/usr/share/nginx/html/index.html

配置

你可以修改在 /etc/nginx/ 目录中的文件来更改配置 ./etc/nginx/nginx.conf 是主配置文件