- 👋 Hi, I’m @wolichuang
- 👀 I’m interested in ...
- 🌱 I’m currently learning ...
- 💞️ I’m looking to collaborate on ...
- 📫 How to reach me ...
wolichuang / dailyinterview Goto Github PK
View Code? Open in Web Editor NEW面试、工作中遇到的issue
面试、工作中遇到的issue
xss是一个用于对用户输入的内容进行过滤,以避免遭受XSS攻击的模块(什么是XSS攻击?)。只要用于论坛、博客、网上商店等等一些可允许用户录入页面排版、格式控制相关的HTML的场景,xss模块通过白名单来控制允许的标签及相关的标签属性,另外还提供了一系列的接口以便用户扩展,比其他同类模块更为灵活。
npm install xss
var xss = require('xss');
var html = xss('<script>alert("xss");</script>');
console.log(html);
<script src="https://raw.github.com/leizongmin/js-xss/master/build/xss.js"></script>
<script>
// 使用函数名 filterXSS,用法一样
var html = filterXSS('<script>alert("xss");</scr' + 'ipt>');
alert(html);
</script>
1、启动:
C:\server\nginx-1.0.2>start nginx或
C:\server\nginx-1.0.2>nginx.exe
2、停止:
C:\server\nginx-1.0.2>nginx.exe -s stop或
C:\server\nginx-1.0.2>nginx.exe -s quit
注:stop是快速停止nginx,可能并不保存相关信息;quit是完整有序的停止nginx,并保存相关信息。
3、重新载入Nginx:
C:\server\nginx-1.0.2>nginx.exe -s reload
./nginx -s restart
当配置信息修改,需要重新载入这些配置时使用此命令。
4、重新打开日志文件:
C:\server\nginx-1.0.2>nginx.exe -s reopen
tail -f ./log/error.log
5、查看Nginx版本:
C:\server\nginx-1.0.2>nginx -v
6、nginx-1.14.0/logs/nginx.pid" failed (2: The system cannot find the file specified)
**
打开系统任务管理器,找到nginx.exe进程,kill掉它
7、检查nginx是否启动成功
tasklist /fi "imagename eq nginx.exe"
# 查看端口是否占用
netstat -ano | findstr 0.0.0.0:80 或 netstat -ano | findstr "80"
# 执行命令 nginx.conf文件所在目录
nginx -t
8、阿里云入口方向添加 端口
# 新增配置规则
0.0.0.0/0
9、防火墙设置
firewall-cmd --permanent --zone=public --add-service=http
firewall-cmd --permanent --zone=public --add-service=https
firewall-cmd --reload
firewall-cmd --add-port=80/tcp --permanent
firewall-cmd --add-port=8080/tcp --permanent
systemctl start nginx #启动
systemctl stop nginx #停止
systemctl restart nginx #重启
systemctl status nginx #查看运行状态
systemctl enable nginx #开机启动
service firewalld restart # 从启动防火墙
10、linux中nginx配置访问路径
日志中显示,自动跳到Linux安装目录根路径下htm文件中,
注意:其中htm路径为nginx默认配置的路径,其配置代码如下
# 解决
user root;
11、mac 下查看 nginx目录
brew search nginx //查询要安装的软件是否存在
12、nginx.conf
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
#侦听8080端口
listen 8080;
#定义使用 localhost访问
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
#定义服务器的默认网站根目录位置
root html;
#定义首页索引文件的名称
index index.html index.htm;
}
...
...
... (注释代码太多,就不全部贴出来了)
include servers/*;
}
npm uninstall vue-cli -g // 卸载vue-cli旧版本
npm install -g @vue/cli // 安装vue-cli3.0
npm vue -V // 查版本
1. npm config set prefix "C:\lichuang\database\nodejs\node_global"
2. 编辑系统变量 NODE_PATH: C:\lichuang\database\nodejs\node_global
3. 编辑用户变量 Path: C:\lichuang\database\nodejs\node_global
4. npm install -g @vue/[email protected]
5. vue --version
DROP TABLE IF EXISTS `admin_school`;
CREATE TABLE `admin_school` (
`id` int(50) NOT NULL AUTO_INCREMENT,
`name` varchar(50) CHARACTER SET utf8 NOT NULL,
`person` varchar(50) CHARACTER SET utf8 NOT NULL,
`phone` varchar(50) DEFAULT NULL,
`address` varchar(120) CHARACTER SET utf8 NOT NULL,
`schoolid` varchar(10) CHARACTER SET utf8 NOT NULL,
PRIMARY KEY (`id`),
KEY `schoolid` (`schoolid`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;
select * from `admin_school` order by id desc; #全部
select * from `admin_school` where id = "45"; #id
select * from `admin_school` where title like "%Ubuntu%"; #模糊查询
select * from `admin_school` group by brief HAVING count(*)>2 # 分组查询
select * from `admin_school` where title REGEXP '^[A-D]' # 正则查询
INSERT INTO `admin_school` VALUES ('鞍山路小学', '张三', '12345678901', '市南区鞍山路112号', '01');
update `admin_school` set title="world" where id=60; # 更新单条数据
delete from `admin_school` where id=58; # 删除数据
SELECT a.*,b.* FROM `jc_info` a JOIN `jc_aq` b on a.jcid=b.jcid order by a.id desc limit 0,3 # 嵌套查询
SELECT a.*,b.useritem,c.citem1,c.citem2,c.citem3 FROM `jc_info` a JOIN `jc_aq` b join jc_count c on a.jcid=b.jcid=c.jcid order by a.id desc limit 0,3 # 多表嵌套
step1:
苹果->系统偏好设置->最下边点mysql 在弹出页面中 关闭mysql服务(点击stop mysql server)
step2:
进入终端输入:cd /usr/local/mysql/bin/
回车后 登录管理员权限 sudo su
回车后输入以下命令来禁止mysql验证功能 ./mysqld_safe --skip-grant-tables &
回车后mysql会自动重启(偏好设置中mysql的状态会变成running)
step3:
输入命令 ./mysql
回车后,输入命令 FLUSH PRIVILEGES;
回车后,输入命令 SET PASSWORD FOR 'root'@'localhost' = PASSWORD('你的新密码');
tar
解包:tar xvf FileName.tar
打包:tar cvf FileName.tar DirName
(注:tar是打包,不是压缩!)
.gz
解压1:gunzip FileName.gz
解压2:gzip -d FileName.gz
压缩:gzip FileName
.tar.gz 和 .tgz
解压:tar zxvf FileName.tar.gz
压缩:tar zcvf FileName.tar.gz DirName
.bz2
解压1:bzip2 -d FileName.bz2
解压2:bunzip2 FileName.bz2
压缩: bzip2 -z FileName
.tar.bz2
解压:tar jxvf FileName.tar.bz2
压缩:tar jcvf FileName.tar.bz2 DirName
.bz
解压1:bzip2 -d FileName.bz
解压2:bunzip2 FileName.bz
压缩:未知
.tar.bz
解压:tar jxvf FileName.tar.bz
压缩:未知
.Z
解压:uncompress FileName.Z
压缩:compress FileName
.tar.Z
解压:tar Zxvf FileName.tar.Z
压缩:tar Zcvf FileName.tar.Z DirName
.zip
解压:unzip FileName.zip
压缩:zip FileName.zip DirName
.lha
解压:lha -e FileName.lha
压缩:lha -a FileName.lha FileName
.rpm
解包:rpm2cpio FileName.rpm | cpio -div
.deb
解包:ar p FileName.deb data.tar.gz | tar zxf -
.tar .tgz .tar.gz .tar.Z .tar.bz .tar.bz2 .zip .cpio .rpm .deb .slp .arj .rar .ace .lha .lzh .lzx .lzs .arc .sda .sfx .lnx .zoo .cab .kar .cpt .pit .sit .sea
解压:sEx x FileName.*
压缩:sEx a FileName.* FileName
sEx只是调用相关程序,本身并无压缩、解压功能
gzip 命令
减少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间。gzip 是在 Linux 系统中经常使用的一个对文件进行压缩和解压缩的命令,既方便又好用。
语法:gzip [选项] 压缩(解压缩)的文件名该命令的各选项含义如下:
-c 将输出写到标准输出上,并保留原有文件。-d 将压缩文件解压。-l 对每个压缩文件,显示下列字段: 压缩文件的大小;未压缩文件的大小;压缩比;未压缩文件的名字-r 递归式地查找指定目录并压缩其中的所有文件或者是解压缩。-t 测试,检查压缩文件是否完整。-v 对每一个压缩和解压的文件,显示文件名和压缩比。-num 用指定的数字 num 调整压缩的速度,-1 或 --fast 表示最快压缩方法(低压缩比),-9 或--best表示最慢压缩方法(高压缩比)。系统缺省值为 6。指令实例:
gzip *% 把当前目录下的每个文件压缩成 .gz 文件。gzip -dv *% 把当前目录下每个压缩的文件解压,并列出详细的信息。gzip -l *% 详细显示例1中每个压缩的文件的信息,并不解压。gzip usr.tar% 压缩 tar 备份文件 usr.tar,此时压缩文件的扩展名为.tar.gz。
1.
<meta name="format-detection" content="telephone=yes"/>
2.
<a href="tel:400-0000-688">400-0000-688</a>
<a href="sms:18688888888">发短信</a>
一种基于文本的数据交换方式,可以进行跨域数据交换。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Wsscat's jsonp</title>
</head>
<body>
<button onclick="jsonpServer('jsonp.php')">JSONP</button>
</body>
<script>
function jsonpScript(url) {
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.setAttribute("src", url);
document.body.appendChild(script);
}
function jsonCallback(data) {
console.log(data);
}
$.ajax({
url:'index.js',
type:'get',
dataType:'jsonp',
jsonpCallback:'jsonCallback',
success:function(data){
console.log(data)
}
})
</script>
</html>
var data = '[{"id":"1","name":"wsscat"},{"id":"2","name":"asw"}]';
var data = "jsonCallback(" . $data . ")";
console.log(data);
1. 当需要使用除 String 和 Symbol 以外的键名时,那么Map是最佳解决方案。
2. 如果需要按插入顺序遍历键值对,用Map。
3. 频繁增删改查,用Map。
4. Map由于不被JSON支持,所以不适合前后端数据交互,即便是前端加工后端数据,也不值得专门把对象转为Map
5. Map的原生属性
size,获取长度
6. Map的操作方法
.set(key, value):返回整个Map结构。如果key已经有值,则键值会被更新,否则就新生成该键。由于返回整个Map,所以可以链式操作。
.get(key):获取不到则返回undefined。
.has(key):键是否在Map中,返回布尔值。
.delete(key):删除成功返回true,失败返回false。
.clear():Map会成为空Map,方法执行返回undefined。
7. Map的遍历方法
.keys():返回键名的遍历器(即MapIterator)。不支持.forEach,支持...。
.values():返回键值的遍历器(即MapIterator)。不支持.forEach,支持...。
.entries():返回所有成员的遍历器(即MapIterator)。通常没用,遍历Map本身可以使用.forEach,遍历它的遍历器反而不能用.forEach,也就是说这个遍历器更弱。
.forEach():遍历 Map 的所有成员。跟数组完全一致的用法。
8. Map转对象
只能是遍历Map,然后依次给对象附加属性。
const map = new Map();
map.set(1,"foo").set(2,"bar").set(3,"baz");
const mapToObj = (map) => {
let obj = {};
for(let [k,v] of map) {
obj[k] = v;
}
return obj;
}
console.log(mapToObj(map));
9. Map转数组
最优雅办法是解构,这种方法会得到二维数组,每个元素格式类似[1, 'foo']。如果只想得到键或者值组成的数组,需要改成...map.map(v=>v[0])或者...map.map(v=>v[1])。
const map = new Map();
map.set(1,"foo").set(2,"bar").set(3,"baz");
const arr = [...map];
console.log(arr);
10. 对象转Map
优雅办法是使用Object.entries()将对象解构,得到的结果也是二维数组,跟...将可遍历对象解构的结果是一样的。恰好new Map()接受二维数组转换为Map。
let obj = {"a":1, "b":2};
let map = new Map(Object.entries(obj));
11. 数组转Map
符合格式的二维数组可以直接转换为Map,如果是一维数组转Map呢?首先这不一定有必要,因为可能一维数组转Set更好一些,如果一定要转Map,可以这样:
const arr = ["foo","bar","baz"];
const arrToMap = (arr) => new Map(arr.map( (value,key) => [key,value]));
console.log(arrToMap(arr));
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>css- 写一个三角形</title>
<style>
.wrap {
width: 1200px;
margin: 20px auto;
}
.angle {
width: 0;
border: 10px solid coral;
border-right-color: #fff;
border-top-color: #fff;
border-bottom-color: #fff;
margin-top: 20px;
}
.angle:nth-of-type(2) {
border: 10px solid coral;
border-left-color: #fff;
border-top-color: #fff;
border-bottom-color: #fff;
}
.angle:nth-of-type(3) {
border: 10px solid coral;
border-left-color: #fff;
border-right-color: #fff;
border-bottom-color: #fff;
}
.angle:nth-of-type(4) {
border: 10px solid coral;
border-left-color: #fff;
border-right-color: #fff;
border-top-color: #fff;
}
</style>
</head>
<body>
<div class="wrap">
<div class="angle"></div>
<div class="angle"></div>
<div class="angle"></div>
<div class="angle"></div>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
html,
body {
width: 100%;
height: 100%;
}
body {
margin: 0 auto;
}
.container {
width: 100%;
height: 100%;
display: flex;
}
.left,
.right {
flex: 0 0 auto;
width: 250px;
height: 100%;
}
.content {
flex: 1 1 auto;
height: 100%;
}
.red {
background-color: coral;
}
.blue {
background-color: cornflowerblue;
}
</style>
</head>
<body>
<div class="container">
<div class="left red">left</div>
<div class="content">middle</div>
<div class="right blue">right</div>
</div>
</body>
</html>
回流:引起Dom树结构变化,页面布局变化的行为
重绘:只是样式改变,不会引起Dom树变化,页面布局变化的行为
回流必定引起重绘,但重绘不一定会伴随回流
主要**就是减少对Dom树的操作次数和减少一些具有影响性的样式请求
1.合并多次对样式的修改,如改变className
2.动态改变样式时使用cssText
3.将要改变的元素节点,先隐藏掉,改变后再显示
4.元素节点本身是处于隐藏状态,通过cloneNode或者replaceChild将其展示,原理与第3点相同
5.不要经常访问会引起浏览器flush队列的属性,如要确要访问,使用缓存即可
6.让元素脱离动画流,减少render树的规模
7.牺牲平滑度来换取速度
8.避免使用table布局
9.IE中避免使用Javascript表达式
DOM 浏览器文档模型 可以对浏览器的内容区域进行访问和操作,操作 html 树,改变 html 的内容和属性。(document)
BOM 浏览器对象模型 可以对浏览器窗口进行访问和操作,譬如可以弹出新的窗口,改变状态栏中的文本。(window)
npm install live-server -g 安装live-server到全局。
新建编译系统,并配置为:
{
"shell_cmd": "live-server",
"working_dir": "${project_path}"
}
ctrl+B就可以相对当前工程目录启动live-server
启动参数说明:
--port=NUMBER - 选择要使用的端口,默认值:PORT env var或8080
--host=ADDRESS - 选择要绑定的主机地址,默认值:IP env var或0.0.0.0(“任意地址”)
--no-browser - 禁止自动Web浏览器启动
--browser=BROWSER - 指定浏览器使用,而不是系统默认
--quiet | -q - 禁止记录
--verbose | -V - 更多日志记录(记录所有请求,显示所有侦听的IPv4接口等)
--open=PATH - 启动浏览器到PATH而不是服务器根目录
--watch=PATH - 用逗号分隔的路径来专门监视更改(默认值:观看所有内容)
--ignore=PATH- 要忽略的逗号分隔的路径字符串(anymatch -compatible definition)
--ignorePattern=RGXP-文件的正则表达式忽略(即.*\.jade)(不推荐使用赞成--ignore)
--middleware=PATH - 导出.js文件的路径导出中间件功能添加; 可以是一个没有路径的名字,也不是引用middleware文件夹中捆绑的中间件的扩展名
--entry-file=PATH - 提供这个文件(服务器的根相对),以取代丢失的文件(对单页面应用程序有用)
--mount=ROUTE:PATH - 在定义的路线下提供路径内容(可能有多个定义)
--spa - 将请求从/ abc转换为/#/ abc(适用于单页面应用程序)
--wait=MILLISECONDS - (默认100ms)等待所有更改,然后重新加载
--htpasswd=PATH - 启用期待位于PATH的htpasswd文件的http-auth
--cors - 为任何来源启用CORS(反映请求源,支持凭证的请求)
--https=PATH - 到HTTPS配置模块的路径
--proxy=ROUTE:URL - 代理ROUTE到URL的所有请求
--help | -h - 显示简短的使用提示和退出
--version | -v - 显示版本和退出
首选项-->按键绑定-->用户
{ "keys": ["F2"], "command": "open_in_browser" }
<link href="https://unpkg.com/[email protected]/dist/video-js.min.css" rel="stylesheet">
<script src="https://unpkg.com/[email protected]/dist/video.min.js"></script>
<video
id="my-player"
class="video-js vjs-fluid"
controls
preload="auto"
poster="https://vjs.zencdn.net/v/oceans.png"
data-setup='{}'>
<source src="https://vjs.zencdn.net/v/oceans.mp4" type="video/mp4"></source>
<source src="https://vjs.zencdn.net/v/oceans.webm" type="video/webm"></source>
<source src="https://vjs.zencdn.net/v/oceans.ogv" type="video/ogg"></source>
<p class="vjs-no-js">
To view this video please enable JavaScript, and consider upgrading to a
web browser that
<a href="https://videojs.com/html5-video-support/" target="_blank">
supports HTML5 video
</a>
</p>
</video>
var options = { fluid: true };
var player = videojs('my-player', options, function onPlayerReady() {
videojs.log('Your player is ready!');
// In this context, `this` is the player that was created by Video.js.
this.play();
// How about an event listener?
this.on('ended', function() {
videojs.log('Awww...over so soon?!');
});
});
// 安装
npm install video.js
// 引入video.js
import Videojs from 'video.js'
import 'video.js/dist/video-js.css'
Vue.prototype.$video = Videojs
// 展示层
<!-- 如果有视频,不展示banner图,显示视频框 -->
<img :src="aggregationData.BannerImage" v-show="isBanner" alt="">
<div v-show="isVideo">
<video
id="myVideo"
class="video-js vjs-big-play-centered vjs-fluid"
controls
preload="auto"
width="100%"
height="100%"
:poster="aggregationData.BannerImage"
>
<source
type="video/mp4"
:src="aggregationData.BannerVideo"
>
</video>
</div>
initVideo() { //此处初始化的调用,我放在了获取数据之后的方法内,而不是放在钩子函数mounted
//页面dom元素渲染完毕,执行回调里面的方法
this.$nextTick(() => {
let myPlayer = this.$video(document.getElementById('myVideo'), {
//确定播放器是否具有用户可以与之交互的控件。没有控件,启动视频播放的唯一方法是使用autoplay属性或通过Player API。
controls: true,
//自动播放属性,muted:静音播放
autoplay: false,
//建议浏览器是否应在<video>加载元素后立即开始下载视频数据。
preload: "auto",
//设置视频播放器的显示宽度(以像素为单位)
// width: "800px",
//设置视频播放器的显示高度(以像素为单位)
// height: "400px",
controlBar:{
playToggle:true
}
});
})
1. gif
优点:无损压缩 、图片体积小
缺点:色彩丰富的图片会失真
适用: 小图标
2. png
优点:无损压缩,图片质量高,色彩丰富,支持透明度,提供了边缘优化。
缺点:图片较大。
适用:小图标,小背景图
3. jpg
优点:占用内存小,网页加载速度快
缺点:有损压缩
适用:大背景图,色彩丰富的图片
4.SVG
优点:SVG是矢量图形,不受像素影响,在不同平台上都表现良好;可以通过JS控制实现动画效果。
缺点:DOM比正常的图形慢,而且如果其结点多而杂,就更慢;不能与HTML内容集成。
适用场景:主要用于设计模型的展示等。
5. WebP
优点:WebP格式,谷歌(google)开发的一种旨在加快图片加载速度的图片格式。图片压缩体积大约只有JPEG的2/3,并能节省大量的服务器宽带资源和数据空间。
缺点:相较编码JPEG文件,编码同样质量的WebP文件需要占用更多的计算资源。
适用场景:WebP既支持有损压缩也支持无损压缩。将来可能是JPEG的代替品。
在vue.config.js中将lintOnSave设置为fasle即可
@click.native="changePassword"
方法1.不要将button放在form表单中
方法2.给button设置type属性为button
<button type="button">提交</button>
方法3.如果使用了elementui,可以使用el-button
<link href="/Scripts/Common/viewer.min.css" rel="stylesheet">
<script src="/Scripts/Common/viewer.min.js"></script>
// 使用
<el-table-column label="照片" align='center' fixed="right">
<template slot-scope="scope">
<el-button type="text" size="small" v-on:click="lookDetail(scope.row)">查看</el-button>
</template>
</el-table-column>
<div class='elImage' v-show="centerDialogVisible">
<ul id='viewer'>
<li v-for="(item,index) in photo1" :key="index">
<img class="user-avatar" :data-original='item' :src="item">
</li>
</ul>
</div>
this.$nextTick(function(){
var viewer = new Viewer(document.getElementById('viewer'),{
url: 'data-original',
navbar: false,
fullscreen: false,
hide:function(){
viewer.destroy()
}
});
viewer.show()
})
引入外部css,作用域确是全局的解决方案
<style lang="scss" scoped="scoped" src="./video.scss"></style>
/*按钮*/
.meeting-radio {
padding: 5px 0;
::v-deep .el-radio {
padding-right: 50px;
}
::v-deep .el-radio__label {
font-size: 16px;
}
::v-deep .el-radio__inner {
width: 18px;
height: 18px;
}
::v-deep .el-radio__inner::after {
width: 8px;
height: 8px;
background-color: #b5000d;
}
::v-deep .el-radio__input.is-checked .el-radio__inner {
border-color: #b5000d;
border-width: 2px;
background: #fff;
}
::v-deep .el-radio__input.is-checked + .el-radio__label {
color: #b5000d;
}
}
nowrap 会将多个连续空格符或换行符视为一个空格符,默认情况下,文本超过容器宽度时,会自动在合适的地方添加换行符进行换行。设置了该值后,换行效果会被消除,使文本不进行换行,从而实现文本单行显示的效果。此时我们会发现文本发生了溢出:后面的文本内容跑到容器外面
.single {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
-webkit-line-clamp 可以指定文本在第几行进行截断并添加 …。该属性只有在 display 属性设置成 -webkit-box 或者 -webkit-inline-box 并且 -webkit-box-orient 属性设置成 vertical时才有效果。
.multi-line {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
}
伪元素 ::before(当然也可以使用 ::after) 务必要设置和容器元素一样的背景,否则会出现文字重叠的效果
.multi-line {
position: relative;
line-height: 20px;
max-height: 60px;
overflow: hidden;
word-break: break-all;
}
.multi-line::before {
content: "…";
position: absolute;
top: 40px;
right: 0;
background-color: #fff;
}
.fade-out{
position: relative;
line-height: 20px;
max-height: 60px;
overflow: hidden;
word-break: break-all;
}
.fade-out::after {
content: "";
position: absolute;
top: 40px;
right: 0;
width: 40%;
height: 20px;
background-image: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1) 70%);
}
.read-more {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
word-break: break-all;
max-width: 600px;
}
const content = document.querySelector('.read-more')
const btn = document.querySelector('button')
function setReadmoreVisible() {
if (content.scrollHeight > content.clientHeight) {
btn.style.display = 'inline-block'
} else {
btn.style.display = 'none'
}
}
window.addEventListener('resize', function() {
setReadmoreVisible()
}, false)
window.onload = function() {
setReadmoreVisible()
}
tsc parallax.ts -t es5
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
header {
position: absolute;
top: 0;
left: 0;
z-index: 9999;
width: 100%;
height: 50px;
line-height: 50px;
font-size: 18px;
text-align: center;
background: #ccc;
}
main {
position: absolute;
top: 50px;
bottom: 0;
width: 100%;
margin-bottom: 50px;
overflow-y: scroll;
/*让滑动更流畅*/
-webkit-overflow-scrolling: touch;
}
footer {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 50px;
line-height: 50px;
text-align: center;
background: #666;
border-top: 1px solid #e6e6e6;
}
footer input {
display: inline-block;
width: 90%;
height: 20px;
font-size: 14px;
outline: none;
border: 1px solid #e6e6e6;
border-radius: 5px;
}
</style>
</head>
<body>
<header>header</header>
<main>
<ul>
<li>14</li>
<li>15</li>
<li>16</li>
<li>17</li>
<li>18</li>
<li>19</li>
<li>20</li>
<li>1</li>
<li>12</li>
<li>13</li>
<li>14</li>
<li>15</li>
<li>16</li>
<li>17</li>
<li>18</li>
<li>19</li>
<li>20</li>
<li>1</li>
<li>12</li>
<li>13</li>
</ul>
</main>
<footer>
<input type="text" placeholder="Type here..." />
</footer>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.10.0/jquery.js"></script>
<script type="text/javascript">
var timer = null;
$(function () {
$('input').on('focus', function () {
$('main').on('scroll', function () {
$('input').blur();
});
var target = this;
clearInterval(timer);
timer = setInterval(function () {
target.scrollIntoView(true);
}, 100);
});
});
</script>
</body>
</html>
img.error {
display: inline-block;
transform: scale(1);
content: '';
color: transparent;
}
img.error::before {
content: '';
position: absolute;
left: 0; top: 0;
width: 100%; height: 100%;
background: #f5f5f5 url(break.svg) no-repeat center / 50% 50%;
}
img.error::after {
content: attr(alt);
position: absolute;
left: 0; bottom: 0;
width: 100%;
line-height: 2;
background-color: rgba(0,0,0,.5);
color: white;
font-size: 12px;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
<img src="zxx.jpg" alt="CSS新世界封面" onerror="this.classList.add('error');">
<img src="/image.gif" onerror='this.src="default.gif" />
jdk 需要装1.8
flutter doctor
flutter doctor --android-licenses
mainWindow = new BrowserWindow({
resizable: false,
titleBarStyle: 'hidden',
webPreferences: {
webviewTag: true,
preload: path.join(__dirname, 'preload.js')
}
});
import App from './router/App'
import { BrowserRouter as Router } from 'react-router-dom'
ReactDOM.render(
<Router>
<App />
</Router>, document.getElementById('root'))
import React, { Component } from 'react'
//路由表
import routes from './routes'
//路由配置
import demofrom './demo'
export default class App extends Component {
render() {
return (
<div>
{
demo(routes)
}
</div>
)
}
}
//引入组件
import Home from './views/Home'
import Kind from './views/Kind'
import Cart from './views/Cart'
import User from './views/User'
import UserList from './views/UserList'
import AdminList from './views/Adminlist'
// eslint-disable-next-line import/no-anonymous-default-export
export default [
{
path: '/home',
title: '首页',
component: Home
},
{
path: '/kind',
title: '分类管理',
component: Kind
},
{
path: '/cart',
title: '购物车管理',
component: Cart
},
{
path:'/user',
title:'用户管理',
component:User,
children: [
{
path: '/user/list',
title: '用户列表',
component: UserList
},
{
path: '/user/admin',
title: '管理员列表',
component: AdminList
}
]
}
]
import React from 'react'
import { Route, Switch, NavLink } from 'react-router-dom'
// eslint-disable-next-line import/no-anonymous-default-export
export default (routes) =>{
return(
<div>
<ul>
{
routes.map((route)=>(
<li key={route.path}>
//标签跳转
<NavLink to = { route.path } >{ route.title }</NavLink>
</li>
))
}
</ul>
<Switch>
{
routes.map((route)=>(
//内容显示
<Route key={route.path} path={route.path} render = {()=>(
<route.component routes = { route.children }/>
)}/>
))
}
</Switch>
</div>
)
}
import React from 'react'
import demo from './../demo'
const User = (props) =>{
return(
<div>
{ demo(props.routes)}
</div>
)
}
export default User
1 git 是分布式的 , svn 是集中式的
2 git 的分支是指向某次提交变动较小。 svn 的分支是整个版本库复制的一个目录
今日 get
Sass是成熟、稳定、强大的CSS预处理器,而SCSS是Sass3版本当中引入的新语法特性,完全兼容CSS3的同时继承了Sass强大的动态功能。CSS书写代码规模较大的Web应用时,容易造成选择器、层叠的复杂度过高,因此推荐通过SASS预处理器进行CSS的开发,SASS提供的变量、嵌套、混合、继承等特性,让CSS的书写更加有趣与程式化。
1、依次执行下面三条命令,移除旧源,改用新源
> gem sources --remove http://rubygems.org/
> gem sources --remove https://rubygems.org/
> gem sources -a https://rubygems.org/
2、然后执行下面的命令,查看源列表
> gem sources -l
应该会是下面输出
*** CURRENT SOURCES ***
https://gems.ruby-china.org/
(请确保只有 https://gems.ruby-china.org/)
3、然后就可以安装compass了
> gem install compass
> gem install sass
> 或则
sudo apt-get install ruby ruby-sass ruby-compass
4. https://rubygems.org/search?utf8=%E2%9C%93&query=compass
5. 编译
sass sass 文件 css 文件
cnpm install -g node-sass
node-sass src/input.scss dist/output.css
node-sass –watch src/input.scss dist/output.css
变量用来存储需要在CSS中复用的信息,例如颜色和字体。SASS通过$符号去声明一个变量。
$font-stack: Helvetica, sans-serif;
$primary-color: #333;
body {
font: 100% $font-stack;
color: $primary-color;
}
SASS能够将代码分割为多个片段,并以underscore风格的下划线作为其命名前缀(_reset.scss),SASS会通过这些下划线来辨别哪些文件是SASS片段,并且不让片段内容直接生成为CSS文件,从而只是在使用@import指令的位置被导入。_会产生新的HTTP请求。
// _reset.scss
html, body, ul, ol {
margin: 0;
padding: 0;
}
// base.scss
@import 'reset'; // 可省略扩展名
body {
font: 100% Helvetica, sans-serif;
background-color: #efefef;
}
/*===== SCSS =====*/
a {
font-weight: bold;
text-decoration: none;
&:hover { text-decoration: underline; }
body & { font-weight: normal; }
}
SASS允许开发人员以嵌套的方式使用CSS
nav {
ul {
margin: 0;
padding: 0;
list-style: none;
}
}
混合(Mixin)用来分组那些需要在页面中复用的CSS声明,该特性在添加浏览器兼容性前缀的时候非常有用。
@mixin border-radius($radius) {
border-radius: $radius;
-ms-border-radius: $radius;
-moz-border-radius: $radius;
-webkit-border-radius: $radius;
}
.box {
@include border-radius(10px);
}
通过@extend指令在选择器之间复用CSS属性,并且不会产生冗余的代码。
// 这段代码不会被输出到最终生成的CSS文件,因为它没有被任何代码所继承。
%other-styles {
display: flex;
flex-wrap: wrap;
}
// 下面代码会正常输出到生成的CSS文件,因为它被其接下来的代码所继承。
%message-common {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.message {
@extend %message-common;
}
.success {
@extend %message-common;
border-color: green;
}
.error {
@extend %message-common;
border-color: red;
}
.warning {
@extend %message-common;
border-color: yellow;
}
提供了标准的算术运算符,例如+、-、*、/、%。可以在aside和article选择器当中对宽度进行简单的计算。
.container { width: 100%; }
article[role="main"] {
float: left;
width: 600px / 960px * 100%;
}
aside[role="complementary"] {
float: right;
width: 300px / 960px * 100%;
}
CSS许多属性都位于相同的命名空间(例如font-family、font-size、font-weight都位于font命名空间下),Scss当中只需要编写命名空间一次,后续嵌套的子属性都将会位于该命名空间之下。
.demo {
// 命令空间后带有冒号:
font: {
family: fantasy;
size: 30em;
weight: bold;
}
}
// Math 的 max 方法将会应用给 Array
var max1 = Math.max.apply(Array,[25,62,91,78,34,62])
var min1 = Math.min.apply(Array,[25,62,91,78,34,62])
// es6 扩展运算符
Math.max(...[25,62,91,78,34,62])
Math.min(...[25,62,91,78,34,62])
1. 安装依赖
yarn add --dev @babel/polyfill
在入口文件 main.js 引入依赖 import '@babel/polyfill';
2. 修改 babel.config.js
module.exports = {
presets: [
[
'@vue/app',
{
useBuiltIns: 'entry'
}
]
],
};
3. 修改 .browserslistrc 或 package.json
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 10"
]
4. 修改 vue.config.js
默认情况下 babel-loader 会忽略所有 node_modules 中的文件,如果你想要通过 Babel 显式转译一个依赖,可以在这个选项中列出来。
module.exports = {
transpileDependencies: ["element-ui", "vue-qrcode-directive"],
}
XSS 攻击,通过 sql 注入 和 脚本注入的方式,向数据库注入非法信息,造成页面显示错乱。(如:留言评论模块)
csrf 跨站请求伪造,冒充正确的用户登录进行一些非法操作。(如:用户登录)
实现数组与树结构的相互转换
let data = [
{ id: 0, parentId: null, name: '生物' },
{ id: 1, parentId: 0, name: '动物' },
{ id: 2, parentId: 0, name: '植物' },
{ id: 3, parentId: 0, name: '微生物' },
{ id: 4, parentId: 1, name: '哺乳动物' },
{ id: 5, parentId: 1, name: '卵生动物' },
{ id: 6, parentId: 2, name: '种子植物' },
{ id: 7, parentId: 2, name: '蕨类植物' },
{ id: 8, parentId: 4, name: '大象' },
{ id: 9, parentId: 4, name: '海豚' },
{ id: 10, parentId: 4, name: '猩猩' },
{ id: 11, parentId: 5, name: '蟒蛇' },
{ id: 12, parentId: 5, name: '麻雀' }
]
let node = {
"id": 0,
"parentId": null,
"name": "生物",
"children": [{
"id": 1,
"parentId": 0,
"name": "动物",
"children": [{
"id": 4,
"parentId": 1,
"name": "哺乳动物",
"children": [{
"id": 8,
"parentId": 4,
"name": "大象"
}, {
"id": 9,
"parentId": 4,
"name": "海豚"
}, {
"id": 10,
"parentId": 4,
"name": "猩猩"
}]
}, {
"id": 5,
"parentId": 1,
"name": "卵生动物",
"children": [{
"id": 11,
"parentId": 5,
"name": "蟒蛇"
}, {
"id": 12,
"parentId": 5,
"name": "麻雀"
}]
}]
}, {
"id": 2,
"parentId": 0,
"name": "植物",
"children": [{
"id": 6,
"parentId": 2,
"name": "种子植物"
}, {
"id": 7,
"parentId": 2,
"name": "蕨类植物"
}]
}, {
"id": 3,
"parentId": 0,
"name": "微生物"
}]
}
function transTree(data) {
let result = []
let map = {}
if (!Array.isArray(data)) {//验证data是不是数组类型
return []
}
data.forEach(item => {//建立每个数组元素id和该对象的关系
map[item.id] = item //这里可以理解为浅拷贝,共享引用
})
data.forEach(item => {
let parent = map[item.parentId] //找到data中每一项item的爸爸
if (parent) {//说明元素有爸爸,把元素放在爸爸的children下面
(parent.children || (parent.children = [])).push(item)
} else {//说明元素没有爸爸,是根节点,把节点push到最终结果中
result.push(item) //item是对象的引用
}
})
return result //数组里的对象和data是共享的
}
console.log(JSON.stringify(transTree(data)))
function transArr(node) {
let queue= [node]
let data = [] //返回的数组结构
while (queue.length !== 0) { //当队列为空时就跳出循环
let item = queue.shift() //取出队列中第一个元素
data.push({
id: item.id,
parentId: item.parentId,
name: item.name
})
let children = item.children // 取出该节点的孩子
if (children) {
for (let i = 0; i < children.length; i++) {
queue.push(children[i]) //将子节点加入到队列尾部
}
}
}
return data
}
console.log(transArr(node))
cd /usr/local/src/
wget http://nodejs.org/dist/v6.10.3/node-v6.10.3.tar.gz
tar zxvf node-v6.10.3.tar.gz
cd node-v6.10.3
./configure --prefix=/usr/local/node/6.10.3
make
make install
vim /etc/profile
export NODE_HOME=/usr/local/node/6.10.3
export PATH=$NODE_HOME/bin:$PATH
source /etc/profile
node -v
npm install pm2 -g
pm2 start app.js
vi /etc/nginx/nginx.conf
server {
listen 8888;
server_name localhost;
location / {
root /usr/local/var/www/php/;
index index.html;
}
}
修改配置文件后重启Nginx:nginx -s reload
具体为:scp -r local_dir username@servername:remote_dir,把当前目录的local_dir目录上传到服务器的remote_dir目录。
例如:scp -r test [email protected]:/var/www/,把当前目录下的test目录上传到服务器的/var/www/ 目录。
在修改数据之后立即使用这个方法,获取更新后的 DOM。所以放在Vue.nextTick()回调函数中的执行的应该是会对DOM进行操作的
1. 如果需要 在 created()函数进行的DOM操作,一定要放在Vue.nextTick()的回调函数中。
原因是在created()钩子函数执行的时候DOM 其实并未进行任何渲染,与之对应的就是mounted钩子函数,因为该钩子函数执行时所有的DOM挂载已完成。
2. 当数据双向绑定改变 dom元素后,对新DOM进行操作的方法应该放在 nextTick 中。
3. Vue是异步执行dom更新的,一旦观察到数据变化,Vue就会开启一个队列,然后把在同一个事件循环 (event loop) 当中观察到数据变化的 watcher 推送进这个队列。如果这个watcher被触发多次,只会被推送到队列一次。这种缓冲行为可以有效的去掉重复数据造成的不必要的计算和Dom操作。而在下一个事件循环时,Vue会清空队列,并进行必要的DOM更新。
当你设置 vm.someData = 'new value',DOM 并不会马上更新,而是在异步队列被清除,也就是下一个事件循环开始时执行更新时才会进行必要的DOM更新。如果此时你想要根据更新的 DOM 状态去做某些事情,就会出现问题。
为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用。
1. 第一种方法是直接在子组件中通过this.$parent.event来调用父组件的方法
<template>
<div>
<child></child>
</div>
</template>
<script>
import child from '~/components/dam/child';
export default {
components: {
child
},
methods: {
fatherMethod() {
console.log('测试');
}
}
};
</script>
<template>
<div>
<button @click="childMethod()">点击</button>
</div>
</template>
<script>
export default {
methods: {
childMethod() {
this.$parent.fatherMethod();
}
}
};
</script>
2. 第二种方法是在子组件里用$emit向父组件触发一个事件,父组件监听这个事件。
<template>
<div>
<child @fatherMethod="fatherMethod"></child>
</div>
</template>
<script>
import child from '~/components/dam/child';
export default {
components: {
child
},
methods: {
fatherMethod() {
console.log('测试');
}
}
};
</script>
<template>
<div>
<button @click="childMethod()">点击</button>
</div>
</template>
<script>
export default {
methods: {
childMethod() {
this.$emit('fatherMethod');
}
}
};
</script>
3. 第三种是父组件把方法传入子组件中,在子组件里直接调用这个方法
<template>
<div>
<child :fatherMethod="fatherMethod"></child>
</div>
</template>
<script>
import child from '~/components/dam/child';
export default {
components: {
child
},
methods: {
fatherMethod() {
console.log('测试');
}
}
};
</script>
<template>
<div>
<button @click="childMethod()">点击</button>
</div>
</template>
<script>
export default {
props: {
fatherMethod: {
type: Function,
default: null
}
},
methods: {
childMethod() {
if (this.fatherMethod) {
this.fatherMethod();
}
}
}
};
</script>
watch: {
$route: 'loadPath' // 监听事件
},
loadPath() {
this.listParams.title = this.$route.query.input;
this.fetchData(); // 加载数据
},
watch:{
fristName:{
handle(newValue,oldValue){
this.fullValue = newValue + this.lastName;
},
immediate: true //表示声明了fistName后,立即执行handle方法
deep: true // 加上deep:true后,就可以监听obj属性的变化了
}
}
// 开销较大可以直接监听对象属性名
// 直接监听对象的属性
watch:{
obj.a:{
handle(newValue, oldValue){
console.log('obj.a is changed')
},
immediate: true,
// deep: true
}
}
downExcel(){
var link = document.createElement("a");
link.setAttribute("download", "");
link.href = `${process.env.BASE_URL}file/beian_import.xls`;
link.click();
link.remove();
},
:class="currentIndex==index ? 'active' : ''"
:style="currentIndex==index ? 'display:block' : 'display:none'"
组件之间传递数组
props: {
bannerImages: {
type: Array,
default: () => {
return []
}
}
},
// 子组件深度监听slots
watch: {
imagesList: {
handler: function (newval, oldval) {
console.log('this.imagesList', this.imagesList)
},
immediate: true,
deep: true
}
},
this.$set(this.obj, 'name', '新的值');
Vue.set(vm.obj, 'name', '新的值')
export { default as Banner } from './Banner/index.vue';
export { default as BreadCrumb } from './BreadCrumb/index.vue';
export { default as CreateMetting } from './CreateMetting/index.vue';
export { default as CrumbNav } from './CrumbNav/index.vue';
export { default as Footer } from './Footer/index.vue';
export { default as Layout } from './Layout/index.vue';
export { default as NavBox } from './NavBox/index.vue';
export { default as SvgIcon } from './SvgIcon/index.vue';
可以返回 一个函数
let [a,b,c] = [1,2,3]
如果你在父组件里想在子组件的mounted方法里边做一些事情
//父组件中这样写
<has-child
:value="40"
@hook:mounted="handleChildMounted"
/>
// 子组件中不用写东西
mounted () {
},
vue父子通讯是单向数据流,也就是子组件不能修改父组件的值,但是在很多情况下是需要修改的,比如在做功能编辑的时候,子组件需要带入父组件的原始值,而且子组件也需要修改这个值,到最后的保存值在父组件中。
// 父组件
<step-two-other v-bind:stepTwoConfig.sync="monitorConfigStr"></step-two-other>
// 子组件
<el-input v-model="config"></el-input>
props: {
stepTwoConfig: String
},
computed: {
config: {
get() {
return this.stepTwoConfig
},
set(val) {
this.$emit('update:stepTwoConfig', val)
}
}
}
// query通过path切换路由 this.$route.query.id | /detail?id=1&user=123
<router-link :to="{path: 'Detail', query: { id: 1 }}">前往Detail页面</router-link>
// params通过name切换路由 this.$route.params.id | /detail/123
<router-link :to="{name: 'Detail', params: { id: 1 }}">前往Detail页面</router-link>
proxyTable: {
// 用‘/api’开头,代理所有请求到目标服务器, 以 api 代替 target 的接口域名
'/api': {
target: 'http://jsonplaceholder.typicode.com', // 接口域名
changeOrigin: true, // 是否启用跨域
pathRewrite: { //
'^/api': ''
}
}
}
libraryDirectory {
"plugins": [
// 这里是原来的代码部分
// …………
// 这里是要我们配置的代码
["import",
{
"libraryName": "vant",
"libraryDirectory": "es",
"style": true
}
]
]
}
在main.js中按需加载你需要的插件:
// 按需引入vant组件
import {
DatetimePicker,
Button,
List
} from 'vant';
// 使用vant组件
Vue.use(DatetimePicker)
.use(Button)
.use(List);
// 最后在在页面中使用:
<van-button type="primary">按钮</van-button>
.van-tabs /deep/ .van-ellipsis { color: blue};
.van-tabs >>> .van-ellipsis { color: blue};
// 通过$once来监听定时器,在beforeDestroy钩子可以被清除。
this.$once('hook:beforeDestroy', () => {
clearInterval(timer);
})
(function(c, d) {
var e = document.documentElement || document.body,
a = "orientationchange" in window ? "orientationchange" : "resize",
b = function() {
var f = e.clientWidth;
e.style.fontSize = f >= 750 ? "100px" : 100 * (f / 750) + "px";
};
b();
c.addEventListener(a, b, false);
})(window);
安装 cnpm install vue-awesome-swiper --save
在组件中使用的方法,全局使用意义不大
// 引入组件
import 'swiper/dist/css/swiper.css'
import { swiper, swiperSlide } from 'vue-awesome-swiper'
// 在components中注册组件
components: {
swiper,
swiperSlide
}
// template中使用轮播
// ref是当前轮播
// callback是回调
// 更多参数用法,请参考文档
<swiper :options="swiperOption" ref="mySwiper" @someSwiperEvent="callback">
<!-- slides -->
<swiper-slide><div class="item">1</div></swiper-slide>
<swiper-slide><div class="item">2</div></swiper-slide>
<swiper-slide><div class="item">3</div></swiper-slide>
<!-- Optional controls -->
<div class="swiper-pagination" slot="pagination"></div>
<div class="swiper-button-prev" slot="button-prev"></div>
<div class="swiper-button-next" slot="button-next"></div>
<div class="swiper-scrollbar" slot="scrollbar"></div>
</swiper>
// 参数要写在data中
data() {
return {
// swiper轮播的参数
swiperOption: {
// 滚动条
scrollbar: {
el: '.swiper-scrollbar',
},
// 上一张,下一张
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
// 其他参数…………
}
}
},
cnpm install fastclick -S
import FastClick from 'fastclick'; // 引入插件
FastClick.attach(document.body); // 使用 fastclick
路由懒加载可以帮我们在进入首屏时不用加载过度的资源,从而减少首屏加载速度。
...
{
path: '/shipin',
component: Layout,
redirect: '/shipin/my',
children: [
{
path: 'my',
name: 'my',
component: () => import('@/pages/shipin/my'),
meta: { title: '我的会议', headerTemplate: 1 }
},
{
path: 'control-meeting',
name: 'control-meeting',
component: (resolve) =>
require(['@/pages/shipin/control-meeting.vue'], resolve),
// component: () => import('@/pages/shipin/control-meeting.vue'),
meta: { title: '会议控制', headerTemplate: 1 }
}
]
},
1. http://momentjs.cn/docs/#/displaying/
2.
import moment from 'moment'
Vue.prototype.$moment = moment
moment.locale('zh-cn')
3. 组件中使用
import moment from "moment";
filters: {
filterCalendar(calendar) {
return moment(calendar).format('YYYY MMM Do dddd')
},
filterTimes(times) {
return moment(times).format('hh:mm')
}
},
/**
* 邮箱
* @param {*} s
*/
export const isEmail = (s) => {
return /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/.test(s)
}
/**
* 手机号码
* @param {*} s
*/
export const isMobile = (s) => {
return /^1[0-9]{10}$/.test(s)
}
/**
* URL地址
* @param {*} s
*/
export const isURL = (s) => {
return /^http[s]?:\/\/.*/.test(s)
}
/**
* 是否字符串
*/
export const isString = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'String'
}
/**
* 是否数字
*/
export const isNumber = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Number'
}
/**
* 是否boolean
*/
export const isBoolean = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Boolean'
}
/**
* 是否函数
*/
export const isFunction = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Function'
}
/**
* 是否为null
*/
export const isNull = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Null'
}
/**
* 是否undefined
*/
export const isUndefined = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Undefined'
}
/**
* 是否对象
*/
export const isObj = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Object'
}
/**
* /是否数组
*/
export const isArray = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Array'
}
/**
* 是否时间
*/
export const isDate = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Date'
}
/**
* 是否正则
*/
export const isRegExp = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'RegExp'
}
/**
* 是否错误对象
*/
export const isError = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Error'
}
/**
* 是否Symbol函数
*/
export const isSymbol = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Symbol'
}
/**
* 是否Promise对象
*/
export const isPromise = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Promise'
}
/**
* 是否Set对象
*/
export const isSet = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Set'
}
export const ua = navigator.userAgent.toLowerCase();
/**
* 是否是微信浏览器
*/
export const isWeiXin = () => {
return ua.match(/microMessenger/i) == 'micromessenger'
}
/**
* 是否是移动端
*/
export const isDeviceMobile = () => {
return /android|webos|iphone|ipod|balckberry/i.test(ua)
}
/**
* 是否是QQ浏览器
*/
export const isQQBrowser = () => {
return !!ua.match(/mqqbrowser|qzone|qqbrowser|qbwebviewtype/i)
}
/**
* 是否是爬虫
*/
export const isSpider = () => {
return /adsbot|googlebot|bingbot|msnbot|yandexbot|baidubot|robot|careerbot|seznambot|bot|baiduspider|jikespider|symantecspider|scannerlwebcrawler|crawler|360spider|sosospider|sogou web sprider|sogou orion spider/.test(ua)
}
/**
* 是否ios
*/
export const isIos = () => {
var u = navigator.userAgent;
if (u.indexOf('Android') > -1 || u.indexOf('Linux') > -1) { //安卓手机
return false
} else if (u.indexOf('iPhone') > -1) { //苹果手机
return true
} else if (u.indexOf('iPad') > -1) { //iPad
return false
} else if (u.indexOf('Windows Phone') > -1) { //winphone手机
return false
} else {
return false
}
}
/**
* 是否为PC端
*/
export const isPC = () => {
var userAgentInfo = navigator.userAgent;
var Agents = ["Android", "iPhone",
"SymbianOS", "Windows Phone",
"iPad", "iPod"
];
var flag = true;
for (var v = 0; v < Agents.length; v++) {
if (userAgentInfo.indexOf(Agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}
/**
* 电话号码
* @param {*} s
*/
export const isPhone = (s) => {
return /^([0-9]{3,4}-)?[0-9]{7,8}$/.test(s)
}
/**
* 去除html标签
* @param {*} str
*/
export const removeHtmltag = (str) => {
return str.replace(/<[^>]+>/g, '')
}
/**
* 获取url参数
* @param {*} name
*/
export const getQueryString = (name) => {
const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
const search = window.location.search.split('?')[1] || '';
const r = search.match(reg) || [];
return r[2];
}
/**
* 动态引入js
* @param {*} src
*/
export const injectScript = (src) => {
const s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = src;
const t = document.getElementsByTagName('script')[0];
t.parentNode.insertBefore(s, t);
}
/**
* 根据url地址下载
* @param {*} url
*/
export const download = (url) => {
var isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
var isSafari = navigator.userAgent.toLowerCase().indexOf('safari') > -1;
if (isChrome || isSafari) {
var link = document.createElement('a');
link.href = url;
if (link.download !== undefined) {
var fileName = url.substring(url.lastIndexOf('/') + 1, url.length);
link.download = fileName;
}
if (document.createEvent) {
var e = document.createEvent('MouseEvents');
e.initEvent('click', true, true);
link.dispatchEvent(e);
return true;
}
}
if (url.indexOf('?') === -1) {
url += '?download';
}
window.open(url, '_self');
return true;
}
/**
* el是否包含某个class
* @param {*} el
* @param {*} className
*/
export const hasClass = (el, className) => {
let reg = new RegExp('(^|\\s)' + className + '(\\s|$)')
return reg.test(el.className)
}
/**
* el添加某个class
* @param {*} el
* @param {*} className
*/
export const addClass = (el, className) => {
if (hasClass(el, className)) {
return
}
let newClass = el.className.split(' ')
newClass.push(className)
el.className = newClass.join(' ')
}
/**
* el去除某个class
* @param {*} el
* @param {*} className
*/
export const removeClass = (el, className) => {
if (!hasClass(el, className)) {
return
}
let reg = new RegExp('(^|\\s)' + className + '(\\s|$)', 'g')
el.className = el.className.replace(reg, ' ')
}
/**
* 获取滚动的坐标
* @param {*} el
*/
export const getScrollPosition = (el = window) => ({
x: el.pageXOffset !== undefined ? el.pageXOffset : el.scrollLeft,
y: el.pageYOffset !== undefined ? el.pageYOffset : el.scrollTop
});
/**
* 滚动到顶部
*/
export const scrollToTop = () => {
const c = document.documentElement.scrollTop || document.body.scrollTop;
if (c > 0) {
window.requestAnimationFrame(scrollToTop);
window.scrollTo(0, c - c / 8);
}
}
/**
* el是否在视口范围内
* @param {*} el
* @param {*} partiallyVisible
*/
export const elementIsVisibleInViewport = (el, partiallyVisible = false) => {
const {
top,
left,
bottom,
right
} = el.getBoundingClientRect();
const {
innerHeight,
innerWidth
} = window;
return partiallyVisible ?
((top > 0 && top < innerHeight) || (bottom > 0 && bottom < innerHeight)) &&
((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth)) :
top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth;
}
/**
* 粘贴板
* @param {*} value
*/
export const copyTextToClipboard = (value) => {
var textArea = document.createElement("textarea");
textArea.style.background = 'transparent';
textArea.value = value;
document.body.appendChild(textArea);
textArea.select();
try {
var successful = document.execCommand('copy');
} catch (err) {
console.log('Oops, unable to copy');
}
document.body.removeChild(textArea);
}
/**
* 判断类型集合
* @param {*} str
* @param {*} type
*/
export const checkStr = (str, type) => {
switch (type) {
case 'phone': //手机号码
return /^1[3|4|5|6|7|8|9][0-9]{9}$/.test(str);
case 'tel': //座机
return /^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/.test(str);
case 'card': //身份证
return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(str);
case 'pwd': //密码以字母开头,长度在6~18之间,只能包含字母、数字和下划线
return /^[a-zA-Z]\w{5,17}$/.test(str)
case 'postal': //邮政编码
return /[1-9]\d{5}(?!\d)/.test(str);
case 'QQ': //QQ号
return /^[1-9][0-9]{4,9}$/.test(str);
case 'email': //邮箱
return /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(str);
case 'money': //金额(小数点2位)
return /^\d*(?:\.\d{0,2})?$/.test(str);
case 'URL': //网址
return /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/.test(str)
case 'IP': //IP
return /((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))/.test(str);
case 'date': //日期时间
return /^(\d{4})\-(\d{2})\-(\d{2}) (\d{2})(?:\:\d{2}|:(\d{2}):(\d{2}))$/.test(str) || /^(\d{4})\-(\d{2})\-(\d{2})$/.test(str)
case 'number': //数字
return /^[0-9]$/.test(str);
case 'english': //英文
return /^[a-zA-Z]+$/.test(str);
case 'chinese': //中文
return /^[\\u4E00-\\u9FA5]+$/.test(str);
case 'lower': //小写
return /^[a-z]+$/.test(str);
case 'upper': //大写
return /^[A-Z]+$/.test(str);
case 'HTML': //HTML标记
return /<("[^"]*"|'[^']*'|[^'">])*>/.test(str);
default:
return true;
}
}
/**
* 严格的身份证校验
* @param {*} sId
*/
export const isCardID = (sId) => {
if (!/(^\d{15}$)|(^\d{17}(\d|X|x)$)/.test(sId)) {
console.log('你输入的身份证长度或格式错误')
return false
}
//身份证城市
var aCity = {
11: "北京",
12: "天津",
13: "河北",
14: "山西",
15: "内蒙古",
21: "辽宁",
22: "吉林",
23: "黑龙江",
31: "上海",
32: "江苏",
33: "浙江",
34: "安徽",
35: "福建",
36: "江西",
37: "山东",
41: "河南",
42: "湖北",
43: "湖南",
44: "广东",
45: "广西",
46: "海南",
50: "重庆",
51: "四川",
52: "贵州",
53: "云南",
54: "西藏",
61: "陕西",
62: "甘肃",
63: "青海",
64: "宁夏",
65: "**",
71: "**",
81: "香港",
82: "澳门",
91: "国外"
};
if (!aCity[parseInt(sId.substr(0, 2))]) {
console.log('你的身份证地区非法')
return false
}
// 出生日期验证
var sBirthday = (sId.substr(6, 4) + "-" + Number(sId.substr(10, 2)) + "-" + Number(sId.substr(12, 2))).replace(/-/g, "/"),
d = new Date(sBirthday)
if (sBirthday != (d.getFullYear() + "/" + (d.getMonth() + 1) + "/" + d.getDate())) {
console.log('身份证上的出生日期非法')
return false
}
// 身份证号码校验
var sum = 0,
weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2],
codes = "10X98765432"
for (var i = 0; i < sId.length - 1; i++) {
sum += sId[i] * weights[i];
}
var last = codes[sum % 11]; //计算出来的最后一位身份证号码
if (sId[sId.length - 1] != last) {
console.log('你输入的身份证号非法')
return false
}
return true
}
/********************************************* 数字转换 ******************************/
/**
* 随机数范围
*/
export const random = () => {
return Math.random().toString(36).substr(2);
}
/**
* 将阿拉伯数字翻译成中文的大写数字
*/
export const numberToChinese = (num) => {
var AA = new Array("零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十");
var BB = new Array("", "十", "百", "仟", "萬", "億", "点", "");
var a = ("" + num).replace(/(^0*)/g, "").split("."),
k = 0,
re = "";
for (var i = a[0].length - 1; i >= 0; i--) {
switch (k) {
case 0:
re = BB[7] + re;
break;
case 4:
if (!new RegExp("0{4}//d{" + (a[0].length - i - 1) + "}$")
.test(a[0]))
re = BB[4] + re;
break;
case 8:
re = BB[5] + re;
BB[7] = BB[5];
k = 0;
break;
}
if (k % 4 == 2 && a[0].charAt(i + 2) != 0 && a[0].charAt(i + 1) == 0)
re = AA[0] + re;
if (a[0].charAt(i) != 0)
re = AA[a[0].charAt(i)] + BB[k % 4] + re;
k++;
}
if (a.length > 1) // 加上小数部分(如果有小数部分)
{
re += BB[6];
for (var i = 0; i < a[1].length; i++)
re += AA[a[1].charAt(i)];
}
if (re == '一十')
re = "十";
if (re.match(/^一/) && re.length == 3)
re = re.replace("一", "");
return re;
}
/**
* 将数字转换为大写金额
*/
export const changeToChinese = (Num) => {
//判断如果传递进来的不是字符的话转换为字符
if (typeof Num == "number") {
Num = new String(Num);
};
Num = Num.replace(/,/g, "") //替换tomoney()中的“,”
Num = Num.replace(/ /g, "") //替换tomoney()中的空格
Num = Num.replace(/¥/g, "") //替换掉可能出现的¥字符
if (isNaN(Num)) { //验证输入的字符是否为数字
//alert("请检查小写金额是否正确");
return "";
};
//字符处理完毕后开始转换,采用前后两部分分别转换
var part = String(Num).split(".");
var newchar = "";
//小数点前进行转化
for (var i = part[0].length - 1; i >= 0; i--) {
if (part[0].length > 10) {
return "";
//若数量超过拾亿单位,提示
}
var tmpnewchar = ""
var perchar = part[0].charAt(i);
switch (perchar) {
case "0":
tmpnewchar = "零" + tmpnewchar;
break;
case "1":
tmpnewchar = "壹" + tmpnewchar;
break;
case "2":
tmpnewchar = "贰" + tmpnewchar;
break;
case "3":
tmpnewchar = "叁" + tmpnewchar;
break;
case "4":
tmpnewchar = "肆" + tmpnewchar;
break;
case "5":
tmpnewchar = "伍" + tmpnewchar;
break;
case "6":
tmpnewchar = "陆" + tmpnewchar;
break;
case "7":
tmpnewchar = "柒" + tmpnewchar;
break;
case "8":
tmpnewchar = "捌" + tmpnewchar;
break;
case "9":
tmpnewchar = "玖" + tmpnewchar;
break;
}
switch (part[0].length - i - 1) {
case 0:
tmpnewchar = tmpnewchar + "元";
break;
case 1:
if (perchar != 0) tmpnewchar = tmpnewchar + "拾";
break;
case 2:
if (perchar != 0) tmpnewchar = tmpnewchar + "佰";
break;
case 3:
if (perchar != 0) tmpnewchar = tmpnewchar + "仟";
break;
case 4:
tmpnewchar = tmpnewchar + "万";
break;
case 5:
if (perchar != 0) tmpnewchar = tmpnewchar + "拾";
break;
case 6:
if (perchar != 0) tmpnewchar = tmpnewchar + "佰";
break;
case 7:
if (perchar != 0) tmpnewchar = tmpnewchar + "仟";
break;
case 8:
tmpnewchar = tmpnewchar + "亿";
break;
case 9:
tmpnewchar = tmpnewchar + "拾";
break;
}
var newchar = tmpnewchar + newchar;
}
//小数点之后进行转化
if (Num.indexOf(".") != -1) {
if (part[1].length > 2) {
// alert("小数点之后只能保留两位,系统将自动截断");
part[1] = part[1].substr(0, 2)
}
for (i = 0; i < part[1].length; i++) {
tmpnewchar = ""
perchar = part[1].charAt(i)
switch (perchar) {
case "0":
tmpnewchar = "零" + tmpnewchar;
break;
case "1":
tmpnewchar = "壹" + tmpnewchar;
break;
case "2":
tmpnewchar = "贰" + tmpnewchar;
break;
case "3":
tmpnewchar = "叁" + tmpnewchar;
break;
case "4":
tmpnewchar = "肆" + tmpnewchar;
break;
case "5":
tmpnewchar = "伍" + tmpnewchar;
break;
case "6":
tmpnewchar = "陆" + tmpnewchar;
break;
case "7":
tmpnewchar = "柒" + tmpnewchar;
break;
case "8":
tmpnewchar = "捌" + tmpnewchar;
break;
case "9":
tmpnewchar = "玖" + tmpnewchar;
break;
}
if (i == 0) tmpnewchar = tmpnewchar + "角";
if (i == 1) tmpnewchar = tmpnewchar + "分";
newchar = newchar + tmpnewchar;
}
}
//替换所有无用汉字
while (newchar.search("零零") != -1)
newchar = newchar.replace("零零", "零");
newchar = newchar.replace("零亿", "亿");
newchar = newchar.replace("亿万", "亿");
newchar = newchar.replace("零万", "万");
newchar = newchar.replace("零元", "元");
newchar = newchar.replace("零角", "");
newchar = newchar.replace("零分", "");
if (newchar.charAt(newchar.length - 1) == "元") {
newchar = newchar + "整"
}
return newchar;
}
/********************************************* 关于数组 ******************************/
/**
* 判断一个元素是否在数组中
*/
export const contains = (arr, val) => {
return arr.indexOf(val) != -1 ? true : false;
}
/**
* @param {arr} 数组
* @param {fn} 回调函数
* @return {undefined}
*/
export const each = (arr, fn) => {
fn = fn || Function;
var a = [];
var args = Array.prototype.slice.call(arguments, 1);
for (var i = 0; i < arr.length; i++) {
var res = fn.apply(arr, [arr[i], i].concat(args));
if (res != null) a.push(res);
}
}
/**
* @param {arr} 数组
* @param {fn} 回调函数
* @param {thisObj} this指向
* @return {Array}
*/
export const map = (arr, fn, thisObj) => {
var scope = thisObj || window;
var a = [];
for (var i = 0, j = arr.length; i < j; ++i) {
var res = fn.call(scope, arr[i], i, this);
if (res != null) a.push(res);
}
return a;
}
/**
* @param {arr} 数组
* @param {type} 1:从小到大 2:从大到小 3:随机
* @return {Array}
*/
export const sort = (arr, type = 1) => {
return arr.sort((a, b) => {
switch (type) {
case 1:
return a - b;
case 2:
return b - a;
case 3:
return Math.random() - 0.5;
default:
return arr;
}
})
}
/**
* 去重
*/
export const unique = (arr) => {
if (Array.hasOwnProperty('from')) {
return Array.from(new Set(arr));
} else {
var n = {},
r = [];
for (var i = 0; i < arr.length; i++) {
if (!n[arr[i]]) {
n[arr[i]] = true;
r.push(arr[i]);
}
}
return r;
}
}
/**
* 求两个集合的并集
*/
export const union = (a, b) => {
var newArr = a.concat(b);
return this.unique(newArr);
}
/**
* 求两个集合的交集
*/
export const intersect = (a, b) => {
var _this = this;
a = this.unique(a);
return this.map(a, function (o) {
return _this.contains(b, o) ? o : null;
});
}
/**
* 删除其中一个元素
*/
export const remove = (arr, ele) => {
var index = arr.indexOf(ele);
if (index > -1) {
arr.splice(index, 1);
}
return arr;
}
/**
* 将类数组转换为数组的方法
*/
export const formArray = (ary) => {
var arr = [];
if (Array.isArray(ary)) {
arr = ary;
} else {
arr = Array.prototype.slice.call(ary);
};
return arr;
}
/**
* 最大值
*/
export const max = (arr) => {
return Math.max.apply(null, arr);
}
/**
* 最小值
*/
export const min = (arr) => {
return Math.min.apply(null, arr);
}
/**
* 求和
*/
export const sum = (arr) => {
return arr.reduce((pre, cur) => {
return pre + cur
})
}
/**
* 平均值
*/
export const average = (arr) => {
return this.sum(arr) / arr.length
}
/********************************************* String 字符串操作 ******************************/
/**
* 去除空格
* @param {str}
* @param {type}
* type: 1-所有空格 2-前后空格 3-前空格 4-后空格
* @return {String}
*/
export const trim = (str, type) => {
type = type || 1
switch (type) {
case 1:
return str.replace(/\s+/g, "");
case 2:
return str.replace(/(^\s*)|(\s*$)/g, "");
case 3:
return str.replace(/(^\s*)/g, "");
case 4:
return str.replace(/(\s*$)/g, "");
default:
return str;
}
}
/**
* @param {str}
* @param {type}
* type: 1:首字母大写 2:首字母小写 3:大小写转换 4:全部大写 5:全部小写
* @return {String}
*/
export const changeCase = (str, type) => {
type = type || 4
switch (type) {
case 1:
return str.replace(/\b\w+\b/g, function (word) {
return word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase();
});
case 2:
return str.replace(/\b\w+\b/g, function (word) {
return word.substring(0, 1).toLowerCase() + word.substring(1).toUpperCase();
});
case 3:
return str.split('').map(function (word) {
if (/[a-z]/.test(word)) {
return word.toUpperCase();
} else {
return word.toLowerCase()
}
}).join('')
case 4:
return str.toUpperCase();
case 5:
return str.toLowerCase();
default:
return str;
}
}
/*
* 检测密码强度
*/
export const checkPwd = (str) => {
var Lv = 0;
if (str.length < 6) {
return Lv
}
if (/[0-9]/.test(str)) {
Lv++
}
if (/[a-z]/.test(str)) {
Lv++
}
if (/[A-Z]/.test(str)) {
Lv++
}
if (/[\.|-|_]/.test(str)) {
Lv++
}
return Lv;
}
/**
* 函数节流器
* @param {Function} fn 需要执行性的函数
* @param {number} time 时间戳
* @param {number} interval 间隔时间
*/
export const debouncer = (fn, time, interval = 200) => {
if (time - (window.debounceTimestamp || 0) > interval) {
fn && fn();
window.debounceTimestamp = time;
}
}
/**
* 在字符串中插入新字符串
* @param {string} soure 源字符
* @param {string} index 插入字符的位置
* @param {string} newStr 需要插入的字符
* @returns {string} 返回新生成的字符
*/
export const insertStr = (soure, index, newStr) => {
var str = soure.slice(0, index) + newStr + soure.slice(index);
return str;
}
/**
* 判断两个对象是否键值相同
* @param {Object} a 第一个对象
* @param {Object} b 第一个对象
* @return {Boolean} 相同返回true,否则返回false
*/
export const isObjectEqual = (a, b) => {
var aProps = Object.getOwnPropertyNames(a);
var bProps = Object.getOwnPropertyNames(b);
if (aProps.length !== bProps.length) {
return false;
}
for (var i = 0; i < aProps.length; i++) {
var propName = aProps[i];
if (a[propName] !== b[propName]) {
return false;
}
}
return true;
}
/**
* 16进制颜色转RGB\RGBA字符串
* @param {String} val 16进制颜色值
* @param {Number} opa 不透明度,取值0~1
* @return {String} 转换后的RGB或RGBA颜色值
*/
export const colorToRGB = (val, opa) => {
var pattern = /^(#?)[a-fA-F0-9]{6}$/; //16进制颜色值校验规则
var isOpa = typeof opa == 'number'; //判断是否有设置不透明度
if (!pattern.test(val)) { //如果值不符合规则返回空字符
return '';
}
var v = val.replace(/#/, ''); //如果有#号先去除#号
var rgbArr = [];
var rgbStr = '';
for (var i = 0; i < 3; i++) {
var item = v.substring(i * 2, i * 2 + 2);
var num = parseInt(item, 16);
rgbArr.push(num);
}
rgbStr = rgbArr.join();
rgbStr = 'rgb' + (isOpa ? 'a' : '') + '(' + rgbStr + (isOpa ? ',' + opa : '') + ')';
return rgbStr;
}
/**
* 追加url参数
* @param {string} url url参数
* @param {string|object} key 名字或者对象
* @param {string} value 值
* @return {string} 返回新的url
* @example
* appendQuery('lechebang.com', 'id', 3);
* appendQuery('lechebang.com?key=value', { cityId: 2, cityName: '北京'});
*/
export const appendQuery = (url, key, value) => {
var options = key;
if (typeof options == 'string') {
options = {};
options[key] = value;
}
options = $.param(options);
if (url.includes('?')) {
url += '&' + options
} else {
url += '?' + options
}
return url;
}
/**
* 判断a数组是否包含b数组中
*/
export const getArrRepeat = (arr1, arr2) => {
return arr1.filter((item, index) => {
return arr2.includes(item)
})
}
/**
* 统计数组中相同的元素个数
*/
export const getArrObjCount = (data) => data.reduce((all, item) => {
if (!all[item]) {
all[item] = 0;
}
all[item]++;
return all;
}, {});
/**
* 将数组分片
* 列子[1,2,3,4,5,6,7,8] [[1,2,3],[4,5,6],[7,8]]
*/
export const arrChunk = (data = [], space = 5) => {
var result = [];
for (var i = 0, len = data.length; i < len; i += space) {
result.push(data.slice(i, i + space));
}
return {
data: result,
total: data.length,
space
};
}
/**
* 复制内容
*/
export const copyToClip = (content) => {
var aux = document.createElement("input");
aux.setAttribute("value", content);
document.body.appendChild(aux);
aux.select();
document.execCommand("copy");
document.body.removeChild(aux);
console.log('复制成功');
}
/**
* 生成uuid
*/
export const generateUUID = () => {
let d = new Date().getTime();
let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
let r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16);
});
return uuid;
}
/**
* 兼容requestAnimationFrame
*/
export const requestAniFrame = () => {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
};
}
/*
* 探测浏览器是否支持webp
*/
export const webpSupport = () => {
if (!localStorage) return false;
switch (localStorage.getItem('supportWebp')) {
case 'true':
return true;
case 'false':
return false;
default:
try {
if (document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0) {
document.body.classList.add('webp');
localStorage.setItem('supportWebp', 'true');
return true;
} else {
localStorage.setItem('supportWebp', 'false');
return false;
}
} catch (e) {
localStorage.setItem('supportWebp', 'false');
return false;
}
}
}
/**
* 随机数范围
*/
// export function randomCode() {
// return Math.random()
// .toString(36)
// .substr(2);
// }
/**
* 随机路径
* @param {*} time
* @param {*} cFormat
*/
export function generateUUID() {
var d = new Date().getTime();
if (window.performance && typeof window.performance.now === 'function') {
d += performance.now(); // use high-precision timer if available
}
var uuid = 'xxxxxxxxxxxx2xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16);
});
return uuid;
}
npm install --save core-js
connection error: { MongoNetworkError: failed to connect to server [localhost:27017] on first connect [MongoError: Server at localhost:27017 reports maximum wire version 0, but this version of the Node.js Driver requires at least 2 (MongoDB 2.6)]
MongoDB Server 2.4.x: mongoose ^3.8 or 4.x
MongoDB Server 2.6.x: mongoose ^3.8.8 or 4.x
MongoDB Server 3.0.x: mongoose ^3.8.22, 4.x, or 5.x
MongoDB Server 3.2.x: mongoose ^4.3.0 or 5.x
MongoDB Server 3.4.x: mongoose ^4.7.3 or 5.x
MongoDB Server 3.6.x: mongoose 5.x
MongoDB Server 4.0.x: mongoose ^5.2.0
var array = ['北京',['朝阳','丰台']]
console.log(array.flat(Infinity))
只要新建文件 .prettierrc
{
"semi": false,
"singleQuote": true
}
报错的JS文件中第一行写上
/* eslint-disable */
Use /* eslint-disable */ to ignore all warnings in a file.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<div id="container" style="min-height: 420px; margin: 30px auto"></div>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"
></script>
<script type="text/javascript">
/**
* 修改参数
* **/
function buildCharts(all, issues, temperature, lines) {
var dom = document.getElementById('container'); // dom id
var myChart = echarts.init(dom);
var app = {};
option = null;
option = {
title: {
text: '考勤图表',
left: 'center',
align: 'right'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
crossStyle: {
color: '#999'
}
},
formatter: function (params) {
var relVal = params[0].name;
for (var i = 0, len = params.length; i < len; i++) {
relVal +=
'<br/><span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:' +
params[i].color +
'"></span>';
if (params[i].seriesName === '考勤率') {
relVal +=
params[i].seriesName + ' : ' + params[i].value * 100 + '%';
} else {
relVal += params[i].seriesName + ' : ' + params[i].value;
}
}
return relVal;
}
},
legend: {
right: 20,
data: ['打卡人数', '考勤异常人数', '体温异常人数', '考勤率']
},
xAxis: [
{
type: 'category',
data: [
'早上入校',
'中午离校',
'中午入校',
'下午离校',
'晚上入校',
'晚上离校'
],
axisPointer: {
type: 'shadow'
}
}
],
yAxis: [
{
type: 'value',
name: '人数',
min: 0,
max: 3000,
interval: 300,
axisLabel: {
formatter: '{value} 人'
}
},
{
type: 'value',
name: '考勤率',
axisLabel: {
formatter: function (value, index) {
var per_value = value * 100 + '%';
return per_value;
}
}
}
],
series: [
{
name: '打卡人数',
type: 'bar',
itemStyle: {
color: 'rgb(237,127,140)'
},
data: all
},
{
name: '考勤异常人数',
type: 'bar',
itemStyle: {
color: 'rgb(250,206,145)'
},
data: issues
},
{
name: '体温异常人数',
type: 'bar',
itemStyle: {
color: 'rgb(255,255,128)'
},
data: temperature
},
{
name: '考勤率',
type: 'line',
yAxisIndex: 1,
data: lines
}
]
};
if (option && typeof option === 'object') {
myChart.setOption(option, true);
}
}
window.onload = function () {
const all = [2000, 490, 700, 232, 256, 767];
const issues = [135, 162, 32, 20, 64, 33];
const temperature = [26, 59, 90, 26, 28, 70];
const lines = [];
for (var i = 0; i < all.length; i++) {
const line = (issues[i] / (all[i] + issues[i])).toFixed(2);
lines.push(line);
}
buildCharts(all, issues, temperature, lines);
};
</script>
</body>
</html>
"eslintConfig": {
"root": true,////此项是用来告诉eslint找当前配置文件不能往父级查找
"env": {
"node": true//此项指定环境的全局变量,下面的配置指定为node环境
},
"extends": [// 此项是用来配置vue.js风格,就是说写代码的时候要规范的写,如果你使用vs-code我觉得应该可以避免出错
"plugin:vue/essential",
"@vue/standard"
],
"rules": {//规则配置写在这里
"indent": [1, 4]
},
"parserOptions": {
"parser": "babel-eslint"//此项是用来指定eslint解析器的,解析器必须符合规则,babel-eslint解析器是对babel解析器的包装使其与ESLint解析
}
},
devServer: {
overlay: {
warnings: false,
errors: false
},
}
lintOnSave: false
举例:
1. /[^\uFF00-\uFFFF]/g
2. /[^\x00-\xff]/g
举例:这是半角字符
/[\x00-\xff]/g
举例:第一行\n第三行(中间第二行为空)
/\n\s*\r/
举例: 测试首尾空白字符
1. /^\s*|\s*$/
2. /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g
举例:我带有~符号哦!
/[^~\x22]+/i
举例:
/^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$/
举例:test
/^[A-Za-z]+$/
举例:0123test456
/^[A-Za-z0-9]+$/
举例:
/^\w+$/
举例:
1. /^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(:\d+)?(\/((\.)?(\?)?=?&?[a-zA-Z0-9_-](\?)?)*)*$/i
2. /^(https?:\\/\\/)?([\\da-z\\.-]+)\\.([a-z\\.]{2,6})([\/\\w \\.-]*)*\/?$/$1
3. /[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/i
4. /https?:\/\/[^\s]*/
5. /^(f|ht){1}(tp|tps):\/\/([\w-]+\.)+[\w-]+(\/[\w- ./?%&=]*)?/
举例:
/[a-zA-z]+:\/\/[^\s]*/
举例:
/[^\x00-\xff]/g
举例:
/\x20-\x7f/
举例:
/\xa1-\xff/
举例:
1. /[\u4E00-\u9FA5]/
2. /^[\u4e00-\u9fa5],{0,}$/
3. /^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0])+$/
举例:
/^[\u2E80-\u9FFF]+$/
举例:
/^\x3130-\x318F$/
举例:
/^\u0800-\u4e00$/
举例:
/^(19|20)\d{2}\-((0?[1-9])|(1[0-2]))\-((0?[1-9])|([1-2]\d)|3[01])$/
举例:
1. /^[1-2][0-9][0-9][0-9]-[0-1]{0,1}[0-9]-[0-3]{0,1}[0-9]$/
2. /^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$/
举例:
/^(?:(?!0000)[0-9]{4}(?:(?:0[1-9]|1[0-2])(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])(?:29|30)|(?:0[13578]|1[02])31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)0229)$/
举例:
/^\d{4}(\-)\d{1,2}\1\d{1,2}$/
举例:
/^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$/
举例:05
/^(0?[1-9]|1[0-2])$/
举例:31
/^((0?[1-9])|((1|2)[0-9])|30|31)$/
举例:11:32:23
/^(?:1[0-2]|0?[1-9]):[0-5]\d:[0-5]\d$/
举例:17:32:23
/^(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d$/
举例:
/^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$/
举例:-36.58
/^[+-]*(\d)*(\.\d{0,2})*$/
举例:
/^[1-9][0-9]*$/
举例:
/^(0|[1-9][0-9]*)$/
举例:
/^(0|-?[1-9][0-9]*)$/
举例:
/^[0-9]+(.[0-9]+)?$/
举例:
/^[0-9]+(.[0-9]{2})?$/
举例:
/^[0-9]+(.[0-9]{1,2})?$/
举例:
/^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$/
举例:
1. /^-?\d*\.?\d+$/
2. /^[0-9]*$/
举例:
/^\d{n}$/
举例:
/^\d{n,}$/
举例:58
/^\d{m,n}$
举例:
1. /^-?\d+$/
2. /^-?[1-9]\d*$/
举例:
1. /^\d+$/
2. /^[1-9]\d*$/
举例:
1. /^-[1-9]\d*|0$/
2. /^((-\d+)|(0+))$/
举例:
1. /^-\d+$/
2. /^-[1-9]\d*$/
举例:
/^\d*\.?\d+$/
举例:
/^(\-|\+)?\d+(\.\d+)?$/
举例:
/^-\d*\.?\d+$/
举例:
1. /^[1-9]\d*|0$/
2. /^\d+$/
举例:
1. /^\-[1-9][0-9]*$/
2. /^-[1-9]\d*$/
举例:
1. /^\+?[1-9][0-9]*$/
2. /^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$/
举例:
1. /^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$/
2. /^(-?\d+)(\.\d+)?$/
举例:
1. /^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$/
2. /^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$/
举例:
1. /^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$/
2. /^((-\d+(\.\d+)?)|(0+(\.0+)?))$ /
举例:
1. /^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$/
2. /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/
举例:
1. /^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$/
2. /^\d+(\.\d+)?$/
举例:
/^([1-9][0-9]*)+(.[0-9]{1,2})?$/
举例:1234
/^[0-9]+(.[0-9]{1,4})?$/
举例:127.0.0.1
/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
举例:
/^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i
举例:http://www.haizlin.com
/^(?=^.{3,255}$)(http(s)?:\/\/)?(www\.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\d+)*(\/\w+\.\w+)*([\?&]\w+=\w*)*$/
举例:http://www.baidu.com:8081?a=1&b=c
/^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$/
举例:65535
/^[1-9]$|(^[1-9][0-9]$)|(^[1-9][0-9][0-9]$)|(^[1-9][0-9][0-9][0-9]$)|(^[1-6][0-5][0-5][0-3][0-5]$)/
举例:255.255.255.0
/^(254|252|248|240|224|192|128|0)\.0\.0\.0|255\.(254|252|248|240|224|192|128|0)\.0\.0|255\.255\.(254|252|248|240|224|192|128|0)\.0|255\.255\.255\.(254|252|248|240|224|192|128|0)$/
举例:
1. /(http|https):\/\/([\w.]+\/?)\S*/
2. /http[s]{0,1}:\/\/([\w.]+\/?)\S*/
举例:80285586
/^[1-9][0-9]{4,11}$/
举例:
1. /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/
2. /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/
3. /[\w!#$%&'*+/=?^_{|}~-]+(?:.[\w!#$%&'*+/=?^_{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/
4. /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
5. /^[a-zA-Z0-9]+[a-zA-Z0-9_.-]+@(([a-zA-Z0-9]+)\.){1,2}[a-z]{2,3}$/
举例:
/^([1-9]{1})(\d{15}|\d{18})$/
举例:
/^.*MSIE [5-8](?:\\.[0-9]+)?(?!.*Trident\\/[5-9]\\.0).*$/
举例:aya002002
/^[a-zA-Z]([-_a-zA-Z0-9]{5,19})+$/
举例:
1. /^.*?\.(html|css|jpg)$/
2. /^([a-zA-Z]\\:|\\\\)\\\\([^\\\\]+\\\\)*[^\\/:*?"<>|]+\\.txt(l)?$$/
举例:
1. /^(?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-7|9])|(?:5[0-3|5-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[1|8|9]))\d{8}$/
2. /^1[34578]\d{9}$/
3. /^[+]{0,1}(d){1,3}[ ]?([-]?((d)|[ ]){1,12})+$/
举例:13456555555
/^1(34[0-8]|3[5-9\d]|440|4[78]\d|5[0-27-9]\d|70[356]|78\d|8[2-478]\d|98\d)\d{7}$/
举例:18689888888
/^1(3[0-2]\d|4[56]\d|5[56]\d|66\d|70[4789]|71|7[56]\d|8[56]\d)\d{7}$/
举例:13388888888
/^1(3[3]\d|349|410|49\d|53\d|70[0-2]|7[37]\d|740|8[019]\d|99\d)\d{7}$/
举例:测试提取16进制的颜色#ff0012值
/#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/
举例:15
/^d+.d+$/
举例:
/^\w+\(({[^()]+})\)$/
举例:
/^[\u4E00-\u9FA5]{2,10}(·[\u4E00-\u9FA5]{2,10}){0,2}$/
举例:
/^([a-zA-Z0-9]{4}|[a-zA-Z0-9]{6})$/
举例:
1. /<(.*)>.*<\/\1>|<(.*) \/>/
2. /^<([a-z]+)([^<]+)(?:>(.)|\s+/>)$/
3. /<\/?\w+((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[\^'">\s]+))?)+\s*|\s*)\/?>/
举例:
1. /^<!--[\s\S]*?-->$/
2. /<!--(.*?)-->/
举例:
/^<([a-z]+)([^<]+)*(?:>(.*)<\\/\\\\\\1>|\\s+\\/>)$/
举例:
/^\\s*[a-zA-Z\\-]+\\s*[:]{1}\\s[a-zA-Z0-9\\s.#]+[;]{1}/
举例:百度
/(<a\\s*(?!.*\\brel=)[^>]*)(href="https?:\\/\\/)((?!(?:(?:www\\.)?'.implode('|(?:www\\.)?', $follow_list).'))[^" rel="external nofollow" ]+)"((?!.*\\brel=)[^>]*)(?:[^>]*)>
举例:
1. /^[a-zA-Z0-9_-]{2,10}$/
2. /^[a-zA-Z]{1}[a-zA-Z\s]{0,20}[a-zA-Z]{1}$/
举例:
1. /\d{3}-\d{8}|\d{4}-\d{7}/
2. /^(0[0-9]{2})\d{8}$|^(0[0-9]{3}(\d{7,8}))$/
举例:
/^[+]{0,1}(d){1,3}[ ]?([-]?((d)|[ ]){1,12})+$/
举例:010-88888888
/^(\(\d{3,4}\)|\d{3,4}-)?\d{7,8}$/
举例:
1. /^[a-zA-Z0-9_-]{4,16}$/
2. /^[a-zA-Z][a-zA-Z0-9_]{4,16}$/
举例:
/^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$/
举例:
/^(?!\d{6,8}$)(?! )(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])[a-zA-Z0-9_]{6,16}$/
举例:
/^(?!\d{6,8}$)(?! )(?=.*[a-z])(?=.*[0-9])[a-zA-Z0-9_]{6,16}$/
举例:
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{6,20}$/
举例:
1. /^\d{6}$/
2. /^(0[1-7]|1[0-356]|2[0-7]|3[0-6]|4[0-7]|5[1-7]|6[1-7]|7[0-5]|8[013-6])\d{4}$/
3. [1-9]\d{5}(?!\d)
举例:
1. /(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}$)/
2. /^[1-9]{1}\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
3. /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$/
举例:
1. /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
2. ^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X|x)$
3. /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/
举例:
/[\uFF00-\uFFFF]/g
举例:
/^[\\u4E00-\\u9FA5A-Za-z0-9_]+$/$1
举例:
/^[a-zA-Z]\w{5,17}$/
举例:
/[^%&',;=?$\x22]+/
举例:
/^\s*data:(?:[a-z]+\/[a-z0-9-+.]+(?:;[a-z-]+=[a-z0-9-]+)?)?(?:;base64)?,([a-z0-9!$&',()*+;=\-._~:@\/?%\s]*?)\s*$/i
举例:
/^[a-f0-9]{64}$/
举例:
/^\d{15,17}$/
举例:
/^[a-zA-Z]:\\(?:\w+\\?)*$/
举例:
/^[a-zA-Z]:\\(?:\w+\\)*\w+\.\w+$/
举例:
/^https?:\/\/.*?(?:swf|avi|flv|mpg|rm|mov|wav|asf|3gp|mkv|rmvb|mp4)$/i
举例:
/^https?:\/\/.*?(?:gif|png|jpg|jpeg|webp|svg|psd|bmp|tif)$/i
举例:12540300G347861750
/^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/
举例:
/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领 A-Z]{1}[A-HJ-NP-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/
举例:
/[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领 A-Z]{1}[A-HJ-NP-Z]{1}(([0-9]{5}[DF])|([DF][A-HJ-NP-Z0-9][0-9]{4}))$/
举例:
/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/
举例:
/(^[EeKkGgDdSsPpHh]\d{8}$)|(^(([Ee][a-fA-F])|([DdSsPp][Ee])|([Kk][Jj])|([Mm][Aa])|(1[45]))\d{7}$)/
前端在H5页面调起微信支付有两种办法,一是利用内置对象,二是通过引用微信的js sdk,从写法上来看用内置对象方法比较简单
一、设置支付目录
请确保实际支付时的请求目录与后台配置的目录一致,否则将无法成功唤起微信支付。
二、设置授权域名
开发公众号支付时,在统一下单接口中要求必传用户openid,而获取openid则需要您在公众平台设置获取openid的域名,只有被设置过的域名才是一个有效的获取openid的域名,否则将获取失败。
function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":"", //公众号名称,由商户传入
"timeStamp":"1395712654", //时间戳,自1970年以来的秒数
"nonceStr":"e61463f8efa94090b1f366cccfbbb444", //随机串
"package":"prepay_id=u802345jgfjsdfgsdg888",
"signType":"MD5", //微信签名方式:
"paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名
},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {} // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。});}
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);}
}else{onBridgeReady();}
通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验。
1. 步骤一:绑定域名 【必需】先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。登录后可在“开发者中心”查看对应的接口权限。
2. 步骤二:引入JS文件【必需】在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.2.0.js
3. 步骤三:通过config接口注入权限验证配置 【必需】
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名,见附录1
jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
4. 步骤四:通过ready接口处理成功验证
5. 步骤五:通过error接口处理失败验证
6. 步骤六:判断当前客户端版本是否支持指定JS接口
wx.checkJsApi({
jsApiList: ['chooseImage'], // 需要检测的JS接口列表,所有JS接口列表见附录2,
success: function(res) {
// 以键值对的形式返回,可用的api值true,不可用为false
// 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
}
});
app.json 中没有注册路径
<swiper catchtap="handleLinkSwiper">
<image src="../../../../assets/img/home/banner1.jpg" data-url="https://mp.weixin.qq.com/"/>
// swiper 弹出链接
handleLinkSwiper(event) {
let url = JSON.stringify(event.target.dataset.url);
url = encodeURIComponent(url);
wx.navigateTo({
url: `/pages/service/web-view/index?url=${url}`
});
}
.eslint.js
module.exports = {
root: true,
env: {
node: true
},
extends: ['plugin:vue/essential', '@vue/standard'],
parserOptions: {
parser: 'babel-eslint'
},
rules: {
'space-before-function-paren': 0,
semi: 'off',
indent: 0,
quotes: ['error', 'single'],
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
}
}
一、安装lib-flexible
npm i lib-flexible -D
二、在main.js中引入
import 'lib-flexible/flexible'
三、在index.html文件中设置meta标签:
<meta name='viewport' content='width=device-width , initial-scale=1.0'>
四、然后在项目中写css时会自动将rem转化为px,需要安装px2rem这个工具
npm i px2rem-loader -D
/build/util.js:
a、在cssLoader对象下面添加一个px2remLoader对象:
const px2remLoader = {
loader : 'px2rem-loader',
options : {
//这个参数是通过psd设计稿的 宽度 / 10 来计算,这里以750为标准
remUnit : 75
}
}
b、然后将utils.js文件中的generateLoaders函数的loaders常量改为[cssLoader, px2remLoader]
const loaders = [cssLoader, px2remLoader]
4.2 无build文件夹(使用了vue cli3或3以上版本)
在项目根目录下新建vue.config.js文件
const cssLoader = {
loader: 'css-loader',
options: {
minimize: process.env.NODE_ENV === 'production',
sourceMap: options.sourceMap
}
}
// 新增px2remLoader
const px2remLoader = {
loader: 'px2rem-loader',
options: {
remUnit: 75
}
}
function generateLoaders (loader, loaderOptions) {
// 新增px2remLoader
const loaders = options.usePostCSS ? [cssLoader, postcssLoader, px2remLoader] : [cssLoader, px2remLoader]
if (loader) {
loaders.push({
loader: loader + '-loader',
options: Object.assign({}, loaderOptions, {
sourceMap: options.sourceMap
})
})
}
}
重新启动项目,即可自适应(单位使用px)
文件>设置>首选项 搜索设置 search.followSymlinks:false ; 之前好多的rg进程没有了。电脑也不卡了
git.enabled: false
git.autorefresh: false
首选项 - settings - "terminal.integrated.shell.windows": "D:\\program\\Git\\bin\\bash.exe"
{
// tab 大小为2个空格
"editor.tabSize": 2,
// 编辑器换行
"editor.wordWrap": "off",
// 开启 vscode 文件路径导航
"breadcrumbs.enabled": true,
// prettier 设置语句末尾不加分号
"prettier.semi": false,
// prettier 设置强制单引号
"prettier.singleQuote": true,
// 选择 vue 文件中 template 的格式化工具
"vetur.format.defaultFormatter.html": "js-beautify-html",
// vetur 的自定义设置
"vetur.format.defaultFormatterOptions": {
"js-beautify-html": {
"wrap_attributes": "aligned-multiple"
},
"prettier": {
"singleQuote": true,
"semi": false,
"printWidth": 100,
"wrapAttributes": false,
"sortAttributes": false
}
},
"files.associations": {
"*.vue": "vue",
"*.cjson": "jsonc",
"*.wxss": "css",
"*.wxs": "javascript"
},
// 自动修复
"editor.codeActionsOnSave": {
"source.fixAll": true, // 启用全部的格式化工具
"source.fixAll.eslint": false, // 关闭eslint格式化工具
},
"eslint.options": {
"extensions": [
".js",
".vue"
]
},
"search.exclude": {
"**/node_modules": true,
"**/bower_components": true,
"**/dist": true
},
"emmet.syntaxProfiles": {
"javascript": "jsx",
"vue": "html",
"vue-html": "html"
},
"git.confirmSync": false,
"window.zoomLevel": 0,
"editor.renderWhitespace": "boundary",
"editor.cursorBlinking": "smooth",
"editor.minimap.enabled": true,
"editor.minimap.renderCharacters": false,
"window.title": "${dirty}${activeEditorMedium}${separator}${rootName}",
"editor.codeLens": true,
"editor.snippetSuggestions": "top",
"editor.suggestSelection": "first",
"vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue",
"eslint.format.enable": true,
"editor.quickSuggestions": {
"strings": true
},
"emmet.includeLanguages": {
"wxml": "html"
},
"minapp-vscode.disableAutoConfig": true,
"search.followSymlinks": false,
"git.enabled": false,
"git.autorefresh": false,
"editor.formatOnSave": true,
"eslint.validate": [
"javascript", // 用eslint的规则检测js文件
{
"language": "vue", // 检测vue文件
"autoFix": true // 为vue文件开启保存自动修复的功能
},
{
"language": "html",
"autoFix": true
},
],
"terminal.integrated.shell.windows": "D:\\program\\Git\\bin\\bash.exe"
}
修改 eslintrc.js
rules: {
...
"vue/html-self-closing": ["error", {
"html": {
"void": "always",
"normal": "never",
"component": "always"
},
"svg": "always",
"math": "always"
}],
...
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.