Giter Site home page Giter Site logo

dailyinterview's Introduction

  • 👋 Hi, I’m @wolichuang
  • 👀 I’m interested in ...
  • 🌱 I’m currently learning ...
  • 💞️ I’m looking to collaborate on ...
  • 📫 How to reach me ...

dailyinterview's People

Watchers

 avatar  avatar

dailyinterview's Issues

前端性能优化方案有哪些

  1. 减少 http 请求, 图片、样式、脚本做压缩合并。图片CSS Sprites
  2. 网页Gzip,CDN托管,data缓存 ,图片服务器
  3. 减少DOM操作次数,优化javascript性能
  4. 延迟加载 | 延迟渲染
  5. 图片预加载,将样式表放在顶部,将脚本放在底部 加上时间戳。
  6. 优化网络路由,比如增加 CDN 缓存;或增加并发处理能力,比如服务端设置多个域名,客户端使用多个域名同时请求资源,增加并发量。

浏览器安全-XSS攻击防护

定义

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>

nginx 使用笔记

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/*;
}

vue 升级 vue-cli3.x

安装 vue-cli3.x

npm uninstall vue-cli -g      // 卸载vue-cli旧版本
npm install -g @vue/cli      // 安装vue-cli3.0
npm vue -V                  // 查版本

安装不上 vue-cli3.x

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

mysql

创建表

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 # 多表嵌套

mysql 恢复初始密码

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('你的新密码');

terminal 命令合集

打包

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。

CSS 的居中方案有哪些?

水平居中

内联元素

  1. 使用 text-align:center
  2. 使用 Flexbox :display: flex; justify-content: center;
  3. 使用 Grid :display: grid; justify-content: center;

块元素

  1. 单个块元素使用 Auto Margin : margin: 0 auto;
  2. 单个块元素使用 display: flex; justify-content: center;
  3. 单个块元素transform使用 position: absolute; left: 50%; transform: translateX(-50%);
  4. 单个块元素已知宽度下使用 position: absolute;left: 50%;margin-left: -60px;
  5. 多个块元素父级使用 display: flex; margin-left: auto;margin-right: auto;

垂直居中

  1. Vertical Padding 使用 padding-top:20px; padding-bottom:20px;
  2. middle 使用 vertical-align: middle;
  3. Flexbox 使用 display: flex;justify-content: center;align-items: center;
  4. 绝对定位 使用 position: absolute;top: 50%;transform: translateY(-50%);
  5. 绝对定位 已知高度下使用 position: absolute;top: 50%;margin-top: -60px;
  6. Grid 使用 display: grid;align-items: center;

水平垂直居中

  1. Padding 和Text Align 使用 text-align: center; padding-top: 24px; padding-bottom: 24px;
  2. 绝对定位 使用 position: absolute;left: 50%;top: 50%;transform: translate(-50%,-50%);
  3. Flexbox 使用 display: flex;justify-content: center; align-items: center;
  4. Grid 使用 display: grid;justify-content: center;align-items: center;

jsonp

一种基于文本的数据交换方式,可以进行跨域数据交换。

<!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);

js - 数组

Map

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));

用CSS绘制一个三角形

  1. 三角形的原理就是一个盒子有四个边框交界处都是45度角
  2. 当盒子宽高都为0是,最后其实就是一个由4个三角形形成的正方形
  3. 给 border-color 设置透明,然后给其中一个设置颜色就是一个三角形了
<!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>

使用flex实现三栏布局,两边固定,中间自适应

<!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>

js- 重绘和回流

  1. 回流:引起Dom树结构变化,页面布局变化的行为

  2. 重绘:只是样式改变,不会引起Dom树变化,页面布局变化的行为

  3. 回流必定引起重绘,但重绘不一定会伴随回流

如何优化代码减少回流重绘过程?

主要**就是减少对Dom树的操作次数和减少一些具有影响性的样式请求

1.合并多次对样式的修改,如改变className

2.动态改变样式时使用cssText

3.将要改变的元素节点,先隐藏掉,改变后再显示

4.元素节点本身是处于隐藏状态,通过cloneNode或者replaceChild将其展示,原理与第3点相同

5.不要经常访问会引起浏览器flush队列的属性,如要确要访问,使用缓存即可

6.让元素脱离动画流,减少render树的规模

7.牺牲平滑度来换取速度

8.避免使用table布局

9.IE中避免使用Javascript表达式

DOM和BOM有什么区别

  1. DOM 浏览器文档模型 可以对浏览器的内容区域进行访问和操作,操作 html 树,改变 html 的内容和属性。(document)

  2. BOM 浏览器对象模型 可以对浏览器窗口进行访问和操作,譬如可以弹出新的窗口,改变状态栏中的文本。(window)

sublime-text 配置

live-server

  1. sublime使用live-server实时刷新浏览器页面预览
  2. 配置快捷键
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" }

video 视频播放器

html 中使用

<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?!');
  });
});

vue 中使用

// 安装
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-element-admin 问题汇总

关闭代码校验eslint

在vue.config.js中将lintOnSave设置为fasle即可

el-dropdown-item的点击事件,点击后没有任何反应

@click.native="changePassword"

el-form 时点击提交按钮导致页面刷新的问题

方法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()
 })

vue-cli style @import "";

引入外部css,作用域确是全局的解决方案

<style lang="scss" scoped="scoped" src="./video.scss"></style>

vue element-ui修改样式不生效

/*按钮*/
.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;
  }
}

