原生JS实现AJAX

快速理解AJAX

1. 创建一个XMLHttpRequest实例
2. 通过open方法,填入请求类型,地址,同步还是异步
3. 设置请求头信息,比如内容格式为json
4. 通过send方法发送请求数据
5. 通过onreadstatechange方法获取响应数据,包括状态码和data

var xhr = new XMLHttpRequest(); //ajax实例化
xhr.open(ajaxData.type, ajaxData.url, ajaxData.async); // post,xxx.com/api,sync
xhr.setRequestHeader("Content-Type", ajaxData.contentType); // json
xhr.send(convertData(ajaxData.data));
xhr.onreadystatechange = function () {
    if (xhr.readyState == 4) {
        if (xhr.status == 200) {
            ajaxData.success(xhr.response)
        } else {
            ajaxData.error()
        }
    }
}

快速理解移动端REM适配方案

我写这篇文章的时间是2020年,为什么要写上时间,因为我们知道前端技术更新的很快,可能过几年这篇文章里面介绍的技术就淘汰了。
目前主流的移动端适配方案有2种:媒体查询和rem。
不过媒体查询的方式更适合做响应式布局,所以从2017至今,移动端的设配方案就是使用rem。通常VUE项目中会安装flexible和postcss-px2rem两个插件来自动计算。
我相信有的人只是会用这2个插件,但是还没有认真了解过其原理。下面我就用最简短的说明来介绍一下其中的原理,帮助您快速理解。

首先我们知道rem是相对于html根元素的单位,默认情况html的font-size是16px,所以 1rem = 16px;

那么得出来,pc端设计稿的话如果30px换成rem的公式就是 30/16=1.8rem(目标单位/根字体单位);

为了适配不同的屏幕大小,在不同大小的屏幕上面,字体也要随着改变,所以我们不能只用16px,而需要动态的设定根字体的单位;

例如现在移动端的设计稿普遍使用ihpone6作为标准,也就是宽度为375,为了计算方便,首先用js写一个函数把html的字体单位设为375/10,也就是37.5,像这样:

let htmlDom = document.getElementsByTagName('html')[0]
let setFontSize = function () {
let htmlWidth = document.documentElement.clientWidth //(viewport宽度)
htmlDom.style.fontSize = htmlWidth / 10 + 'px' //iphone6=37.5
}
setFontSize()

具备了动态改变根字体的能力,只要给文字或者容器宽高的值设定rem就可以实现适配了;

那么根据设计稿的要求我们具体应该设置多少rem呢?这里有个公式,也非常简单,就是设计稿标注的像素值除以根字体的值就得出了rem的值;

基于iPhone6的设计稿某个文字标注30px。那么它的rem值 就是30/37.5 = 0.8rem。 所以在css中的字体大小就要写.8rem。

看到这里,大家可以尝试一下在chrome的调试看看,不过要注意一点就是,iphone6的屏幕是2x屏,所以在算rem的时候需要把30px看做30/2也就是15px,然后再用15/37.5。现在业界已经默认都使用Iphone6最为移动端UI的标准了。

但是每次写rem之前都得自己用计算器除一次也太麻烦了,所以我们可以写一个scss的函数来帮我们这样就方便很多,例如像下面这样使用。

@function px2rem($px) {
$rem: 37.5px; //iphone 6
@return ($px/$rem) + rem;
}
.box {
font-size: px2rem(15px);
}

为了方便编译scss文件,可以使用webpack来打包编译或则其他方式。

最后我写了一个小极简的demo,大家可以下载到本地运行一下加深理解。

https://github.com/yjxf8285/rem-demo

解决npm 全局安装某些包时报权限相关的错误

今天在Mac系统下全局安装node-sass总是报权限方面的错误。

错误信息:gyp ERR! stack Error: EACCES: permission denied, mkdir ‘/usr/local/lib/node_modules/node-sass/.node-gyp’

字面上大概意思就是没有操作这个目录的权限,然后我尝试手动把/usr/local/lib/node_modules的目录权限改成777也不行。

最后经过网上各种搜索解决办法,找到了根本原因是:

npm 出于安全考虑不支持以 root 用户运行,即使你用 root 用户身份运行了,npm 会自动转成一个叫 nobody 的用户来运行,而这个用户几乎没有任何权限。这样的话如果你脚本里有一些需要权限的操作,比如写文件(尤其是写 /root/.node-gyp),就会崩掉了。
为了避免这种情况,要么按照 npm 的规矩来,专门建一个用于运行 npm 的高权限用户;要么加 –unsafe-perm 参数,这样就不会切换到 nobody 上,运行时是哪个用户就是哪个用户,即使是 root。

知道了问题的原因就可以正确的解决了,所以把安装命令后面加上这个–unsafe-perm 参数即可。
完整的全局安装node-sass命令为:
sudo npm i -g node-sass --unsafe-perm

js 快速排序

问题:一个值未知的数组,如何快速根据值的大小进行排序。
思路:
先找到数组的中位数pivot作为参照物
遍历数组中的每一项与其比较,然后小的放到一个Left的空数组里面,比它大的放点right的空数组里面
再递归左边的数组和右边的组数,最后把2个数组和中位数连接到一个数组里面去

