分类 原创文章 下的文章

const express = require("express");
const { createProxyMiddleware, responseInterceptor } = require("http-proxy-middleware");

const port = 8080;
const app = express();
app.use(
    createProxyMiddleware("/api/", {
        target: "http://example.com/api/",
        changeOrigin: true,
        pathRewrite: {
            "^/api": "",
        },
       selfHandleResponse: true, 
        onProxyRes: responseInterceptor(async (responseBuffer, proxyRes, req, res) => {
            res.removeHeader("Access-Control-Allow-Origin")
            res.setHeader("Access-Control-Allow-Origin", "*")
            return responseBuffer
     }),
    })
);
app.use(express.static("dist"));
app.listen(port);
console.log("Server is running at http://localhost:" + port);

验证手机号

export function checkPhone(value) {
    return /^1[0-9]{10}$/.test(value)
}

验证二代身份证号

export function checkIDCardNumber(value){
    return /(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(value)
}

对象转换查询条件

export function objectToQuery(queryParameters) {
    if (queryParameters) {
        return Object.entries(queryParameters).reduce((queryString, [key, val], index) => {
            const symbol = queryString.length === 0 ? '?' : '&'
            queryString += ['string', 'number', 'boolean'].includes(typeof val) ?
                `${symbol}${key}=${val}` : ''
            return queryString
        }, '')
    }
    return ''
}

日期格式化

export function dateFormat(fmt, date) {
    let ret
    const opt = {
        'y+': date.getFullYear().toString(), // 年
        'M+': (date.getMonth() + 1).toString(), // 月
        'd+': date.getDate().toString(), // 日
        'H+': date.getHours().toString(), // 时
        'm+': date.getMinutes().toString(), // 分
        's+': date.getSeconds().toString() // 秒
        // 有其他格式化字符需求可以继续添加,必须转化成字符串
    }
    for (let k in opt) {
        ret = new RegExp('(' + k + ')').exec(fmt)
        if (ret) {
            fmt = fmt.replace(
                ret[1],
                ret[1].length == 1
                    ? opt[k]
                    : opt[k].padStart(ret[1].length, '0')
            )
        }
    }
    return fmt
}

console.log(dateFormat('yy-MM-dd HH:mm:ss',new Date()))

深拷贝

export function deepCopy(obj) {
    let result = {}
    for (let key in obj) {
        switch (true) {
            // 处理为null的情况
            case obj[key] === null: {
                result[key] = null
                break
            }
            // 处理值是自己的情况
            case obj[key] === obj: {
                result[key] = result
                break
            }
            // 处理值是对象的情况
            case typeof obj[key] === 'object': {
                result[key] = deepCopy(obj[key])
                break
            }
            // 其他情况
            default: {
                result[key] = obj[key]
            }
        }
    }
    return result
}

防抖与节流

// 防抖
export function debounce(func, wait){
    let timeout = null
    return function(){
        // 使this指向不变并能获取到e参数
        let context = this
        let args = arguments
        if(timeout){
            clearTimeout(timeout)
        }
        timeout = setTimeout(() => {
            func.apply(context, args)
        }, wait)
    }
}
// 节流
export function throttle(func, wait) {
    let timeout
    return function() {
        let context = this
        let args = arguments
        if (! timeout) {
            timeout = setTimeout(() => {
                timeout = null
                func.apply(context, args)
            }, wait)
        }
    }
}

验证类型

export function typeOf(obj) {
    const maps = {
        '[object Boolean]': 'boolean',
        '[object Number]': 'number',
        '[object String]': 'string',
        '[object Function]': 'function',
        '[object Array]': 'array',
        '[object Date]': 'date',
        '[object RegExp]': 'regExp',
        '[object Undefined]': 'undefined',
        '[object Null]': 'null',
        '[object Object]': 'object',
        '[object Symbol]': 'symbol'
    }
    return maps[toString.call(obj)]
}

持续更新中...

需求

在某项目开发过程中,产品妹子提了一个需求,要抄支付宝账单,大概看了一下,主要是吸顶的部分不太好做。

刚开始打算用Javascript一把梭,后来想起来CSS3有一个position: sticky可以做到吸顶,直接搞定收工。

等等,让我再看看设计稿……

啊,还要修改吸顶时的样式!还是谷歌一下吧。

解决方案

最终从这里找到了一个Solution。

.myElement {
  position: sticky;
  top: -1px;
}

.is-pinned {
  color: red;
}
const el = document.querySelector(".myElement")
const observer = new IntersectionObserver( 
  ([e]) => e.target.classList.toggle("is-pinned", e.intersectionRatio < 1),
  { threshold: [1] }
);

observer.observe(el);

原理

浏览器给我们提供了一个API用来观察元素是否在可视区域内,IntersectionObserver构造函数第一个参数是当元素可见时的回调函数,它的参数所携带的intersectionRatio属性值为1即监听对象完全可见,为0即完全不可见。

构造函数第二个参数是配置项,threshold属性值数组里的1表示当何时执行回调函数(或者说是执行函数的最低可视比例,0的时候元素刚刚进入可视区域就执行,1的时候元素完全进入可视区域才会执行)。

上述的解决方案使用了一个巧妙的方式,让吸顶时的元素top: -1px。当元素进入可视区域但未滚动到吸顶位置时,它完全可视;当元素吸顶时由于顶部向上偏移了1像素实际上没有完全可视,这样就完成了样式的切换。

要注意的是:回调函数的参数和配置项的threshold属性都是数组

关于IntersectionObserver的更多内容,请移步阮一峰大佬的博客

参考了别人的脚本,稍微修改了一下,目前还没发现bug。

如有问题请评论区告诉我。

$sqlInfo = array(
    'host' => 'localhost',
    'port' => '3306',
    'username' => 'root', // 只是示例
    'password' => '1234', // 只是示例
    'database' => '',
    'charset' => 'utf8mb4'
);
function sqlBackUp($sqlInfo, $filename) {
    $link = mysqli_connect($sqlInfo['host'], $sqlInfo['username'], $sqlInfo['password'], $sqlInfo['database'], $sqlInfo['port']);
    mysqli_options($link, MYSQLI_OPT_INT_AND_FLOAT_NATIVE, 1);
    mysqli_query($link, "set names ".$sqlInfo['charset']);
    $tables = mysqli_query($link, 'SHOW TABLES FROM '.$sqlInfo['database'].'');
    $tabList = array();
    while ($row = mysqli_fetch_row($tables)) {
        $tabList[] = $row[0];
    }
    $mysql = '';
    foreach ($tabList as $val) {
        $sql = "show create table ".$val;
        $res = mysqli_query($link, $sql);
        $row = mysqli_fetch_array($res);
        $info = "DROP TABLE IF EXISTS `".$val."`;\r\n";
        $mysql .= $info.$row[1].";\r\n\r\n";
        mysqli_free_result($res);
    }
    foreach ($tabList as $val) {
        $sql = "select * from ".$val;
        $res = mysqli_query($link, $sql);
        if (mysqli_num_rows($res) < 1) {
            continue;
        }
        while ($row = mysqli_fetch_row($res)) {
            $mysql .= "INSERT INTO `".$val."` VALUES (";
            foreach ($row as $zd) {
                if (gettype($zd) == 'NULL') {
                    $mysql .= "NULL, ";
                } else if (gettype($zd) == 'string') {
                    $mysql .= "'".addslashes($zd)."', ";
                } else {
                    $mysql .= $zd.", ";
                }
            }
            $mysql = substr($mysql, 0, strlen($mysql)-2);
            $mysql .= ");\r\n";
        }
        mysqli_free_result($res);
        $mysql .= "\r\n";
    }
    mysqli_close($link);
    $fp = fopen($filename, 'w');
    fputs($fp, $mysql);
    fclose($fp);
}

不到30行代码实现谷歌的反向代理,可以放在虚拟主机搭建谷歌搜索镜像站

注意 服务器需要开启curl,index.php文件必须放在根目录,apache服务器需要新建(修改)一个内容为FallbackResource /index.php.htaccess文件,其他服务器请自己配置对应的路由。

index.php:

<?php

    /*
        Google Mirror
        Put this file to the ROOT directory, and write "FallbackResource /index.php" to the .htaccess file.
    */

    $params = $_SERVER['REQUEST_URI'];
    $response = curl('https://www.google.com'.$params);
    $header = $response['header'];
    $data = $response['data'];
    $data = str_replace('src="https://www.google.com','src="',$data);
    $contentType = [];
    preg_match("/Content-Type:([^:]+);/",$header,$contentType);
    header("Content-Type:".$contentType[1]);
    echo $data;
    
    function curl($url) {
        $ch = curl_init();
        curl_setopt($ch,CURLOPT_URL,$url);
        curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);
        curl_setopt($ch,CURLOPT_HEADER,TRUE);
        curl_setopt($ch,CURLOPT_FOLLOWLOCATION,TRUE);
        curl_setopt($ch,CURLOPT_USERAGENT,$_SERVER['HTTP_USER_AGENT']);
        $data = curl_exec($ch);
        $headerSize = curl_getinfo($ch,CURLINFO_HEADER_SIZE);
        curl_close($ch);
        $header = substr($data,0,$headerSize);
        $result = [
            'header' => $header,
            'data' => substr($data,$headerSize,-1),
        ];
        return $result;
    }

?>