css-文字截断

单行截断

nowrap 会将多个连续空格符或换行符视为一个空格符,默认情况下,文本超过容器宽度时,会自动在合适的地方添加换行符进行换行。设置了该值后,换行效果会被消除,使文本不进行换行,从而实现文本单行显示的效果。此时我们会发现文本发生了溢出:后面的文本内容跑到容器外面

.single {
	white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

多行截断:-webkit-line-clamp

-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()
}

ts 问题汇总

error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.

tsc parallax.ts -t es5

ios 下 fixed 定位底部 input框弹出软键盘

<!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>

图片 error 处理

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" />

electron嵌入webview显示空白问题

 mainWindow = new BrowserWindow({
    resizable: false,
    titleBarStyle: 'hidden',
    webPreferences: {
      webviewTag: true,
      preload: path.join(__dirname, 'preload.js')
    }
  });

react 路由

react-router-dom

  1. 在src目录下的index.js中
import App from './router/App'
import { BrowserRouter as Router } from 'react-router-dom'
ReactDOM.render(
  <Router>
      <App />
  </Router>, document.getElementById('root'))
  1. 创建一个目录router,在此目录下创建App.jsx文件:
import React, { Component } from 'react'
//路由表
import routes from './routes'
//路由配置
import demofrom './demo'
export default class App extends Component {
    render() {
      return (
        <div>
          {
            demo(routes)
          }
        </div>
      )
    }
  }
  1. 在router目录下创建routes.js文件,用来配置我们的路由表:
//引入组件
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
        }
      ]
   }
  ]
  1. 创建demo.js文件,用来配置路由:
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>
    )
}
  1. 我们需要创建一个views目录,里面写入我们需要的组件,与根组件App类似,以User.js为例,格式如下:
import React from 'react'
import demo from './../demo'
const User = (props) =>{
  return(
    <div>
      { demo(props.routes)}
    </div>
  )
}
export default User

标准模式和怪异模式的区别

  1. 标准盒模型:元素内容宽度=width,元素实际宽度=margin2+border2+padding2+width
  2. 怪异盒模型:元素内容宽度=width-border2-padding2,元素实际宽度=margin2+border2+padding2+width=margin2+width

git 与 svn 的区别在哪里

1 git 是分布式的 , svn 是集中式的
2 git 的分支是指向某次提交变动较小。 svn 的分支是整个版本库复制的一个目录

scss 使用

scss 编译

是什么

  1. webpack 编译 scss
  2. sublime-text 编译 scss
  3. ruby compass 编译 scss
  4. node-sass 编译
  5. 语法

sass

Sass是成熟、稳定、强大的CSS预处理器,而SCSS是Sass3版本当中引入的新语法特性,完全兼容CSS3的同时继承了Sass强大的动态功能。CSS书写代码规模较大的Web应用时,容易造成选择器、层叠的复杂度过高,因此推荐通过SASS预处理器进行CSS的开发,SASS提供的变量、嵌套、混合、继承等特性,让CSS的书写更加有趣与程式化。