let arr = [11, 82, 4, 44, 20]
var quickSort = function (arr) {
    if (arr.length <= 1) { return arr }
    var pivotIndex = Math.floor(arr.length / 2)
    var pivot = arr.splice(pivotIndex, 1)[0]
    var left = []
    var right = []
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] < pivot) {
            left.push(arr[i])
        } else {
            right.push(arr[i])
        }
    }
    return quickSort(left).concat([pivot], quickSort(right))
}
console.info(quickSort(arr))

JS事件循环机制

eventloop重点:
同步任务先执行,然后是异步任务
异步任务又分宏和微
宏任务 setTimeout 最低
微任务 promise 优先级高

console.log(1); // 同步任务

(function(){ // 同步任务
console.log(2)
})();

setTimeout(function () { // 宏任务
console.log(3)
});

new Promise(function (a, b) { // 微任务
console.log(4);
a()
}).then(function () {
console.log(6)
});

console.log(7) // 同步任务

//执行顺序为 1 2 4 7 6 3

 

 

清浮动技巧

了解为什么页面元素会浮动之前先明白一个概念—— 块级格式化上下文:BFC(block formatting contexts) 默认是关闭状态
BFC的特性
* 块级格式化上下文会阻止外边距叠加
* 块级格式化上下文不会重叠浮动元素
* 块级格式化上下文通常可以包含浮动
CSS3里面对触发BFC这个规范做了改动,称之为:flow root

float
overflow
display
position(absolute,fixed)

表单元素
所有css3清浮动的几种方式为

overflow: hidden;
overflow: auto;
float: left;
display:inline-block;
position: fixed;

 

 

力扣算法第1题:两数之和

给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。
你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。
例如:
给定 nums = [2, 7, 11, 15], target = 9 。 ·8
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

解题思路:
1. 把nums想象成相亲者
2. 把target想象成匹配条件
3. 用字典建立一个婚姻介绍所,存储相亲者的数字和下标

解题步骤:
新建一个字典作为婚姻介绍所
遍历nums里的值,有合适的就牵手成功,没有就先登记,字典里面Key就是nums里的值,value就是下标。

var twoSum = function (nums, target) {
    let map = new Map() // 婚姻介绍所
    for (let i = 0; i < nums.length; i++) {
        const n = nums[i] //自己
        const n2 = target - n //对象
        if (map.has(n2)) { //是否有合适的对象
            return [map.get(n2), i] //有就返回对象的下标和自己的下标
        } else {
            map.set(n, i) // 没有合适的对象就把自己登记到介绍所
        }
    }
}
let res = twoSum([2, 7, 11, 15], 9)

 

 

js 多重条件过滤

假设一组JSON数据中,需要你根据某一个值去筛选出来当前值所在的对象,最基本的做法:
遍历数组然后判断这个值是否等于你要查找的那个值,如果等于就返回当前遍历的节点对象。

那么问题来了,如果是5个条件呢,你要嵌套遍历5次吗?那如果是10个条件呢?嵌套遍历比较笨,而且性能也不好,所以使用es6的filter方法更好。

思路是先定义个空对象来保存筛选条件,然后再遍历数组,然后通过比较数组的数组项和条件对象的健值,找到后返回。

// 多重过滤
function multiFilter(array, filters) {
    const filterKeys = Object.keys(filters) // 先把筛选条件保存下来
    // 主要是用filter方法来过滤
    const res = array.filter((item) => {
        const isHave = filterKeys.every((key) => {
            let targetValue = filters[key] // 条件的值
            let originValue = item[key] // 元数据的值
            if (!targetValue) { // 如果条件为空就返回对象
                return true
            } else {
                if (originValue === targetValue) { // 否则返回条件相等的的对象
                    return true
                } else {
                    return false
                }
            }
        })
        return isHave
    })
    return res
}

 

 

CSS布局垂直居中(已知高度和未知高度)

已知高度使用用传统的绝对定位-margin高度的一半方法,这里不多介绍。
未知高度常用的三种方法:
1.表格 cell-table方法

.parent1{
display: table;
background-color: #FD0C70;
}
.parent1 .child{
display: table-cell;
vertical-align: middle;
}

2. 决定定位 transform:translate(-50%;-50%)

.parent2{
position: relative;
}
.parent2 .child{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}

3.弹性布局 flex

.parent3{
display: flex;
justify-content: center;
align-items: center;
}

 

 

实现深拷贝函数

ES6的Object.assign()函数其实只能拷贝一层,所以需要手写一个深拷贝函数。
有个小技巧判断一个对象是否为数组,instanceof是否等于Array。
主要思路就是使用in方法遍历对象的每个key和值,用递归的方式拷贝到新的对象里面去

function deepClone(obj) {
    let newObj = obj instanceof Array ? [] : {}
    if (obj && typeof obj === "object") {
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                newObj[key] = (obj && typeof obj[key] === 'object') ? deepClone(obj[key]) : obj[key];
            }
        }
    }
    return newObj
}