sublime-text 编译scss

ruby compass 编译 scss

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 文件

node-sass 编译

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;
  }
}

文档

  1. https://www.sass.hk/guide/

写一个获取数组的最大值、最小值的方法

// 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])

Vue CLI 3 配置兼容IE10

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"],
}

git pull 和 git fetch 的区别?

  1. git fetch 只是将远程库上的变化下载下来,不会自动合并到本地分支。
  2. git pull 会自动合并到本地分支

说说你对XSS和CSRF的理解

  1. XSS 攻击,通过 sql 注入 和 脚本注入的方式,向数据库注入非法信息,造成页面显示错乱。(如:留言评论模块)

  2. csrf 跨站请求伪造,冒充正确的用户登录进行一些非法操作。(如:用户登录)

js 算法- 广度优先算法

广度优先算法

实现数组与树结构的相互转换

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))

阿里云部署项目 node

在服务器上安装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

安装pm2

npm install pm2 -g

pm2 start app.js

安装nginx

  • 安装Nginx:yum -y install nginx
  • 开启Nginx:nginx -s start
  • 修改Nginx配置文件:vi /etc/nginx/nginx.conf
  • 修改配置文件后重启Nginx:nginx -s reload
  • 直接重启Nginx:nginx -s restart
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/ 目录。

vue 基础知识

Vue.nextTick()

在修改数据之后立即使用这个方法,获取更新后的 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 更新完成后就会调用。

Vue子组件调用父组件的方法

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>

vue 监听路由变化

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  
   }
}

vue 下载

downExcel(){
      var link = document.createElement("a"); 
      link.setAttribute("download", "");
      link.href = `${process.env.BASE_URL}file/beian_import.xls`;
      link.click();
      link.remove();
    },

vue 实战代码

tab 切换

:class="currentIndex==index ? 'active' : ''" 
:style="currentIndex==index ? 'display:block' : 'display:none'" 

Invalid default value for prop xx: Props with type Object/Array

组件之间传递数组

  props: {
    bannerImages: {
      type: Array,
      default: () => {
        return []
      }
    }
  },

异步跨组件监听值

// 子组件深度监听slots
watch: {
    imagesList: {
        handler: function (newval, oldval) {
            console.log('this.imagesList', this.imagesList)
        },
       immediate: true,
        deep: true
    }
},

vue修改对象属性值视图上没有更新

this.$set(this.obj, 'name', '新的值');
Vue.set(vm.obj, 'name', '新的值')

vue 封装引入多个组件

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';

计算属性传递参数

可以返回 一个函数

es6 解构函数

let [a,b,c] = [1,2,3]

在父组件监听子组件的生命周期方法

如果你在父组件里想在子组件的mounted方法里边做一些事情

//父组件中这样写
<has-child
  :value="40"
  @hook:mounted="handleChildMounted"
/>
 
// 子组件中不用写东西
mounted () { 
},

vue 中使用双向数据流

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)
        }
    }
}

列表进入详情页的传参问题

  1. query通过path切换路由,params通过name切换路由
  2. params动态路由传参,一定要在路由中定义参数,然后在路由跳转的时候必须要加上参数,否则就是空白页面
  3. params传参时,如果没有在路由中定义参数,也是可以传过去的,同时也能接收到,但是一旦刷新页面,这个参数就不存在了。
// 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': ''
        }
      }
}

UI库的按需加载

  1. 安装babel-plugin-import插件使其按需加载:cnpm i babel-plugin-import -D
  2. 在 .babelrc文件中中添加插件配置 :
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>

只在当前页面中覆盖ui库中组件的样式

.van-tabs /deep/ .van-ellipsis { color: blue};

.van-tabs >>> .van-ellipsis { color: blue};

销毁定时器

// 通过$once来监听定时器,在beforeDestroy钩子可以被清除。
this.$once('hook:beforeDestroy', () => {
    clearInterval(timer);
})

rem文件的导入问题

(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',
            },
            // 其他参数…………
        }
    }
},

fastClick的300ms延迟

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 }
      }
    ]
  },

vue 使用 moment.js

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')
   }
},

js-工具类

/**
 * 邮箱
 * @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;
}

mongodb问题合集

mongodb version 版本错误

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

vue ESLint:Strings must use single quote

方法一

只要新建文件 .prettierrc
{
  "semi": false,
  "singleQuote": true
}

方法二

报错的JS文件中第一行写上 
/* eslint-disable */
 
Use /* eslint-disable */ to ignore all warnings in a file.

echarts-bar+line

<!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>

vue-cli3 关闭eslint

  1. 关闭eslint,直接注释掉package.json文件中eslint的配置就可以了(以下是vue-cli的默认配置)
  "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解析
     }
   },
  1. 或者vue.config.js中将以下三项设置为false
    devServer: {
        overlay: {
            warnings: false,
            errors: false
        },
      
    }

  lintOnSave: false

正则表达式

常用正则表达式

目录

字符 | 日期 | 数字 | 金额 | 网络 | 其它

正则表达式列表

字符

全角字符(fullAngle)

举例:


1. /[^\uFF00-\uFFFF]/g
2. /[^\x00-\xff]/g
半角字符(halfAngle)

举例:这是半角字符


/[\x00-\xff]/g
空白行(blank)

举例:第一行\n第三行(中间第二行为空)


/\n\s*\r/
首尾空白字符(包括空格、制表符、换页符等等)(blankSpace)

举例: 测试首尾空白字符


1. /^\s*|\s*$/
2. /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g
带有~的字符(wave)

举例:我带有~符号哦!


/[^~\x22]+/i
xml文件(xml)

举例:


/^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$/
由26个英文字母组成的字符串(english)

举例:test


/^[A-Za-z]+$/
由数字和26个英文字母组成的字符串(englishNumber)

举例:0123test456


/^[A-Za-z0-9]+$/
由数字、26个英文字母或者下划线组成的字符串(englishNumberSymbol)

举例:


/^\w+$/
URL(url)

举例:


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- ./?%&=]*)?/
URI(uri)

举例:


/[a-zA-z]+:\/\/[^\s]*/
匹配双字节字符(包括汉字在内, 一个双字节字符长度计2,ASCII字符计1)(doubleCharacter)

举例:


/[^\x00-\xff]/g
ASCII(ascii)

举例:


/\x20-\x7f/
GBK下的中文(gbkChina)

举例:


/\xa1-\xff/
中文(china)

举例:


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])+$/
Unicode编码中的汉字范围(chinaChar)

举例:


/^[\u2E80-\u9FFF]+$/
韩文(korean)

举例:


/^\x3130-\x318F$/
日文(japanese)

举例:


/^\u0800-\u4e00$/

日期

出生年月日(birth)

举例:


/^(19|20)\d{2}\-((0?[1-9])|(1[0-2]))\-((0?[1-9])|([1-2]\d)|3[01])$/
日期格式,已考虑平闰年:yyyy-mm-dd(yyyymmdd)

举例:


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)$/
日期格式,已考虑平闰年:yyyyMMdd(yyyyMMdd)

举例:


/^(?:(?!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)$/
日期正则,简单判定,未做月份及日期的判定(simpleDate)

举例:


/^\d{4}(\-)\d{1,2}\1\d{1,2}$/
日期正则,复杂判定(complexDate)

举例:


/^(?:(?!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)$/
月份,格式:"01"-"09"和"1"-"12"(month)

举例:05


/^(0?[1-9]|1[0-2])$/
一个月的31天,格式:01、09和1、31(day)

举例:31


/^((0?[1-9])|((1|2)[0-9])|30|31)$/
12小时制,hh:mm:ss(hours12)

举例:11:32:23


/^(?:1[0-2]|0?[1-9]):[0-5]\d:[0-5]\d$/
24小时制,hh:mm:ss(hours24)

举例:17:32:23


/^(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d$/

金额

只能有一位小数(onlyOneDecimal )

举例:


/^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$/
小数点后只能有最多两位数字(可以有正负号)(twoDigitNumber)

举例:-36.58


/^[+-]*(\d)*(\.\d{0,2})*$/
格式:"10000.00" 和 "10,000.00", 和没有 "分" 的 "10000" 和 "10,000"()

举例:


/^[1-9][0-9]*$/
任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过(anyNumber)

举例:


/^(0|[1-9][0-9]*)$/
一个0或者一个不以0开头的数字,还可以允许开头有一个负号()

举例:


/^(0|-?[1-9][0-9]*)$/
以0或者一个可能为负的开头不为0的数字()

举例:


/^[0-9]+(.[0-9]+)?$/
小数点后面至少应该有1位数,所以"10."是不通过的,但是 "10" 和 "10.2" 是通过的()

举例:


/^[0-9]+(.[0-9]{2})?$/
这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样()

举例:


/^[0-9]+(.[0-9]{1,2})?$/
1到3个数字,后面跟着任意个逗号+3个数字,逗号成为可选,而不是必须(commaSeparation)

举例:


/^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$/

数字

纯数字(number)

举例:


1. /^-?\d*\.?\d+$/
2. /^[0-9]*$/
n位的数字(nDigitNumber)

举例:


/^\d{n}$/
至少n位数字()

举例:


/^\d{n,}$/
m-n位的数字(digitsRange)

举例:58


/^\d{m,n}$
整数(integer)

举例:


1. /^-?\d+$/
2. /^-?[1-9]\d*$/
正整数(positiveInteger)

举例:


1. /^\d+$/
2. /^[1-9]\d*$/
非正整数(负整数 + 0)(nonPositiveInteger)

举例:


1. /^-[1-9]\d*|0$/
2. /^((-\d+)|(0+))$/
负整数(negtiveInteger)

举例:


1. /^-\d+$/
2. /^-[1-9]\d*$/
正数(positive)

举例:


/^\d*\.?\d+$/
正数、负数、和小数(positiveNegative)

举例:


/^(\-|\+)?\d+(\.\d+)?$/
负数(negative)

举例:


/^-\d*\.?\d+$/
非负整数(正整数 + 0)(nonNegtiveInteger)

举例:


1. /^[1-9]\d*|0$/
2. /^\d+$/
非零的负整数(nonZeroNegativeInteger)

举例:


1. /^\-[1-9][0-9]*$/
2. /^-[1-9]\d*$/
非零的正整数(nonZeroPositiveInteger)

举例:


1. /^\+?[1-9][0-9]*$/
2. /^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$/
浮点数(floatPoint)

举例:


1. /^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$/
2. /^(-?\d+)(\.\d+)?$/
正浮点数(positiveFloatingPoint)

举例:


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]*))$/
非正浮点数(负浮点数 + 0)(nonPositiveFloatingPoint)

举例:


1. /^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$/
2. /^((-\d+(\.\d+)?)|(0+(\.0+)?))$ /
负浮点数(negativeFloatingPointNumber)

举例:


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]*)))$/
非负浮点数(正浮点数 + 0)(nonNegativeFloatingPointNumber)

举例:


1. /^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$/
2. /^\d+(\.\d+)?$/
非零开头的最多带两位小数的数字()

举例:


/^([1-9][0-9]*)+(.[0-9]{1,2})?$/
有1-4位小数的正实数(positiveRealNumber)

举例:1234


/^[0-9]+(.[0-9]{1,4})?$/

网络

ipv4(ipv4)

举例: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]?)$/
ipv6(ipv6)

举例:


/^((([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
网址(website)

举例: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*)*$/
域名(domain)

举例: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})+$/
端口号(port)

举例: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]$)/
子网掩码(subnetMask)

举例: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)$/
http/https(http)

举例:


1. /(http|https):\/\/([\w.]+\/?)\S*/
2. /http[s]{0,1}:\/\/([\w.]+\/?)\S*/

其它

5-11位的腾讯QQ号,腾讯QQ号从10000开始(qq)

举例:80285586


/^[1-9][0-9]{4,11}$/
邮箱(email)

举例:


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}$/
银行卡(bankCard)

举例:


/^([1-9]{1})(\d{15}|\d{18})$/
IE版本(ieVervison)

举例:


/^.*MSIE [5-8](?:\\.[0-9]+)?(?!.*Trident\\/[5-9]\\.0).*$/
微信号:6至20位,以字母开头,字母,数字,减号,下划线(weChat)

举例:aya002002


/^[a-zA-Z]([-_a-zA-Z0-9]{5,19})+$/
文件的扩展名(fileExt)

举例:


1. /^.*?\.(html|css|jpg)$/
2. /^([a-zA-Z]\\:|\\\\)\\\\([^\\\\]+\\\\)*[^\\/:*?"<>|]+\\.txt(l)?$$/
根据工信部2019年最新公布的手机号段()

举例:


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})+$/
**移动(phoneYidong)

举例: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}$/
**联通(phoneLiantong)

举例: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}$/
**电信(phoneDianxin)

举例: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进制颜色(hexColor)

举例:测试提取16进制的颜色#ff0012值


/#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/
10进制值(decimal)

举例:15


/^d+.d+$/
JSON(json)

举例:


/^\w+\(({[^()]+})\)$/
中文名2到10位(字母,数字,下划线,减号)(chinaName)

举例:


/^[\u4E00-\u9FA5]{2,10}(·[\u4E00-\u9FA5]{2,10}){0,2}$/
中英验证码(verificationCode)

举例:


/^([a-zA-Z0-9]{4}|[a-zA-Z0-9]{6})$/
html标签(htmlTag)

举例:


1. /<(.*)>.*<\/\1>|<(.*) \/>/
2. /^<([a-z]+)([^<]+)(?:>(.)|\s+/>)$/
3. /<\/?\w+((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[\^'">\s]+))?)+\s*|\s*)\/?>/
html注释(htmlNotes)

举例:


1. /^<!--[\s\S]*?-->$/
2. /<!--(.*?)-->/
html片段(htmlFragment)

举例:


/^<([a-z]+)([^<]+)*(?:>(.*)<\\/\\\\\\1>|\\s+\\/>)$/
CSS属性(css)

举例:


/^\\s*[a-zA-Z\\-]+\\s*[:]{1}\\s[a-zA-Z0-9\\s.#]+[;]{1}/
提取页面的url(htmlUrl)

举例:百度


/(<a\\s*(?!.*\\brel=)[^>]*)(href="https?:\\/\\/)((?!(?:(?:www\\.)?'.implode('|(?:www\\.)?', $follow_list).'))[^" rel="external nofollow" ]+)"((?!.*\\brel=)[^>]*)(?:[^>]*)>
英文名(enName)

举例:


1. /^[a-zA-Z0-9_-]{2,10}$/
2. /^[a-zA-Z]{1}[a-zA-Z\s]{0,20}[a-zA-Z]{1}$/
座机号,固定电话(telephone)

举例:


1. /\d{3}-\d{8}|\d{4}-\d{7}/
2. /^(0[0-9]{2})\d{8}$|^(0[0-9]{3}(\d{7,8}))$/
普通电话、传真号码:可以"+"开头,除数字外,可含有"-"(fax)

举例:


/^[+]{0,1}(d){1,3}[ ]?([-]?((d)|[ ]){1,12})+$/
电话号码,正确格式:XXXX-XXXXXXX,XXXX-XXXXXXXX,XXX-XXXXXXX,XXX-XXXXXXXX,XXXXXXX,XXXXXXXX(tel)

举例:010-88888888


/^(\(\d{3,4}\)|\d{3,4}-)?\d{7,8}$/
用户名正则,4到16位(字母,数字,下划线,减号)(userName)

举例:


1. /^[a-zA-Z0-9_-]{4,16}$/
2. /^[a-zA-Z][a-zA-Z0-9_]{4,16}$/
密码强度正则,最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符()

举例:


/^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$/
6-16位字符,区分大小写(不能是9位以下的纯数字,不含空格),必须包含大写字母()

举例:


/^(?!\d{6,8}$)(?! )(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])[a-zA-Z0-9_]{6,16}$/
6-16个字符,区分大小写(不能是9位以下的纯数字,不含空格)()

举例:


/^(?!\d{6,8}$)(?! )(?=.*[a-z])(?=.*[0-9])[a-zA-Z0-9_]{6,16}$/
6-20个字符,同时包含大、小写字母及数字,不可包含特殊字符()

举例:


/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{6,20}$/
**邮政编码(六位数)(postalCode)

举例:


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)
15~18位身份证(idCard)

举例:


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}$/
18位的新版身份证()

举例:


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)$/
全角标点符(可以有中文)(mark)

举例:


/[\uFF00-\uFFFF]/g
中文、英文、数字包括下划线(zhEnNumber)

举例:


/^[\\u4E00-\\u9FA5A-Za-z0-9_]+$/$1
以字母开头,长度在6-18之间,只能包含字符、数字和下划线(beginLetter)

举例:


/^[a-zA-Z]\w{5,17}$/
是否含有 ^%&',;=?$\" 等字符(specialChar)

举例:


/[^%&',;=?$\x22]+/
base64(base64)

举例:


/^\s*data:(?:[a-z]+\/[a-z0-9-+.]+(?:;[a-z-]+=[a-z0-9-]+)?)?(?:;base64)?,([a-z0-9!$&',()*+;=\-._~:@\/?%\s]*?)\s*$/i
64位md5(md5)

举例:


/^[a-f0-9]{64}$/
IMEI(imei)

举例:


/^\d{15,17}$/
window下"文件夹"路径(windowFolder)

举例:


/^[a-zA-Z]:\\(?:\w+\\?)*$/
window下"文件"路径(windowFile)

举例:


/^[a-zA-Z]:\\(?:\w+\\)*\w+\.\w+$/
视频链接地址(videoUrl)

举例:


/^https?:\/\/.*?(?:swf|avi|flv|mpg|rm|mov|wav|asf|3gp|mkv|rmvb|mp4)$/i
图片链接地址(imgUrl)

举例:


/^https?:\/\/.*?(?:gif|png|jpg|jpeg|webp|svg|psd|bmp|tif)$/i
统一社会信用代码(creditCode)

举例:12540300G347861750


/^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/
车牌号(新能源+非新能源)(licensePlate)

举例:


/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领 A-Z]{1}[A-HJ-NP-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/
新能源车牌号(newEnergy)

举例:


/[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领 A-Z]{1}[A-HJ-NP-Z]{1}(([0-9]{5}[DF])|([DF][A-HJ-NP-Z0-9][0-9]{4}))$/
非新能源车牌号(nonNewEnergy)

举例:


/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/
护照(包含香港、澳门)(passportId)

举例:


/(^[EeKkGgDdSsPpHh]\d{8}$)|(^(([Ee][a-fA-F])|([DdSsPp][Ee])|([Kk][Jj])|([Mm][Aa])|(1[45]))\d{7}$)/

小程序

H5页面调起微信支付

前端在H5页面调起微信支付有两种办法,一是利用内置对象,二是通过引用微信的js sdk,从写法上来看用内置对象方法比较简单
一、设置支付目录
请确保实际支付时的请求目录与后台配置的目录一致,否则将无法成功唤起微信支付。
二、设置授权域名
开发公众号支付时,在统一下单接口中要求必传用户openid,而获取openid则需要您在公众平台设置获取openid的域名,只有被设置过的域名才是一个有效的获取openid的域名,否则将获取失败。

  1. 利用内置对象
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();}
  1. 微信JS-SDK

通过使用微信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"}

}

});

navigateTo:fail page "pages/navigate/navigate" is not found

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 Missing space before function parentheses

.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'
  }
}

h5-vue项目屏幕自适应

一、安装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
  1. 修改配置文件 有build文件夹
/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)

vscode 问题合集

vscode 吃内存

文件>设置>首选项 搜索设置 search.followSymlinks:false ; 之前好多的rg进程没有了。电脑也不卡了

git.enabled: false
git.autorefresh: false

vscode 修改Terminal

首选项 - settings - "terminal.integrated.shell.windows": "D:\\program\\Git\\bin\\bash.exe"

vscode 设置 settings.json

{
    // 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"
}

Disallow self-closing on HTML void elements

修改 eslintrc.js

rules: {
...
	"vue/html-self-closing": ["error", {
      "html": {
        "void": "always",
        "normal": "never",
        "component": "always"
      },
      "svg": "always",
      "math": "always"
    }],
...
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.