Code Monkey home page Code Monkey logo

blob's People

Contributors

yanyan14231 avatar

Watchers

 avatar

blob's Issues

正则表达式(长度)

仅支持字母、数字、汉字 /^[A-Za-z0-9\u4e00-\u9fa5]+$/
获取字符串的长度,一个汉字占两个字符
getLength (str) {
    if (str === null) return 0
    if (typeof str !== 'string') {
      str += ''
    }
    return str.replace(/[^\x00-\xff]/g, 'ab').length
 }

vue和elementUI上传图片

使用vue.jselementUI上传图片

<el-form :label-position="labelPosition" label-width="150px" :model="formContent" :rules="rules" ref="formContent" status-icon>
   <el-form-item label="收银台照片" prop="bannerPicture">
        <el-upload
             class="avatar-uploader"
              :action="actionUrl"
              :show-file-list="false"
              :on-success="handleAvatarSuccess"
              :before-upload="beforeAvatarUpload"
              :on-preview="handlePictureCardPreview"
              :on-remove="handleRemove"
               :headers="headers"
            >
            <img v-if="formContent.bannerPicture" :src="formContent.bannerPicture" class="avatar">
            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
        </el-upload>
    </el-form-item>
 </el-form>
说明

headers 设置上传的请求头部
action 请求的地址
on-success 文件上传成功时的钩子
on-preview 点击文件列表中已上传的文件时的钩子
on-remove 删除文件之前的钩子,参数为上传的文件和文件列表,若返回 false 或者返回 Promise 且被 reject,则停止上传。

show-file-list 是否显示已上传文件列表

主要上传图片的过程

data () {
  return {
    actionUrl: '', // 上传的地址
      labelPosition: 'left',
      formContent: {
        bannerPicture: ''
      },
      rules: {
        bannerPicture: [
          { required: true, message: '请选择图片', trigger: 'blur' }
        ]
      },
      headers: {
        source: ''
      }
  }
},
methods: {
    // 上传图片
    handleAvatarSuccess (res, file) {
      if (res.msg === '000') {
        this.formContent.bannerPicture = '网址前缀' + res.url
      } else {
        this.notifyFailedSubmit(res.msg)
      }
    },
    beforeAvatarUpload (file) {
      const isPicType = ['image/jpeg', 'image/jpg', 'image/png', 'image/bmp'].indexOf(file.type) > -1
      const isLt2M = file.size / 1024 / 1024 < 2

      if (!isPicType) {
        this.$message.error('上传图片只能是 JPG / JPEG/ PNG/ BMP 的格式!')
      }
      if (!isLt2M) {
        this.$message.error('上传图片大小不能超过 2MB!')
      }
      return isPicType && isLt2M
    },
    handleRemove (file, fileList) {
    },
    handlePictureCardPreview (file) {
      this.formContent.bannerPicture = file.url
    },
   notifyFailedSubmit (message) {
      this.$notify.error({
        title: '出错了',
        message: message,
        duration: 2000
      })
    }
}

css

<style rel="stylesheet/scss" lang="scss" scoped>
/*上传图片*/
  .avatar-uploader {
    cursor: pointer;
    position: relative;
    overflow: hidden;
  }
  .avatar-uploader-icon {
    font-size: 28px;
    color: #8c939d;
    width: 178px;
    height: 178px;
    line-height: 178px;
    text-align: center;
    border: 1px solid #dcdfe6;
    border-radius: 6px;
  }
  .avatar-uploader-icon:hover{
    border: 1px solid #c0c4cc;
  }
  .avatar {
    width: 178px;
    height: 178px;
    display: block;
  }
  /*上传图片 end*/
</style>

异步加载js脚本时,async与defer的区别

以下图片取自 whatwg 的规范,可以说是最权威的图文解释了,详细参考原文
image

在正常情况下,即<script>没有任何额外属性标记情况下,有几点共识:

  1. js脚本分为加载解析执行这几个步骤,简单对应到图中fetch(加载)和execution(解析并执行)
  2. js的脚本加载(fetch)且执行(execution)会阻塞Dom的渲染,因此js放到最后头

而defer和async的区别如下:

  • async加载(fetch)完成后立即执行(execution)
  • defer加载(fetch)完成后延迟到dom解析完成后才会执行(execution),但会在DomContentLoaded完成之前

拓展

当以下 index.js 加载时,属性是 async 与 defer 时,输出有何不同?

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
  <script src="index.js" defer></script>
  <script>
    console.log('Start')
    document.addEventListener('DOMContentLoaded', () => {
      console.log('DCL')
    })
  </script>
</body>
</html>

index.js

console.log('Async Script')

async 输出 Start 、 DCL 、 Async Script

defer 输出 Start 、 Async Script 、DCL

flex布局

1. Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。

2. 采用 Flex 布局的元素,称为 Flex 容器(flex container),简称"容器"。它的所有子元素自动成为容器成员,称为 Flex 项目(flex item),简称"项目"。

3. 属性

flex-direction flex-wrap flex-flow justify-content align-items align-content

3.1 flex-direction属性决定主轴的方向(即项目的排列方向)
.box {
  flex-direction: row | row-reverse | column | column-reverse;
}

row(默认值):主轴为水平方向,起点在左端
row-reverse:主轴为水平方向,起点在右端
column:主轴为垂直方向,起点在上沿
column-reverse:主轴为垂直方向,起点在下沿
3.2 flex-wrap属性 默认情况下,项目都排在一条线(又称"轴线")上。flex-wrap属性定义,如果一条轴线排不下,如何换行
.box{
  flex-wrap: nowrap | wrap | wrap-reverse;
}

nowrap(默认):不换行
wrap:换行,第一行在上方
wrap-reverse:换行,第一行在下方
3.3 flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap
.box {
  flex-flow: <flex-direction> || <flex-wrap>;
}
3.4 justify-content属性定义了项目在主轴上的对齐方式
.box {
  justify-content: flex-start | flex-end | center | space-between | space-around;
}

flex-start(默认值):左对齐
flex-end:右对齐
center: 居中
space-between:两端对齐,项目之间的间隔都相等
space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍
3.5 align-items属性定义项目在交叉轴上如何对齐
.box {
  align-items: flex-start | flex-end | center | baseline | stretch;
}

flex-start:交叉轴的起点对齐
flex-end:交叉轴的终点对齐
center:交叉轴的中点对齐
baseline: 项目的第一行文字的基线对齐
stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度
3.6 align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用
.box {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}

flex-start:与交叉轴的起点对齐
flex-end:与交叉轴的终点对齐
center:与交叉轴的中点对齐
space-between:与交叉轴两端对齐,轴线之间的间隔平均分布
space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍
stretch(默认值):轴线占满整个交叉轴

4. 项目的属性

order flex-grow flex-shrink flex-basis flex align-self

4.1 order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0
.item {
  order: <integer>;
}
4.2 flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大
.item {
  flex-grow: <number>; /* default 0 */
}

如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍
4.3 flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小
.item {
  flex-shrink: <number>; /* default 1 */
}

如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。

负值对该属性无效
4.4 flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小
.item {
  flex-basis: <length> | auto; /* default auto */
}

它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间
4.5 flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选
.item {
  flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}

该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。

建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值
4.6 align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch
.item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

该属性可能取6个值,除了auto,其他都与align-items属性完全一致

Object.assign

Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

console.log(target);
// expected output: Object { a: 1, b: 4, c: 5 }

console.log(returnedTarget);
// expected output: Object { a: 1, b: 4, c: 5 }

在地图(高德)上的运行轨迹

高德地图自带的,根据用户运动,画出运动轨迹,有起点和终点
vue以及element-ui实现的,

页面布局

<div id="map"></div>

js部分
在mounted时候,加载地图,MP存在其他文件,mapKey是你地图的密钥

async mounted () {
	await MP (this.mapKey)
	this.mapRoute()
},
methods: {
  mapRoute () {
      let data = ‘获取到的数据’
      // let data = [{lng: 116.478935, lat: 39.997761}, {lng: 116.478939, lat: 39.997825}, {lng: 116.478912, lat: 39.998549}, {lng: 116.478912, lat: 39.998549}, {lng: 116.478998, lat: 39.998555}]
      let lineArr = []
      for (let i = 0; i < data.length; i++) {
        if (data[i].lat && data[i].lng) {
          lineArr.push([data[i].lng, data[i].lat])
        }
      }
      let map = new AMap.Map('map', {
	     center: lineArr[0],
	     zoom: 14
      })
     // 起始标记
      let startIcon = new AMap.Icon({
        // 图标尺寸
        size: new AMap.Size(25, 34),
        // 图标的取图地址
        image: '//a.amap.com/jsapi_demos/static/demo-center/icons/dir-marker.png',
        // 图标所用图片大小
        imageSize: new AMap.Size(135, 40),
        // 图标取图偏移量
        imageOffset: new AMap.Pixel(-9, -3)
      })
      let startMarker = new AMap.Marker({
        map: map,
        position: lineArr[0],
        icon: startIcon,
        offset: new AMap.Pixel(-10, -13),
        autoRotation: true
      })
      // 创建一个 icon
      let endIcon = new AMap.Icon({
        size: new AMap.Size(25, 34),
        image: '//a.amap.com/jsapi_demos/static/demo-center/icons/dir-marker.png',
        imageSize: new AMap.Size(135, 40),
        imageOffset: new AMap.Pixel(-95, -3)
      })
      // 将 icon 传入 marker
      let endMarker = new AMap.Marker({
        position: new AMap.LngLat(lineArr[lineArr.length - 1][0], lineArr[lineArr.length - 1][1]),
        icon: endIcon,
        offset: new AMap.Pixel(-13, -30)
      })
      let polyline = new AMap.Polyline({
        map: map,
        path: lineArr,
        showDir: true,
        strokeColor: "#28F",  //线颜色
        // strokeOpacity: 1,     //线透明度
        // strokeWeight: 6,      //线宽
        // strokeStyle: "solid"  //线样式
      })
      map.add([startMarker, endMarker])
      map.setFitView() // 适应地图
    }
}

css

#map {
  width: 100%;
  height: 100%;
}

小球拖拽并实现按钮加减(多个)

image.png

######源码如下:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
    <script src="/Scripts/jquery-3.1.1.js"></script>
    <style type="text/css">

        .lineDiv {float: left; position: relative; height: 5px; background: #ccc; width: 300px; margin: 50px auto; 
        } 
        .lineDiv .minDiv { position: absolute; top: -20px; left: 0; width: 10px; height: 10px;background: #fff; border: 1px solid #d7000c; border-radius: 50%; cursor: pointer
        }   
        .measure-drag{ clear: both; margin: 20px auto;}
        .minus{float: left; width: 20px; height: 20px; line-height: 20px; text-align: center; background: #ccc; cursor: pointer; margin: 40px 5px 0 0;}
        .add{float: left; width: 20px; height: 20px; line-height: 20px; text-align: center;  background: #ccc; cursor: pointer; margin: 40px 0 0 5px;}
    </style>
    </head>
    <body>
        <center>
            <h3>用鼠标拖动小方块<span class="msg">0</span>%</h3>
        </center>
        <div class="measure-drag">
            <div class="minus">-</div>
            <div class="lineDiv">
                <p class="minDiv">
                    <span class="vals">0</span>
                </p>
            </div>
            <div class="add">+</div>
        </div>
        <div class="measure-drag">
            <div class="minus">-</div>
            <div class="lineDiv">
                <p class="minDiv">
                    <span class="vals">0</span>
                </p>
            </div>
            <div class="add">+</div>
        </div>
        <div class="measure-drag">
            <div class="minus">-</div>
            <div class="lineDiv">
                <p class="minDiv">
                    <span class="vals">0</span>
                </p>
            </div>
            <div class="add">+</div>
        </div>
        <div class="measure-drag">
            <div class="minus">-</div>
            <div class="lineDiv">
                <p class="minDiv">
                    <span class="vals">0</span>
                </p>
            </div>
            <div class="add">+</div>
        </div>
        <div class="measure-drag">
            <div class="minus">-</div>
            <div class="lineDiv">
                <p class="minDiv">
                    <span class="vals">0</span>
                </p>
            </div>
            <div class="add">+</div>
        </div>
        
        <script>
           
             $('.measure-drag').each(function(i){
                 drag($('.measure-drag .lineDiv')[i], $('.measure-drag .minDiv')[i], $(".measure-drag .vals")[i], $('.measure-drag .minus')[i], $('.measure-drag .add')[i]);
             });

             function drag(lineDiv, minDiv, vals, minus, add){
                  var msg = $(".msg")[0];
                   /**
                   * lineDiv长线条  minDiv小球  vals小球上的数值,即为所占的比例  minus减 add加
                   */
                    var ifBool = false; //判断鼠标是否按下
                    //事件
                    var start = function(e) {
                        e.stopPropagation();
                        ifBool = true;
                        //console.log("鼠标按下")
                    }
                    var move = function(e) {
                      //  console.log("鼠标拖动")
                        if(ifBool) {
                            if(!e.touches) {    //兼容移动端
                                var x = e.clientX;
                            } else {     //兼容PC端
                                var x = e.touches[0].pageX;
                            }
                            //var x = e.touches[0].pageX || e.clientX; //鼠标横坐标var x
                            var lineDiv_left = getPosition(lineDiv).left; //长线条的横坐标
                            var minDiv_left = x - lineDiv_left; //小方块相对于父元素(长线条)的left值
                            if(minDiv_left >= lineDiv.offsetWidth - 10) {
                                minDiv_left = lineDiv.offsetWidth - 10;
                            }
                            if(minDiv_left < 0) {
                                minDiv_left = 0;
                            }
                            //设置拖动后小方块的left值
                            minDiv.style.left = minDiv_left + "px";
                            msg.innerText = parseInt((minDiv_left / (lineDiv.offsetWidth - 10)) * 100);
                            vals.innerText = parseInt((minDiv_left / (lineDiv.offsetWidth - 10)) * 100);

                        }
                    }
                    var end = function(e) {
                           // console.log("鼠标弹起")
                            ifBool = false;
                        }
                        //鼠标按下方块
                    minDiv.addEventListener("touchstart", start);
                    minDiv.addEventListener("mousedown", start);
                    //拖动
                    window.addEventListener("touchmove", move);
                    window.addEventListener("mousemove", move);
                    //鼠标松开
                    window.addEventListener("touchend", end);
                    window.addEventListener("mouseup", end);
                    //获取元素的绝对位置
                    function getPosition(node) {
                        var left = node.offsetLeft; //获取元素相对于其父元素的left值var left
                        var top = node.offsetTop;
                        current = node.offsetParent; // 取得元素的offsetParent
                          // 一直循环直到根元素
                          
                        while(current != null) {  
                            left += current.offsetLeft;  
                            top += current.offsetTop;  
                            current = current.offsetParent;  
                        }
                        return {
                            "left": left,
                            "top": top
                        };
                    }

                    //减
                    minus.onclick = function(){
                         vals.innerText --;       
                         if(vals.innerText < 0){
                            vals.innerText = 0; 
                         }
                         minDiv_left = vals.innerText/100 * (lineDiv.offsetWidth - 10);
                         minDiv.style.left = minDiv_left + "px";

                    };
                    //加
                    add.onclick = function(){
                         vals.innerText ++;
                         
                         if(vals.innerText >= 100) {
                             vals.innerText = 100;
                         }
                         minDiv_left = vals.innerText/100 * (lineDiv.offsetWidth - 10);
                         minDiv.style.left = minDiv_left + "px";
                    };
             }
           
        </script>
    </body>
</html>

###另一种范围是从-100 ~ 100

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
    <script src="/Scripts/jquery-3.1.1.js"></script>
    <style type="text/css">
        .lineDiv { position: relative; height: 5px; background: #ccc; width: 300px; margin: 50px auto;
        } 
        .lineDiv .minDiv { position: absolute; top: -20px; left: 50%; width: 10px; height: 10px;background: #fff; margin-left: -5px; border: 1px solid #d7000c; border-radius: 50%; cursor: pointer
        }
             
         
    </style>
    </head>
    <body>
        <center>
            <h3>用鼠标拖动小方块<span class="msg">0</span>%</h3>
        </center>
        <div class="measure-drag" style="clear: both; margin: 20px auto;">
            <div class="minus" style="float: left; width: 20px; height: 20px; background: #ccc; cursor: pointer;">-</div>
            <div class="lineDiv" style="float: left;">
                <p class="minDiv">
                    <span class="vals">0</span>
                </p>
            </div>
            <div class="add" style="float: left; width: 20px; height: 20px; background: #ccc; cursor: pointer;">+</div>
        </div>
        <div class="measure-drag" style="clear: both; margin: 20px auto;">
            <div class="minus" style="float: left; width: 20px; height: 20px; background: #ccc; cursor: pointer;">-</div>
            <div class="lineDiv" style="float: left;">
                <p class="minDiv">
                    <span class="vals">0</span>
                </p>
            </div>
            <div class="add" style="float: left; width: 20px; height: 20px; background: #ccc; cursor: pointer;">+</div>
        </div>
        <div class="measure-drag" style="clear: both; margin: 20px auto;">
            <div class="minus" style="float: left; width: 20px; height: 20px; background: #ccc; cursor: pointer;">-</div>
            <div class="lineDiv" style="float: left;">
                <p class="minDiv">
                    <span class="vals">0</span>
                </p>
            </div>
            <div class="add" style="float: left; width: 20px; height: 20px; background: #ccc; cursor: pointer;">+</div>
        </div>
        <div class="measure-drag" style="clear: both; margin: 20px auto;">
            <div class="minus" style="float: left; width: 20px; height: 20px; background: #ccc; cursor: pointer;">-</div>
            <div class="lineDiv" style="float: left;">
                <p class="minDiv">
                    <span class="vals">0</span>
                </p>
            </div>
            <div class="add" style="float: left; width: 20px; height: 20px; background: #ccc; cursor: pointer;">+</div>
        </div>
        
        <script>
           
             $('.measure-drag').each(function(i){
                 drag($('.measure-drag .lineDiv')[i], $('.measure-drag .minDiv')[i], $(".measure-drag .vals")[i], $('.measure-drag .minus')[i], $('.measure-drag .add')[i]);
             });

             function drag(lineDiv, minDiv, vals, minus, add){
                    var msg = $(".msg")[0];
                    /**
                   * lineDiv长线条  minDiv小球  vals小球上的数值,即为所占的比例  minus减 
                       add加
                   */
                    var ifBool = false; //判断鼠标是否按下
                    //事件
                    var start = function(e) {
                        e.stopPropagation();
                        ifBool = true;
                        //console.log("鼠标按下")
                    }
                    var move = function(e) {
                      //  console.log("鼠标拖动")
                        if(ifBool) {
                            if(!e.touches) {    //兼容移动端
                                var x = e.clientX;
                            } else {     //兼容PC端
                                var x = e.touches[0].pageX;
                            }
                            //var x = e.touches[0].pageX || e.clientX; //鼠标横坐标var x
                            var lineDiv_left = getPosition(lineDiv).left; //长线条的横坐标
                            var minDiv_left = x - lineDiv_left; //小方块相对于父元素(长线条)的left值
                            if(minDiv_left >= lineDiv.offsetWidth - 10) {
                                minDiv_left = lineDiv.offsetWidth - 10;
                            }
                            if(minDiv_left < 0) {
                                minDiv_left = 0;
                            }
                            //设置拖动后小方块的left值
                            minDiv.style.left = minDiv_left + "px";
                             msg.innerText =parseInt( (minDiv_left / (lineDiv.offsetWidth - 10)) * 100 * 2 - 100);
                            vals.innerText = parseInt((minDiv_left / (lineDiv.offsetWidth - 10)) * 100 * 2 - 100);     
                        }
                    }
                    var end = function(e) {
                           // console.log("鼠标弹起")
                            ifBool = false;
                        }
                        //鼠标按下方块
                    minDiv.addEventListener("touchstart", start);
                    minDiv.addEventListener("mousedown", start);
                    //拖动
                    window.addEventListener("touchmove", move);
                    window.addEventListener("mousemove", move);
                    //鼠标松开
                    window.addEventListener("touchend", end);
                    window.addEventListener("mouseup", end);
                    //获取元素的绝对位置
                    function getPosition(node) {
                        var left = node.offsetLeft; //获取元素相对于其父元素的left值var left
                        var top = node.offsetTop;
                        current = node.offsetParent; // 取得元素的offsetParent
                          // 一直循环直到根元素
                          
                        while(current != null) {  
                            left += current.offsetLeft;  
                            top += current.offsetTop;  
                            current = current.offsetParent;  
                        }
                        return {
                            "left": left,
                            "top": top
                        };
                    }

                    minus.onclick = function(){
                         vals.innerText --;
                         
                         if(vals.innerText < -100){
                            vals.innerText = -100; 
                         }
                         console.log(lineDiv.offsetWidth);
                         console.log(vals.innerText);

                         minDiv_left = (parseInt(vals.innerText) + 100)/200 * (lineDiv.offsetWidth - 10);
                         minDiv.style.left = minDiv_left + "px";
                         //vals.innerText = parseInt((minDiv_left / (lineDiv.offsetWidth - 10)) * 100);

                    };
                    add.onclick = function(){
                         vals.innerText ++;
                         
                         if(vals.innerText >= 100) {
                             vals.innerText = 100;
                         }

                         minDiv_left = (parseInt(vals.innerText) + 100)/200 * (lineDiv.offsetWidth - 10);
                         minDiv.style.left = minDiv_left + "px";
                         //vals.innerText = a;

                    };
             }
        </script>
    </body>
</html>

image.png

echarts关于图例点击,图的点击

删除图例legend的默认事件,点击变灰色

legend: {
  selectedMode: false
}

点击图的事件

在chart中添加 @click="handleEchart"

handleEchart (e) {
  console.log(e)
}

uni-app echart 使用mpvueEcharts踩坑与流程

同一个页面上引入两个图标

<view class="echart-container">
 <mpvue-echarts canvasId="chatSettled" ref="pieChart1" :echarts="echarts" @onInit="init10Chart" />
</view>
 
<view class="echart-container">
 <mpvue-echarts canvasId="chatOrder" ref="pieChart2" :echarts="echarts" @onInit="init20Chart" />
</view>

如果有两个echart图一定要把参数写成不一样的,比如canvasId等

在限定的范围内,画区域,地址是可以搜索

高德地图自带的,根据用户输入的地址,进行模糊搜索,用户进行选择定位,根据用户输入的半径进行范围限定
vue以及element-ui实现的

限定区域

页面:

<div class="delivery-scope" v-show="range === '2'">
      <div id="location"></div>
      <div class="search">
        <el-input
          id="tip-input"
          size="small"
          class="search-input"
          placeholder="请输入选择地址"
          prefix-icon="el-icon-search"
          v-model="address"
          :clearable="true"
          @input="mapLocation"
        >
        </el-input>
        <ul class="list" v-show="searchMsg">
          <li v-for="(item, index) in list" :key="index" @click="selectAddress(item)">{{item.name}}</li>
        </ul>
      </div>
      <div class="radius">
        以选择的中心点为中心,半径
        <el-input
          size="small"
          class="search-input"
          placeholder="请输入区域半径"
          prefix-icon="el-icon-search"
          v-model="radius"
          :clearable="true"
        >
        </el-input>
        m
      </div>
</div>

css,没给完全,只有下拉框部分的

#location {
  width: 100%;
  height: 100%;
  margin-top: 50px;
}
.search {
  position: absolute;
  left: 10px;
  top: -40px;
  .el-input {
    width: 400px;
  }
  .list {
    width: 380px;
    // height: 300px;
    background: #ffffff;
    padding: 0 10px;
    color: #333;
    font-size: 14px;
  }
  li {
    line-height: 40px;
    cursor: pointer;
  }
}

js

data () {
    return {
      mapKey: '', // 地图密钥
      address: '', // 地址
      list: [], // 下拉框
      searchMsg: false, // 下拉框显示隐藏
      radius: '', // 半径
      selectData: {}, // 存储选中的值
      lnglat: {}, // 记录上次的经纬度
    }
 },
async mounted () {
    await MP (this.mapKey)
    this.map()
},
methods: {
  selectAddress (val) {
      this.selectData = val
      this.address = `${val.district}${val.name}`
      this.searchMsg = false
      this.map({
        center: [val.location.lng, val.location.lat]
      })
      if (JSON.stringify(this.lnglat) !== '{}') {
        this.mark('remove', this.lnglat)
      }
      this.lnglat = val.location
      this.mark('add', val.location)
    },
    map (params) {
      map = new AMap.Map('location', {
        ...params,
	    resizeEnable: true,
        zoom: 14
      })
    },
    mapLocation () {
      map.plugin(['AMap.Autocomplete', 'AMap.PlaceSearch'], () => {
        // 实例化Autocomplete
        var autoOptions = {
          city: '全国'
        }
        let autoComplete = new AMap.Autocomplete(autoOptions)
        autoComplete.search(this.address, (status, result) => {
          if (result && result.info === 'OK') {
            this.list = result.tips
            this.searchMsg = true
            this.placeSearch(this.list.length && this.list[0].name)
          }
        })
      })
    },
    placeSearch (value) {
      let placeSearch = new AMap.PlaceSearch({
        city: '全国',
        map: map
      })
      placeSearch.search(value)
    },
    // 自己添加一个按钮,进行设置限制范围的操作
    set () {
      if (circle) {
        circle.setMap(null)
      }
      circle = new AMap.Circle({
        center: new AMap.LngLat(this.selectData.location.lng, this.selectData.location.lat),  // 圆心位置
        radius: this.radius, // 圆半径
        borderWeight: 3,
        strokeColor: "#FF33FF", 
        strokeOpacity: 1,
        strokeWeight: 6,
        strokeOpacity: 0.2,
        fillOpacity: 0.4,
        strokeStyle: 'dashed',
        strokeDasharray: [10, 10], 
        // 线样式还支持 'dashed'
        fillColor: '#1791fc',
        zIndex: 50
      })
      circle.setMap(map)
      map.setFitView([circle])
    },
   // 添加标记
    mark (type, value) {
      if (type === 'remove') {
        return map.remove(marker)
      }
      marker = new AMap.Marker({
        position: new AMap.LngLat(value.lng, value.lat),
        title: '北京'
      })
      map.add(marker)
    },
}

swiper 绑定点击事件 点击失效处理

在引用swiper这个库的时候,一旦设置 loop:true 的时候,会遇到 dom 绑定事件无法触发的问题。
click 点击事件有时候无任何反应,并且这种情况必现,swiper会进行复制
var mySwiper = new Swiper('.swiper-container', {
	    autoplay: true, //可选选项,自动滑动
            loop: true,
            pagination: {
                el: '.swiper-pagination',
            },
            on: {
                click: function () {
                    var realIndex = this.realIndex;
                    _this.handleClickSlide(realIndex);
                }
            }
        })
function handleClickSlide (index) {
   console.log(index)
}
要找到具体点击 哪一个

加载地图

创建的时候,加载js的文件

export default function MP (key) {
  const JS1 = new Promise(function (resolve, reject) {
    window.onload = function () {
      resolve(window.AMap)
    }
    let script = document.createElement('script')
    script.type = 'text/javascript'
    script.src = 'https://webapi.amap.com/maps?v=1.4.6&key=' + key + '&callback=onload'
    script.onerror = reject
    document.head.appendChild(script)
  })
  const JS2 = new Promise(function (resolve, reject) {
    let script2 = document.createElement('script')
    script2.type = 'text/javascript'
    script2.src = 'https://webapi.amap.com/ui/1.0/main-async.js'
    script2.onerror = reject
    script2.onload = function () {
      resolve('success')
    }
    document.head.appendChild(script2)
  })
  return Promise.all([JS1, JS2]).then(function (result) {
    return result[0]
  }).catch(e => {
    console.log(e)
  })
}

使用vue, mounted加载,MP是引入上面的函数

async mounted () {
    await MP ('这是你的地图key')
},

fabric.js自己设置的

customerControl.js

/*
 * fabric.js Controls Extension
 * for fabric.js current build
 * Simon Kunz 09.02.2016 for pixolith
 * Licensed under the MIT license.
 */

'use strict';
(function(window) {
    var fabric = window.fabric || ( window.fabric = {} ),
        minExtCompat = '1.6.0',
        isVML = function() {
            return typeof G_vmlCanvasManager !== 'undefined';
        },
        degreesToRadians = fabric.util.degreesToRadians,
        cursorOffset = {
            mt: 0, // n
            tr: 1, // ne
            mr: 2, // e
            br: 3, // se
            mb: 4, // s
            bl: 5, // sw
            ml: 6, // w
            tl: 7 // nw
        };

    if (minExtCompat.localeCompare(window.fabric.version) > -1) {
        console.warn('this extension might not be fully compatible with your version ' +
            'of fabric.js (' + window.fabric.version + ').' +
            'Consider using the latest compatible build of fabric.js (> ' + minExtCompat + ')'
        );
    }

    fabric.util.object.extend(fabric.Object.prototype, {

        /**
         * When true, image icons are loaded via the drawImage method
         * @type Boolean
         * @default false
         */

        useCustomIcons: false,

        /**
         * Sets a background-color for drawImage operations with transparency
         * @type string
         * @default transparent
         */

        cornerBackgroundColor: 'transparent',

        /**
         * Sets the shape of the background for drawImage operations with transparency
         * @type string
         * @default rect
         */

        cornerShape: '',

        /**
         * Inner Padding between Shape Background and drawn Image
         * @type int
         * @default rect
         */

        cornerPadding: 0,

        /**
         * Set a custom corner icon
         * @param {Object} obj settings and icon url.
         * @param callback function
         */

        customiseCornerIcons: function(obj, callback) {
            var setting,
                cornerConfig;

            for (setting in obj) {
                if (obj.hasOwnProperty(setting)) {

                    cornerConfig = {};

                    if (obj[setting].cornerShape !== undefined) {
                        this.cornerShape = obj[setting].cornerShape;
                    }

                    if (obj[setting].cornerBackgroundColor !== undefined) {
                        this.cornerBackgroundColor = obj[setting].cornerBackgroundColor;
                    }

                    if (obj[setting].borderColor !== undefined) {
                        this.borderColor = obj[setting].borderColor;
                    }

                    if (obj[setting].cornerSize !== undefined) {
                        this.cornerSize = obj[setting].cornerSize;
                    }

                    if (obj[setting].cornerPadding !== undefined) {
                        this.cornerPadding = obj[setting].cornerPadding;
                    }

                    if (obj[setting].icon !== undefined || Object.keys(obj)[0] === 'settings') {
                        this.useCustomIcons = true;

                        if (obj[setting].settings !== undefined) {
                            cornerConfig.settings = obj[setting].settings;
                        }

                        if (obj[setting].icon !== undefined) {
                            cornerConfig.icon = obj[setting].icon;

                            this.loadIcon(setting, cornerConfig, function() {
                                if (callback && typeof( callback ) === 'function') {
                                    callback();
                                }
                            });
                        }
                    }
                }
            }
        },

        /**
         * loads the icon image as an image src.
         * @param {Object} corner to load an icon.
         * @param cornerConfig as object containing icon url and corner specific settings
         * @param callback function.
         */

        loadIcon: function(corner, cornerConfig, callback) {
            var self = this,
                icon = new Image();

            icon.onload = function() {
                self[corner + 'Icon'] = this;

                if (cornerConfig.settings) {
                    self[corner + 'Settings'] = cornerConfig.settings;
                }

                if (callback && typeof( callback ) === 'function') {
                    callback();
                }
            };

            icon.onerror = function() {
                fabric.warn(this.src + ' icon is not an image');
            };

            if (cornerConfig.icon.match(/^http[s]?:\/\//) || cornerConfig.icon.substring(0, 2) === '//') {
                icon.crossOrigin = 'Anonymous';
            }

            icon.src = cornerConfig.icon;
        },

        /**
         * copy of the setter method for our american friends.
         * @param {Object} obj containing corner icon urls and settings.
         */

        customizeCornerIcons: function(obj) {
            this.customiseCornerIcons(obj);
        },

        /**
         * Draws corners of an object's bounding box.
         * Requires public properties: width, height
         * Requires public options: cornerSize, padding
         * @param {CanvasRenderingContext2D} ctx Context to draw on
         * @return {fabric.Object} thisArg
         * @chainable
         */

        drawControls: function(ctx) {

            if (!this.hasControls) {
                return this;
            }

            var wh = this._calculateCurrentDimensions(),
                width = wh.x,
                height = wh.y,
                scaleOffset = this.cornerSize,
                left = -(width + scaleOffset) / 2,
                top = -(height + scaleOffset) / 2,
                methodName;

            if (!this.useCustomIcons) {
                ctx.lineWidth = 1;
                ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
                ctx.strokeStyle = ctx.fillStyle = this.cornerColor;

                if (!this.transparentCorners) {
                    ctx.strokeStyle = this.cornerStrokeColor;
                }

                methodName = this.transparentCorners ? 'stroke' : 'fill';
            } else {
                methodName = 'drawImage';
            }

            ctx.save();
           // this._setLineDash(ctx, this.cornerDashArray, null);

            // top-left
            this._drawControl('tl', ctx, methodName,
                left,
                top,
                this.tlIcon,
                this.tlSettings
            );

            // top-right
            this._drawControl('tr', ctx, methodName,
                left + width,
                top,
                this.trIcon,
                this.trSettings
            );

            // bottom-left
            this._drawControl('bl', ctx, methodName,
                left,
                top + height,
                this.blIcon,
                this.blSettings
            );

            // bottom-right
            this._drawControl('br', ctx, methodName,
                left + width,
                top + height,
                this.brIcon,
                this.brSettings
            );

            if (!this.get('lockUniScaling')) {

                // middle-top
                /*this._drawControl('mt', ctx, methodName,
                    left + width / 2,
                    top,
                    this.mtIcon,
                    this.mtSettings
                );*/

                // middle-bottom
              /*  this._drawControl('mb', ctx, methodName,
                    left + width / 2,
                    top + height,
                    this.mbIcon,
                    this.mbSettings
                );*/

                // middle-right
                /*this._drawControl('mr', ctx, methodName,
                    left + width,
                    top + height / 2,
                    this.mrIcon,
                    this.mrSettings
                );
*/
                // middle-left
                /* this._drawControl('ml', ctx, methodName,
                     left,
                     top + height / 2,
                     this.mlIcon,
                     this.mlSettings
                 );*/
            }

            // middle-top-rotate
            if (this.hasRotatingPoint) {
               /* this._drawControl('mtr', ctx, methodName,
                    left + width / 2,
                    top - this.rotatingPointOffset,
                    this.mtrIcon,
                    this.mtrSettings
                );*/
            }

            ctx.restore();

            return this;
        },

        /** Draw controls either with background-shape and color (transparency) or plain image (modified core method)
         * @private
         * {string} icon url of the control
         */

        _drawControl: function(control, ctx, methodName, left, top, icon, settings) {
            if (!this.isControlVisible(control)) {
                return;
            }

            var size = this.cornerSize,
                cornerStroke = this.cornerStrokeColor || 'transparent',
                cornerBG = this.cornerBackgroundColor || 'black',
                cornerShape = this.cornerShape || 'rect',
                cornerPadding = this.cornerPadding || 10;

            if (settings) {
                if (settings.cornerSize) {
                    // Set the size, and also recalc left and top
                    left = left + size / 2 - settings.cornerSize / 2;
                    top = top + size / 2 - settings.cornerSize / 2;
                    size = settings.cornerSize;
                }
                cornerShape = settings.cornerShape || cornerShape;
                cornerBG = settings.cornerBackgroundColor || cornerBG;
                cornerPadding = settings.cornerPadding || cornerPadding;
                cornerStroke = settings.cornerStrokeColor || cornerStroke;
            }

            if (this.useCustomIcons) {
                if (cornerShape) {
                    ctx.globalAlpha = 1;
                    ctx.fillStyle = cornerBG;
                    ctx.lineWidth = 1;
                    ctx.strokeStyle = cornerStroke;
                    switch (cornerShape) {
                        case 'rect':
                            ctx.fillRect(left, top, size, size);

                            if (cornerStroke) {
                                ctx.strokeRect(left, top, size, size);
                            }

                            break;
                        case 'circle':
                            ctx.beginPath();
                            ctx.arc(left + size / 2, top + size / 2, size / 2, 0, 2 * Math.PI);
                            ctx.fill();

                            if (cornerStroke) {
                                ctx.stroke();
                            }

                            ctx.closePath();
                            break;
                    }

                    if (icon !== undefined) {
                        ctx[methodName](
                            icon,
                            left + cornerPadding / 2,
                            top + cornerPadding / 2,
                            size - cornerPadding,
                            size - cornerPadding
                        );
                    }

                } else {
                    if (icon !== undefined) {
                        ctx[methodName](
                            icon,
                            left,
                            top,
                            size,
                            size
                        );
                    }
                }
            } else {
                isVML() || this.transparentCorners || ctx.clearRect(left, top, size, size);
                ctx[methodName + 'Rect'](left, top, size, size);
                if (!this.transparentCorners && cornerStroke) {
                    ctx.strokeRect(left, top, size, size);
                }
            }

        },
    });

    fabric.util.object.extend(fabric.Canvas.prototype, {
        /**
         * When true, actions can be overwritten
         * @type Boolean
         * @default false
         */

        overwriteActions: false,

        /**
         * When true, cursors are fixed
         * @type Boolean
         * @default false
         */

        fixedCursors: false,

        /**
         * setter Method for actions and cursors.
         * @param {Object} obj containing corner action and cursor url/type.
         */

        customiseControls: function(obj) {
            var setting;

            for (setting in obj) {
                if (obj.hasOwnProperty(setting)) {
                    if (obj[setting].action !== undefined) {
                        this.overwriteActions = true;
                        this.setCustomAction(setting, obj[setting].action);
                    }

                    if (obj[setting].cursor !== undefined) {
                        this.fixedCursors = true;
                        this.setCustomCursor(setting, obj[setting].cursor);
                    }
                }
            }
        },

        /**
         * loads the icon image as an image src.
         * @param {Object} corner to load an icon.
         * @param action as a string.
         */

        setCustomAction: function(corner, action) {
            this[corner + 'Action'] = action;
        },

        /**
         * loads the icon image as an image src.
         * @param {Object} corner to load an icon.
         * @param cursorUrl as a string.
         */

        setCustomCursor: function(corner, cursorUrl) {
            this[corner + 'cursorIcon'] = cursorUrl;
        },

        /**
         * copy of the setter method for our american friends.
         * @param {Object} obj containing corner action and cursor url/type.
         */

        customizeControls: function(obj) {
            this.customiseControls(obj);
        },

        /**
         * @private
         */

        _getActionFromCorner: function(target, corner, e) {
            if (!corner) {
                return 'drag';
            }

            if (corner) {
                if (this[corner + 'Action'] && this.overwriteActions) {
                    switch (corner) {
                        //case 'mtr':
                          //  return this[corner + 'Action'] || 'rotate';
                        case 'ml':
                        case 'mr':
                            if (e[this.altActionKey]) {
                                return e[this.altActionKey] ? 'skewY' : 'scaleX';
                            }
                            return this[corner + 'Action'];
                        case 'mt':
                        case 'mb':
                            if (e[this.altActionKey]) {
                                return e[this.altActionKey] ? 'skewY' : 'scaleY';
                            }
                            return this[corner + 'Action'];
                        default:
                            return this[corner + 'Action'] || 'scale';
                    }
                } else {
                    switch (corner) {
                      //  case 'mtr':
                          //  return 'rotate';
                        case 'ml':
                        case 'mr':
                            return e[this.altActionKey] ? 'skewY' : 'scaleX';
                        case 'mt':
                        case 'mb':
                            return e[this.altActionKey] ? 'skewX' : 'scaleY';
                        default:
                            return 'scale';
                    }
                }
            }

            return false;
        },

        /**
         * @private
         * @param {Event} e Event object
         * @param {fabric.Object} target
         */
        _setupCurrentTransform: function(e, target) {
            if (!target) {
                return;
            }

            var pointer = this.getPointer(e),
                corner = target._findTargetCorner(this.getPointer(e, true)),
                action = this._getActionFromCorner(target, corner, e),
                origin = this._getOriginFromCorner(target, corner);

            if (typeof action === 'function') {
                action.call(this, e, target);

                // as of fabric 1.7.11 object cache will try to slice the action to check for scale so we need to convert this to a string
                action = 'void';
            }

            this._currentTransform = {
                target: target,
                action: action,
                corner: corner,
                scaleX: target.scaleX,
                scaleY: target.scaleY,
                skewX: target.skewX,
                skewY: target.skewY,
                offsetX: pointer.x - target.left,
                offsetY: pointer.y - target.top,
                originX: origin.x,
                originY: origin.y,
                ex: pointer.x,
                ey: pointer.y,
                lastX: pointer.x,
                lastY: pointer.y,
                left: target.left,
                top: target.top,
                theta: degreesToRadians(target.angle),
                width: target.width * target.scaleX,
                mouseXSign: 1,
                mouseYSign: 1,
                shiftKey: e.shiftKey,
                altKey: e[this.centeredKey],
            };

            this._currentTransform.original = {
                left: target.left,
                top: target.top,
                scaleX: target.scaleX,
                scaleY: target.scaleY,
                skewX: target.skewX,
                skewY: target.skewY,
                originX: origin.x,
                originY: origin.y,
            };

            if (action === 'remove') {
                this._removeAction(e, target);
            }

            if (action === 'moveUp') {
                this._moveLayerUpAction(e, target);
            }

            if (action === 'moveDown') {
                this._moveLayerDownAction(e, target);
            }

            if (typeof action === 'object') {
                if (Object.keys(action)[0] === 'rotateByDegrees') {
                    this._rotateByDegrees(e, target, action.rotateByDegrees);
                }
            }

            this._resetCurrentTransform();
        },

        /**
         * Custom remove object action
         * @private
         * @param {Event} e Event object
         * @param {fabric.Object} target
         */

        _removeAction: function(e, target) {
            var _this = this;
            if (this.getActiveGroup() && this.getActiveGroup() !== 'undefined') {
                this.getActiveGroup().forEachObject(function(o) {
                    o.off();
                    o.remove();
                });
                this.discardActiveGroup();

                // as of fabric 1.6.3 necessary for reasons..
                setTimeout(function() {
                    _this.deactivateAll();
                }, 0);

            } else {
                target.off();
                target.remove();

                setTimeout(function() {
                    _this.deactivateAll();
                }, 0);
            }
        },

        /**
         * Custom move up object action
         * @private
         * @param {Event} e Event object
         * @param {fabric.Object} target
         */

        _moveLayerUpAction: function(e, target) {
            if (this.getActiveGroup() && this.getActiveGroup() !== 'undefined') {
                this.getActiveGroup().forEachObject(function(o) {
                    o.bringForward();
                });
            } else {
                target.bringForward();
            }
        },

        /**
         * Custom move down object action
         * @private
         * @param {Event} e Event object
         * @param {fabric.Object} target
         */

        _moveLayerDownAction: function(e, target) {
            if (this.getActiveGroup() && this.getActiveGroup() !== 'undefined') {
                this.getActiveGroup().forEachObject(function(o) {
                    o.sendBackwards();
                });
            } else {
                target.sendBackwards();
            }
        },

        /**
         * Custom move down object action
         * @private
         * @param {Event} e Event object
         * @param {fabric.Object} target
         * @param {Integer} value of rotation
         */

        _rotateByDegrees: function(e, target, value) {
            var angle = parseInt(target.getAngle()) + value,
                needsOriginRestore = false;

            if (( target.originX !== 'center' || target.originY !== 'center' ) && target.centeredRotation) {
                this._setOriginToCenter(target);
                needsOriginRestore = true;
            }

            angle = angle > 360 ? angle - 360 : angle;

            if (this.getActiveGroup() && this.getActiveGroup() !== 'undefined') {
                this.getActiveGroup().forEachObject(function(obj) {
                    obj
                        .setAngle(angle)
                        .setCoords();
                });
            } else {
                target
                    .setAngle(angle)
                    .setCoords();
            }

            if (needsOriginRestore) {
                this._setCenterToOrigin(target);
            }

            this.renderAll();
        },

        /**
         * Sets either the standard behaviour cursors or if fixedCursors is true, tries to set a custom cursor
         * either by using an icon or a build-in cursor. Cursor icon extensions are matched with a regular expression.
         * @private
         * {string} corner name
         * {target} event handler of the hovered corner
         */
        _setCornerCursor: function(corner, target, e) {
            var iconUrlPattern = /\.(?:jpe?g|png|gif|jpg|jpeg|svg)$/;

            if (this.fixedCursors && this[corner + 'cursorIcon']) {
                if (this[corner + 'cursorIcon'].match(iconUrlPattern)) {
                    this.setCursor('url(' + this[corner + 'cursorIcon'] + '), auto');
                } else {
                    if (this[corner + 'cursorIcon'] === 'resize') {
                        this.setCursor(this._getRotatedCornerCursor(corner, target, e));
                    } else {
                        this.setCursor(this[corner + 'cursorIcon']);
                    }
                }
            } else {
                if (corner in cursorOffset) {
                    this.setCursor(this._getRotatedCornerCursor(corner, target, e));
                } else if (corner === 'mtr' && target.hasRotatingPoint) {
                    this.setCursor(this.rotationCursor);
                } else {
                    this.setCursor(this.defaultCursor);
                    return false;
                }
            }

            return false;
        },
    });

    if (typeof exports !== 'undefined') {
        module.exports = this;
    }

})(window);

添加四角图片及四角的作用

fabric.Canvas.prototype.customiseControls({
         settings: {
                cornerSize: 32,
                borderColor: '#05121c'
        },
        tr: {
            action: 'remove',
            cursor: 'pointer'
        },
        br: {
            action: 'scale',
            cursor: 'pointer'
        },
        tl: {
            action: 'rotate',
            cursor: 'pointer'
        },
        bl: {
            action: '',
            cursor: 'pointer'
        }
    });
    fabric.Object.prototype.customiseCornerIcons({
        tl: {
            icon: '../images/details/icons/icon_rotate.png'
        },
        br: {
            icon: '../images/details/icons/icon_escal.png'
        },
        tr: {
            icon: '../images/details/icons/icon_remove.png'
        },
        bl: {
            icon: '../images/details/icons/icon_mover.png'
        }
    }, function () {
        canvas.renderAll();
    });

这是为了选中后又重新渲染后,点击每一个图片还会被选中(就是添加四角)


    //设置item的四角矩形及是否有旋转
    function setRotate(item) {
        item.set('hasRotatingPoint', false);
        item.customiseCornerIcons({
            settings: {
                borderColor: '#061101',
                cornerSize: 32,
                cornerShape: 'rect',
                cornerPadding: 10
            },
            tl: {
                icon: '../images/details/icons/icon_rotate2.png'
            },
            br: {
                icon: '../images/details/icons/icon_escal2.png'
            },
            tr: {
                icon: '../images/details/icons/icon_remove2.png'
            },
            bl: {
                icon: '../images/details/icons/icon_mover2.png'
            }
        }, function () {
            canvas.renderAll();
        });
    }

控制绘画区域的鼠标移入移出,以及选中元素删除进行的操作

//控制绘画区域的鼠标移入移出,以及选中元素删除进行的操作
    canvas.on('mouse:over', function (options) {
       
    });
    canvas.on('mouse:out', function (options) {
      
    });
    canvas.on('object:removed', function (item) {
      
    })

选中某个(图片、文字)时进行操作

 //选中某个(图片、文字)时进行操作
    canvas.on('object:selected', function (e) {
        $.each(canvas.getObjects(), function (m, item) {
            for (var n in item) {
                if (n == 'active' && item[n] == true) {
                    if (item.active == true) {
                        setRotate(item);//设置item的四角矩形及是否有旋转
                        if ($('#view').css('backgroundColor') == 'rgba(0, 0, 0, 0)') {
                            item.set('borderColor', '#303030');
                            canvas.renderAll();
                        } else {
                            judgeBorderColor($('#view').css('backgroundColor'), item);
                            canvas.renderAll();
                        }
                        //判断当前选中的在哪个tab中
                        $(this)[0].text ? tabGet(2) : null;
                        $(this)[0].paths ? (item.flag == 1 ? tabGet(0) : tabGet(1)) : null;
                        $(this)[0].filters ? tabGet(3) : null;

                        //getPrice();
                        $('#dis-text').val(item.text);  //设置文字输入框的值
                        _this = item;
                        //选择字体
                        $('.sel-font').on('change', function (e) {
                            _this.fontFamily = $(this).val();
                            canvas.renderAll();
                        });
                        $('#dis-text').on('keyup', function (e) {
                            _this.text = e.target.value;
                            canvas.renderAll();
                        });

                        selColor('#picker2'); //选择字体的颜色
                        selColor('#picker'); //选择图片二的颜色
                        selColor('#picker5'); //选择图片一的颜色

                        //选中字体工具的图片
                        $('.font-tools img').each(function (n) {
                            $(this).on('mousedown', function (e) {
                                n < 3 ? _this.textAlign = fontToolsImg[n] : null;
                                n == 3 ? (_this.fontWeight = _this.fontWeight == 'normal' ? fontToolsImg[n] : 'normal') : null;
                                n == 4 ? (_this.fontStyle = _this.fontStyle != fontToolsImg[n] ? _this.fontStyle = fontToolsImg[n] : 'normal') : null;
                                canvas.renderAll();
                            });
                        });

                        //按delete键可以删除
                        document.onkeydown = function (event) {
                            var e = event || window.event || arguments.callee.caller.arguments[0];
                            if (e && e.keyCode == 46) {
                                canvas.remove(_this);  //删除
                                canvas.renderAll();
                            }
                        };
                    } else {
                        return false;
                    }
                }
            }
        });

    });
var getElementCanvas = (function () {
    var fontFamily = ['宋体','Bookshelf Symbol 7', 'Calibri', 'Cambria', 'Cambria Math', 'Consolas', 'Georgia', 'HoloLens MDL2 Assets', 'Microsoft YaHei UI', 'MS Outlook', 'MS Reference Specialty', 'MT Extra', 'Segoe MDL2 Assets', 'Segoe UI Emoji', 'Segoe UI Symbol', 'SimSun-ExtB', 'Symbol', 'Verdana', 'Webdings', 'Wingdings', 'Wingdings 2', 'Wingdings 3', '等线', '方正兰亭超细黑简体', '方正舒体', '方正姚体', '仿宋', '黑体', '华文彩云', '华文仿宋', '华文行楷', '华文琥珀', '华文楷体', '华文隶书', '华文宋体', '华文细黑', '华文新魏', '华文中宋', '楷体', '隶书',  '微软雅黑', '新宋体', '幼圆'];
    var fontToolsImg = ['left', 'center', 'right', 'bold', 'italic'];
    //添加字体
    $.each(fontFamily, function (i) {
        $('.sel-font').append('<option>' + fontFamily[i] + '</option>');
    });

    //装饰品鼠标滑动的切换
    $('.dec-select li').on('mouseover', function () {
        $('.dec-select li').removeClass('activeTab');
        $(this).addClass('activeTab');
        $('.dec-content li').addClass('dis');
        $('.dec-content li').eq($(this).index()).removeClass('dis');
    });

    //将图片添加到衣服上
    var canvas = this.__canvas = new fabric.Canvas('design-border');
    fabric.Canvas.prototype.customiseControls({
        tr: {
            action: 'remove',
            cursor: 'pointer'
        },
        br: {
            action: 'scale',
            cursor: 'pointer'
        },
        tl: {
            action: 'rotate',
            cursor: 'pointer'
        },
        bl: {
            action: '',
            cursor: 'pointer'
        }
    });
    fabric.Object.prototype.customiseCornerIcons({
        tl: {
            icon: '../images/details/icons/icon_rotate2.png'
        },
        br: {
            icon: '../images/details/icons/icon_escal2.png'
        },
        tr: {
            icon: '../images/details/icons/icon_remove2.png'
        },
        bl: {
            icon: '../images/details/icons/icon_mover2.png'
        }
    }, function () {
        canvas.renderAll();
    });

    //添加四角矩形框,判断是否进行删除
    function setPic(obj, isDelete) {
        obj.customiseCornerIcons({
            settings: {
                cornerSize: 32,
                borderColor: '#05121c'
            },
            tl: {
                icon: '../images/details/icons/icon_rotate2.png'
            },
            br: {
                icon: '../images/details/icons/icon_escal2.png'
            },
            tr: {
                icon: '../images/details/icons/icon_remove2.png'
            },
            bl: {
                icon: '../images/details/icons/icon_mover2.png'
            }

        }, function () {
            canvas.renderAll();
        });
        canvas.add(obj);
        canvas.setActiveObject(obj);
        if (isDelete) {
            var arr = canvas.getObjects();
            var obj = arr[canvas.getObjects().length - 1];
            canvas.remove(obj);
            if ($('.design-border-blue').css('display') == 'block') {
                $('.design-border-blue').css('display', 'none');
            }
        }
    }

    //将图片添加到衣服上
    function addImg(element, imgInstance, num) {
        for (var n = 0; n < element.length; n++) {
            (function (n) {
                element[n].onclick = function () {
                    if ($('.design-border-blue').css('display') == 'none') {
                        $('.design-border-blue').css('display', 'block');
                    }
                    fabric.loadSVGFromURL(element[n]['src'], function (objects, options) {
                        imgInstance[n] = fabric.util.groupSVGElements(objects, options);
                        if (options.width >= options.height) {
                            imgInstance[n].scale(100 / options.width);
                        }else {
                            imgInstance[n].scale(100 / options.height);
                        }
                        imgInstance[n].set({
                            left: 80,
                            top: 100,
                            fill: '#000000',
                            originX: 'center',
                            originY: 'center',
                            hasRotatingPoint: false,
                            flag: num,
                            id: element[n].getAttribute("data-id"),
                            price: element[n].getAttribute('data-pri')
                        });
                        
                        setPic(imgInstance[n]);
                    });
                    /*if (element[n]['src'].indexOf('.svg') > 0) {
                    } else {
                        var img = new fabric.Image(element[n]['src'], {
                                left: 100,
                                top: 150,
                                scale: 6.8,
                                originX: 'center',
                                originY: 'center',
                                hasRotatingPoint: false
                        });
                        setPic(img);
                    } */


                }
            })(n);
        }
    }


    //将文字添加到衣服上
    var txt = $('#dis-text');
    var txtInstance = null;
    $('.design-btn-font').on('click', function () {
        if ($('.design-border-blue').css('display') == 'none') {
            $('.design-border-blue').css('display', 'block');
        }
        txtInstance = new fabric.IText(txt.val(), {
            left: 80,
            top: 100,
            fontFamily: 'Comic Sans',
            fontSize: 20,
            fill: '#000000',
            //id: 'addText',
            originX: 'center',
            originY: 'center',
            hasRotatingPoint: false
        });
        setPic(txtInstance);
    });
    //上传添加图片
    var uploader = WebUploader.create({
        // 选完文件后,是否自动上传。
        auto: true,
        // swf文件路径
        swf: '../js/Uploader.swf',
        // 文件接收服务端。
        server: 'http://webuploader.duapp.com/server/fileupload.php',
        // 选择文件的按钮。可选。
        // 内部根据当前运行是创建,可能是input元素,也可能是flash.
        pick: '#filePicker',
        // 只允许选择图片文件。
        accept: {
            title: 'Images',
            extensions: 'gif,jpg,jpeg,bmp,png',
            mimeTypes: 'image/*'
        },
        resize: false,
        compress: false,
        thumb: {
            allowMagnify: false,
            crop: false,
            type: ''   // 这样会保证png格式的透明背景不会变成黑色
        }
    });
    var oImg = null;
    // 当有文件添加进来的时候
    uploader.on('fileQueued', function (file) {
        var $li = $(
            '<div id="' + file.id + '" class="file-item thumbnail">' +
            '<img>' +
           // '<div class="info">' + file.name + '</div>' +
            '</div>'
            ),
            $img = $li.find('img');
        // $list为容器jQuery实例
        $('#fileList').append($li);
        // 创建缩略图
        // 如果为非图片文件,可以不用调用此方法。
        // thumbnailWidth x thumbnailHeight 为 100 x 100
        uploader.makeThumb(file, function (error, src) {
            if (error) {
                $img.replaceWith('<span>不能预览</span>');
                return;
            }
            $img.attr('src', src);
            //设置图片,将其显示在4*4的框中
            var w = parseInt(file._info.width);
            var h = parseInt(file._info.height);
            var r = w / h;
            if (w <= h) {
                $img.css({ 'width': 3.26 * r + 'rem', 'height': '3.26rem', 'marginLeft': (3.26 - 3.26 * r) / 2 + 'rem' });
            } else {
                $img.css({ 'width': '3.26rem', 'height': 3.26 / r + 'rem', 'marginTop': (3.26 - 3.26 / r) / 2 + 'rem' });
            }

        }, 1500, 1500);
    });
    uploader.on('filesQueued', function () {
        $('#fileList img').each(function (j, item) {
            $(this).unbind('click').on('click', function () {
                oImg = new fabric.Image(item, {
                    left: 80,
                    top: 110,
                    originX: 'center',
                    originY: 'center',
                    hasRotatingPoint: false
                });
                setPic(oImg);
            });
        });
    });

    // 文件上传过程中创建进度条实时显示。
    /* uploader.on('uploadProgress', function (file, percentage) {
        var $li = $('#' + file.id),
            $percent = $li.find('.progress span');

        // 避免重复创建
        if (!$percent.length) {
            $percent = $('<p class="progress"><span></span></p>')
                .appendTo($li)
                .find('span');
        }

        $percent.css('width', percentage * 100 + '%');
    });*/

    /*// 文件上传成功,给item添加成功class, 用样式标记上传成功。
    uploader.on( 'uploadSuccess', function( file ) {
        $( '#'+file.id ).addClass('upload-state-done');
    });

    // 文件上传失败,显示上传出错。
    uploader.on( 'uploadError', function( file ) {
        var $li = $( '#'+file.id ),
            $error = $li.find('div.error');

        // 避免重复创建
        if ( !$error.length ) {
            $error = $('<div class="error"></div>').appendTo( $li );
        }

        $error.text('上传失败');
    });
    // 完成上传完了,成功或者失败,先删除进度条。
    uploader.on( 'uploadComplete', function( file ) {
        $( '#'+file.id ).find('.progress').remove();
    });*/

    //设置item的四角矩形及是否有旋转
    function setRotate(item) {
        item.set('hasRotatingPoint', false);
        item.customiseCornerIcons({
            settings: {
                borderColor: '#061101',
                cornerSize: 32,
                cornerShape: 'rect',
                cornerPadding: 10
            },
            tl: {
                icon: '../images/details/icons/icon_rotate2.png'
            },
            br: {
                icon: '../images/details/icons/icon_escal2.png'
            },
            tr: {
                icon: '../images/details/icons/icon_remove2.png'
            },
            bl: {
                icon: '../images/details/icons/icon_mover2.png'
            }
        }, function () {
            canvas.renderAll();
        });
    }
    //判断当前选中的在哪个tab中
    function tabGet(i) {
        $('.dec-select li').removeClass('activeTab');
        $('.dec-select li').eq(i).addClass('activeTab');
        $('.dec-content li').addClass('dis');
        $('.dec-content li').eq(i).removeClass('dis');
    }
    //选择字体、图片的颜色
    function selColor(id) {
        $(id).colpick({
            submit: 0,
            onChange: function (hsb, hex, rgb, el, bySetColor) {
                $(el).css('border-color', '#' + hex);
                if (!bySetColor) $(el).val(hex);
                $(id).css('background', '#' + hex);
                _this.set('fill', '#' + hex);
                canvas.renderAll();
            }
        }).keyup(function () {
            $(this).colpickSetColor(this.value);
        });
    }
    //控制绘画区域的显示隐藏
    canvas.on('mouse:over', function (options) {
        //console.log(options.e.clientX, options.e.clientY); // 打印坐标
        if (isDesign) {
            $('.design-border-blue').css('display', 'block');
        }
    });
    canvas.on('mouse:out', function (options) {
        //console.log(options.e.clientX, options.e.clientY); // 打印坐标
        if (isDesign) {
            $('.design-border-blue').css('display', 'none');
        }
    });
    canvas.on('object:removed', function (item) {
        if (item.target.pId === true) {
            item.target.pId = false
        } else {
            designUploadId.splice(designUploadId.indexOf(item.target.id), 1)
            console.log(designUploadId)
            getPrice();
        }
    })
    //canvas.on('mouse:up', function () {
    //    var currentId = [];
    //    var objArr = canvas.getObjects();
    //    objArr.forEach(function (item, index) {
    //        currentId.push(item.id);
    //    })
    //    clearCopy(currentId);
    //    //getPrice();
    //})
    //function clearCopy(currentId) {
    //    var len = designUploadId.length;
    //    designUploadId.splice(0, designUploadId.length);
    //    currentId.forEach(function (item, index) {
    //        designUploadId.push(item);
    //    })
    //    console.log(designUploadId.length);
    //    if (designUploadId.length != len) {
    //        designUploadId.isChange = 1;
    //    }
    //}
    $(document).on('click', '.on-pics', function () {
        designUploadId.push($(this).attr('data-id'));
        console.log(designUploadId)
        getPrice();
    })
    //选中某个(图片、文字)时进行操作
    canvas.on('object:selected', function (e) {
        $('.design-border-blue').css('display', 'block');
        $.each(canvas.getObjects(), function (m, item) {
            for (var n in item) {
                if (n == 'active' && item[n] == true) {
                    if (item.active == true) {

                        setRotate(item);//设置item的四角矩形及是否有旋转
                        if ($('#view').css('backgroundColor') == 'rgba(0, 0, 0, 0)') {
                            item.set('borderColor', '#303030');
                            canvas.renderAll();
                        } else {
                            judgeBorderColor($('#view').css('backgroundColor'), item);
                            canvas.renderAll();
                        }
                        //判断当前选中的在哪个tab中
                        $(this)[0].text ? tabGet(2) : null;
                        $(this)[0].paths ? (item.flag == 1 ? tabGet(0) : tabGet(1)) : null;
                        $(this)[0].filters ? tabGet(3) : null;

                        //getPrice();
                        $('#dis-text').val(item.text);  //设置文字输入框的值
                        _this = item;
                        //选择字体
                        $('.sel-font').on('change', function (e) {
                            _this.fontFamily = $(this).val();
                            canvas.renderAll();
                        });
                        $('#dis-text').on('keyup', function (e) {
                            _this.text = e.target.value;
                            canvas.renderAll();
                        });

                        selColor('#picker2'); //选择字体的颜色
                        selColor('#picker'); //选择图片二的颜色
                        selColor('#picker5'); //选择图片一的颜色

                        //选中字体工具的图片
                        $('.font-tools img').each(function (n) {
                            $(this).on('mousedown', function (e) {
                                n < 3 ? _this.textAlign = fontToolsImg[n] : null;
                                n == 3 ? (_this.fontWeight = _this.fontWeight == 'normal' ? fontToolsImg[n] : 'normal') : null;
                                n == 4 ? (_this.fontStyle = _this.fontStyle != fontToolsImg[n] ? _this.fontStyle = fontToolsImg[n] : 'normal') : null;
                                canvas.renderAll();
                            });
                        });

                        //按delete键可以删除
                        document.onkeydown = function (event) {
                            var e = event || window.event || arguments.callee.caller.arguments[0];
                            if (e && e.keyCode == 46) {
                                canvas.remove(_this);  //删除
                                canvas.renderAll();
                            }
                        };
                    } else {
                        return false;
                    }
                }
            }
        });

    });


    //判断衣服颜色深浅,显示不同的边框颜色
    function judgeColor(rgb) {
        var RgbValue = rgb.replace("rgb(", "").replace(")", "");
        var RgbValueArry = RgbValue.split(",");
        var $grayLevel = RgbValueArry[0] * 0.299 + RgbValueArry[1] * 0.587 + RgbValueArry[2] * 0.114;
        $grayLevel >= 192 ? $('.design-border-blue').css('border', '1px solid #303030') : $('.design-border-blue').css('border', '1px solid #dedede');
    }
    //边框颜色改变
    function judgeBorderColor(rgb, item) {
        var RgbValue = rgb.replace("rgb(", "").replace(")", "");
        var RgbValueArry = RgbValue.split(",");
        var $grayLevel = RgbValueArry[0] * 0.299 + RgbValueArry[1] * 0.587 + RgbValueArry[2] * 0.114;
        $grayLevel >= 192 ? item.set('borderColor', '#303030') : item.set('borderColor', '#dedede');
    }
    //衣服颜色列表      
    $('.pro-colors-list li').each(function () {
        $(this).on('click', function () {
            $('#view').css('background', $(this).css('backgroundColor'));
            judgeColor($(this).css('backgroundColor'));
            $('.design-border-blue').css('display', 'none');
            canvas.renderAll();
        });
    });
    //衣服颜色画板 
    $('#picker3').colpick({
        submit: 0,
        onChange: function (hsb, hex, rgb, el, bySetColor) {
            $('#view').css('backgroundColor', '#' + hex);
            judgeColor('rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')');
            $('.design-border-blue').css('display', 'none');
            canvas.renderAll();
        }
    }).keyup(function () {
        $(this).colpickSetColor(this.value);
    });

    //显示隐藏
    function selDisplay(ele) {
        $(ele).css('display') == 'block' ? $(ele).css('display', 'none') : null;
    }
    //点击空白处选中的框也可以消失
    $(document).on('mousedown', function () {

        if (canvas.getActiveObject()) {
            canvas.getActiveObject().active = false;
            canvas.renderAll();
            //创建一个,并删除,使其选中
            fabric.loadSVGFromURL('../images/flower.svg', function (objects, options) {
                a = fabric.util.groupSVGElements(objects, options);
                a.set({
                    left: 100,
                    top: 100,
                    fill: '#000000',
                    originX: 'center',
                    originY: 'center',
                    hasRotatingPoint: false,
                    flag: 1,
                    pId: true
                });
                setPic(a, true);
            });/*  */
            /* console.log(canvas.getActiveObject());
             var item = canvas.getActiveObject();
            //判断当前选中的在哪个tab中
             item.text ? tabGet(2) : null;
             item.paths ? (item.flag == 1 ? tabGet(0) : tabGet(1)) : null;
             item.filters ? tabGet(3) : null; */
            //  setRotate(item);
        }
        selDisplay('.colpick');
        selDisplay('#colorpicker_1');
        selDisplay('#colorpicker_2');
        selDisplay('#colorpicker_3');
        selDisplay('#colorpicker_4');
        selDisplay('.design-border-blue');
    });

  //将饰品修饰的那部分
    $('.dec-content').on('mousedown', function (e) {
        e.stopPropagation();
    });


    /*var json = {"objects":[{"type":"i-text","originX":"center","originY":"center","left":120.78,"top":117.06,"width":27.73,"height":22.6,"fill":"#1d85cf","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":2.45,"scaleY":2.45,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"text":"ffff","fontSize":20,"fontWeight":"normal","fontFamily":"Comic Sans","fontStyle":"","lineHeight":1.16,"textDecoration":"","textAlign":"left","textBackgroundColor":"","charSpacing":0,"styles":{}}]}
    
    canvas.loadFromJSON(json, function () {
        console.log(json);
        canvas.renderAll();
    });*/
    //保存canvas上面的内容 加载json  不提交的
    /*$('.take-count .btn-common').eq(0).on('click', function () {
        console.log(canvas.toJSON());
        var json = JSON.stringify(canvas.toJSON()); 
        canvas.clear();
        $(this).click(function () {
            canvas.loadFromJSON(json, function () {
                console.log(json);
                canvas.renderAll();
            });
        });
 
    });  */
  
    //获取图库一二中的图片
    function getAjaxImg(url, num) {
        var key ;
        if (getUrlParam("ProductId")!=null ) {
            key = getUrlParam("ProductId");
        } else {
            key = getUrlParam("key");
        }
        //  alert(key);
        $.ajax({
            url: '/Details/' + url + '?productId=' +key,//window.location.search.substr(1).split('=')[1],
            type: 'post',
            success: function (data) {
                // console.log(data);
                $.each(data, function (i) {
                    $('.online-pic' + num).append('<img class="left on-pics" data-pri="' + data[i]['price'] + '" data-id="' + data[i]['Id'] + '" src="http://api.quandz.com' + data[i]['Image'] + '" alt="" />');
                });
                addImg($('.online-pic' + num + ' img'), [], num);  //可以点击添加图片到衣服上
            },
            error: function () {
                console.log('error');
            }
        });
    }
    getAjaxImg('GetImageI', 1); //图库一
    getAjaxImg('GetImageII', 2);//图库二

    return canvas;
})();

常用正则表达式总结

1. 手机号 /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57]|19[89]|166)[0-9]{8}$/
2. 固定电话 /0\d{2,3}-\d{7,8}/
3. 金钱3位逗号分隔 val.replace(/\B(?=(?:\d{3})+\b)/g, ',')
4. 字符串中取出汉字 val.match(/[\u4e00-\u9fa5]/g).join('') eg: '这是AB一段CD文字'.match(/[\u4e00-\u9fa5]/g).join('') ==== 这是一段文字
5. 字符串中取出数字 val.replace(/[^0-9]/ig, '') eg: '这是问问2545554'.replace(/[^0-9]/ig, '') ==== 2545554

js中callback和promise的区别

两者之间的主要区别在于,使用回调方法时,我们通常只是将回调传递给一个函数,该函数将在完成时被调用以获取某些结果。但是,在Promise中,您将回调附加在返回的Promise对象上。 原文链接

CallBacks
function getMoneyBack(money, callback) {
  if (typeof money !== 'number') {
    callback(null, new Error('money is not a number'))
  } else {
    callback(money)
  }
}

const money = getMoneyBack(1200)
console.log(money)
Promises
function getMoneyBack(money) {
  return new Promise((resolve, reject) => {
    if (typeof money !== 'number') {
      reject(new Error('money is not a number'))
    } else {
      resolve(money)
    }
  })
}

getMoneyBack(1200).then((money) => {
  console.log(money)
})

http status code

  • 2开头(请求成功)表示成功处理了请求的状态代码。
200   (成功)  服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。 
201   (已创建)  请求成功并且服务器创建了新的资源。 
202   (已接受)  服务器已接受请求,但尚未处理。 
203   (非授权信息)  服务器已成功处理了请求,但返回的信息可能来自另一来源。 
204   (无内容)  服务器成功处理了请求,但没有返回任何内容。 
205   (重置内容) 服务器成功处理了请求,但没有返回任何内容。
206   (部分内容)  服务器成功处理了部分 GET 请求。
  • 3开头(请求被重定向)表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。
300   (多种选择)  针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。 
301   (永久移动)  请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
302   (临时移动)  服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
303   (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
304   (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。 
305   (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。 
307   (临时重定向)  服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
  • 4开头(请求错误)这些状态代码表示请求可能出错,妨碍了服务器的处理。
400   (错误请求) 服务器不理解请求的语法。 
401   (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。 
403   (禁止) 服务器拒绝请求。
404   (未找到) 服务器找不到请求的网页。
405   (方法禁用) 禁用请求中指定的方法。 
406   (不接受) 无法使用请求的内容特性响应请求的网页。 
407   (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
408   (请求超时)  服务器等候请求时发生超时。 
409   (冲突)  服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。 
410   (已删除)  如果请求的资源已永久删除,服务器就会返回此响应。 
411   (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。 
412   (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。 
413   (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。 
414   (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。 
415   (不支持的媒体类型) 请求的格式不受请求页面的支持。 
416   (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。 
417   (未满足期望值) 服务器未满足"期望"请求标头字段的要求。
  • 5开头(服务器错误)这些状态代码表示服务器在尝试处理请求时发生内部错误。
    这些错误可能是服务器本身的错误,而不是请求出错。
500   (服务器内部错误)  服务器遇到错误,无法完成请求。 
501   (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。 
502   (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。 
503   (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。 
504   (网关超时)  服务器作为网关或代理,但是没有及时从上游服务器收到请求。 
505   (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。

链接转成二维码,生成图片并进行下载

背景:

让链接生成二维码,生成的二维码可以进行下载,其中生成的二维码中间可以放上一个logo,二维码周围是一个背景图,主要使用 vue.js QRCode VueQr html2canvas实现的。
首先生成二维码,然后html2canvas 将背景图和二维码转成新的图片,并进行下载

页面
<div class="content" id="content">
  <vue-qr
    v-if="qrcodeUrl"
    :logoSrc="logo"
    :text="qrcodeUrl"
    :whiteMargin="true"
    :size="400"
    :dotScale="1"
    :logoScale="0.2"
    :logoMargin="10"
    logoBackgroundColor="#fff"
    :correctLevel="3"
  ></vue-qr>
  <img v-if="!qrcodeUrl" :src="newSrc" alt="">
</div>
js
import QRCode from 'qrcode'
import VueQr from 'vue-qr'
import html2canvas from 'html2canvas'
其中qrcodeBG 和 logo是两张背景图,可以引进来

components: {
    VueQr,
    QRCode
},
data () {
    return {
      codes: '',
      imgBgSrc: qrcodeBG,
      downloadInfo: '',
      qrcodeUrl: '', // 这是链接的地址
      newSrc: '',
      logo: logo
    }
  },
mounted () {
    this.qrcodeScan(this.qrcodeUrl)
},
methods: {
    // 下载图片
    saveFile (data, filename) {
      let saveLink = document.createElementNS('http://www.w3.org/1999/xhtml', 'a')
      saveLink.href = data
      saveLink.download = filename
      let event = document.createEvent('MouseEvents')
      event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
      saveLink.dispatchEvent(event)
    },
    // 下载二维码
    downloadCode () {
      html2canvas(document.querySelector('#content'), {
        allowTaint: true,
        taintTest: false,
        useCORS: true,
        logging: true,
        scale: 2.5
      }).then(canvas => {
        let image = document.createElement('img')
        image.src = canvas.toDataURL('image/png')
        this.saveFile(image.src, '')
      }).catch((err) => {
        console.log(err)
      })
    },
    qrcodeScan (qrcodeUrl) {
      QRCode.toDataURL(qrcodeUrl, {width: 180, height: 180}).then(url => {
        this.newSrc = url
      }).catch(err => {
        console.error(err)
      })
    }
  }

js高德地图中地址查询定位

高德地图自带的,根据用户输入的地址,进行模糊搜索,用户进行选择定位
vue以及element-ui实现的,

查询搜索功能

页面部分布局

 <div class="location-wrap">
    <div id="location"></div>
    <div class="search">
      <el-input
        id="tip-input"
        size="small"
        class="search-input"
        placeholder="请输入地址"
        prefix-icon="el-icon-search"
        v-model="address"
        :clearable="true"
        @input="mapLocation"
       >
      </el-input>
      <ul class="list" v-show="searchMsg">
        <li v-for="(item, index) in list" :key="index" @click="selectAddress(item)">{{item.name}}</li>
     </ul>
  </div>
</div>

js部分
在mounted时候,加载地图

<script>
import MP from '这个加载地图文件,访问也在简书中'

let map = '' // 定义地图
let marker = '' // 定义一个标记
export default {
  data () {
    return {
      mapKey: '这是你的地图key',
      address: '', // 输入地址
      list: [], // 模糊搜索的list
      searchMsg: false, // list下拉框的显示隐藏
      lnglat: {} // 存储点击的经纬度
    }
  },
  created () {
  },
  async mounted () {
    await MP (this.mapKey)
    this.map()
    this.clickMap() // 地图上的点击事件
  },
  methods: {
   // 将获取到的地址传回到父组件
    handleChange (val) {
      this.$emit('address', val)
    },
   // 下拉框中的选择
    selectAddress (val) {
      this.address = `${val.district}${val.name}`
      this.handleChange(`${val.district}${val.name}`)
    },
   // 初始化地图
    map () {
      map = new AMap.Map('location', {
	     resizeEnable: true,
	     zoom: 14
      })
    },
   // input事件
    mapLocation () {
      // 使用高德地图的自动补全和搜索的功能
      map.plugin(['AMap.Autocomplete', 'AMap.PlaceSearch'], () => {
        // 实例化Autocomplete
        var autoOptions = {
          city: '全国'
        }
        let autoComplete = new AMap.Autocomplete(autoOptions)
        autoComplete.search(this.address, (status, result) => {
          if (result && result.info === 'OK') {
            this.list = result.tips
            this.searchMsg = true
            this.placeSearch(this.list.length && this.list[0].name)
          }
        })
      })
    },
    placeSearch (value) {
      let placeSearch = new AMap.PlaceSearch({
        city: '全国',
        map: map
      })
      placeSearch.search(value)
    },
   // 地图上的点击事件,根据点击位置,记一个mark,点击新的位置,去掉之前的mark,记录最新的
    clickMap () {
      map.on('click', (e) => {
        if (JSON.stringify(this.lnglat) !== '{}') {
          this.mark('remove', this.lnglat)
        }
        this.lnglat = e.lnglat
        this.mark('add', e.lnglat)
        map.plugin(['AMap.Geocoder'], () => {
          let geocoder = new AMap.Geocoder({
            radius: 1000,
            extensions: 'all'
          })
          geocoder.getAddress([e.lnglat.lng, e.lnglat.lat], (status, result) => {
            if (result && result.info === 'OK') {
              this.address = `${result.regeocode.formattedAddress}`
              this.handleChange(`${result.regeocode.formattedAddress}`)
              this.close()
            }
          })
        })
      })
    },
   // 标记的新增和删除
    mark (type, value) {
      if (type === 'remove') {
        return map.remove(marker)
      }
      marker = new AMap.Marker({
        position: new AMap.LngLat(value.lng, value.lat),
        title: '北京'
      })
      map.add(marker)
    }
  }
}
</script>

css样式,使用的less

.location-wrap {
  position: relative;
  width: 100%;
  height: 500px;
}
#location {
  width: 100%;
  height: 100%;
}
.search {
  position: absolute;
  right: 10px;
  top: 10px;
  .el-input {
    width: 400px;
  }
  .list {
    width: 380px;
    // height: 300px;
    background: #ffffff;
    padding: 0 10px;
    color: #333;
    font-size: 14px;
  }
  li {
    line-height: 40px;
    cursor: pointer;
  }
}

提示:高德地图jsapi的地址

导航可以滑动(手指滑动)

可以左右滑动的一个导航栏

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
	<style type="text/css">
		.app{
		    width: 100%;
		    overflow:hidden;

		}
		.app nav{
		    padding: 0 0.5rem;
		    display: -webkit-box;
		    display: -ms-flexbox;
		    display: flex;
		    -webkit-box-align: middle;
		    -ms-flex-align: middle;
		    align-items: middle;
		    overflow: auto;
		}
		.app p{
		    text-align: center;
		    font-size: 0.6rem;
		    -ms-flex-negative: 0;
		    flex-shrink: 0;
		    padding: 0.2rem;
		    margin: 5px;

		}
		.app p.active{
		    color: #ffffff;
		    background-color: #f00000;
		}

	</style>
</head>
<body>
	<div class="app">
	    <nav>
	        <p v-for="(item,$index) in arr" @click="toggle($index)" :class="{active:$index==active}">{{item}}</p>
	    </nav>
	</div>
	<script>
        var app=new Vue({
            el:'.app',
            data:{
               active:0,
                arr:[
                    "新闻1",
                    "新闻1",
                    "新闻1",
                    "新闻1",
                    "新闻1",
                    "新闻1",
                    "新闻1",
                    "新闻1",
                    "新闻1",
                    "新闻1",
                    "新闻1",
                    "新闻1"
                ]

            },
            computed:{

            },
            methods:{
                toggle (index) {
                    this.active = index
                }
            },
        })
    </script>
    <script type="text/javascript">
    	!function(e){function t(){var t=n.clientWidth,r="}";!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)&&t>1024&&(t=640,r=";max-width:"+t+"px;margin-right:auto!important;margin-left:auto!important;}"),e.rem=t/10,/ZTE U930_TD/.test(navigator.userAgent)&&(e.rem=1.13*e.rem),/Android\s+4\.4\.4;\s+M351\s/.test(navigator.userAgent)&&(e.rem=e.rem/1.05),/Android\s+5\.0\.1;\s+MX4\s/.test(navigator.userAgent)&&(e.rem=1.06382*e.rem),i.innerHTML="html{font-size:"+e.rem+"px!important;}body{font-size:"+12*(t/320)+"px"+r}var n=document.documentElement,i=document.createElement("style");n.firstElementChild.appendChild(i),e.addEventListener("resize",function(){t()},!1),e.addEventListener("pageshow",function(e){e.persisted&&t()},!1),t()}(window);
    </script>
</body>
</html>

微信jssdk接入到h5网页

注意!!

1)jssdk 都要先获取配置的信息,然后才能调ready方法

2)对于没有公开的接口,wx.config 的时候传入参数 beta: true

3) eg: wx.invoke(name, args, callback),其中 name 是接口名,args 是参数对象,callback 是回调函数

4) vue单页应用 ,对于苹果手机 ,调用jssdk时会出现 签名错误,或者无效的,可以通过跳转来解决这个问题,就是进入当前页时,使用window.location.href进入

1. 打开卡包

import wx from 'weixin-js-sdk'
// 首先要获取 微信的基本配置
wx.config({
        // debug: true,
        appId: res.appId,
        timestamp: res.timeStamp, // 必填,生成签名的时间戳
        nonceStr: res.nonceStr, // 必填,生成签名的随机串
        signature: res.signature, // 必填,签名
        jsApiList: ['openCard'] // 必填,需要使用的JS接口列表
      })
      wx.ready(function () {
        wx.openCard({
          cardList: data,
          success: function () {
            console.log('success')
          },
          fail: function () {
            console.log('fail')
          },
          complete: function () {
            console.log('complete')
          },
          cancel: function () {
            console.log('cancel')
          }
        })
      })
      wx.error(function () {
        console.log('err') // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
      })

2.获取微信发票抬头

wx.config({
          // debug: true,
          beta: true,
          appId: res.appId,
          timestamp: res.timeStamp, // 必填,生成签名的时间戳
          nonceStr: res.nonceStr, // 必填,生成签名的随机串
          signature: res.signature, // 必填,签名
          jsApiList: ['chooseInvoiceTitle'] // 必填,需要使用的JS接口列表
        })
        wx.ready(function () {
          wx.invoke('chooseInvoiceTitle', {'scene': '1'}, function (res) {
          
          })
        })
        wx.error(function (err) {
          console.log(err)
        })

微信jssdk官方文档

ES新特性

1、Array.prototype.includes

includes是一个Array上很有用的方法,用于快速查找数组中是否包含某个元素,包括NaN(所以和indexOf不一样)

let arr = [1, 2, 3, NaN];
// 查找2是否存在于arr数组中
arr.includes(2) // true
// 第二个参数3表示数组下标为3的项,也即第4项开始查找
arr.includes(2, 3) // false
arr.includes(NaN) // true
arr.indexOf(NaN) != -1  // false

2、指数函数的中缀表示法

JavaScript也采用两个星符号**来表示Math.pow

let a = 2 ** 2;// 等同于: 2 * 2
let b = 2 ** 3;// 等同于: 2 * 2 * 2

// x **= y
let a = 2;
a **= 2;//等同于: a = a * a;

let b = 3;
b **= 3;//等同于: b = b * b * b;

3、Object.values() / Object.entries

用法是 Object.values(obj),obj 可以是一个对象或者数组

const obj = { x: 'xxx', y: 1 };
Object.values(obj); // ['xxx', 1]

const obj = ['e', 's', '8']; // 等同于 { 0: 'e', 1: 's', 2: '8' };
Object.values(obj); // ['e', 's', '8']

//当把数字当做对象的键的时候,返回的数组以键的值升序排序
const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' };
Object.values(obj); // ['yyy', 'zzz', 'xxx']
Object.values('es8'); // ['e', 's', '8']

Object.entries方法返回一个给定对象可枚举属性值的数组[key, value],与Object.values类似。

const obj = { x: 'xxx', y: 1 };
Object.entries(obj); // [['x', 'xxx'], ['y', 1]]

const obj = ['e', 's', '8'];
Object.entries(obj); // [['0', 'e'], ['1', 's'], ['2', '8']]

const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' };
Object.entries(obj); // [['1', 'yyy'], ['3', 'zzz'], ['10', 'xxx']]
Object.entries('es8'); // [['0', 'e'], ['1', 's'], ['2', '8']]

正则表达式的总结2

1、验证金额(输入整数,小数点后一或两位)

// 小数点后两位
export function CheckAmount (str) {
  let reg = /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/
  return reg.test(str)
}
// 小数点后一位
export function CheckOnePoint (str) {
  let reg = /(^[1-9]([0-9]+)?(\.[0-9]{1})?$)|(^(0){1}$)|(^[0-9]\.[0-9]?$)/
  return reg.test(str)
}

2、验证身份证号

export function validateIDcard (str) {
  const reg = /^[1-9][0-9]{5}([1][9][0-9]{2}|[2][0][0|1][0-9])([0][1-9]|[1][0|1|2])([0][1-9]|[1|2][0-9]|[3][0|1])[0-9]{3}([0-9]|[X])$/
  return reg.test(str)
}

3、验证邮箱

export function CheckEmail(email){
  return (/^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,8})$/.test(email))
}

4、手机号简单验证

export function CheckPhone(phone){ 
  return (/^1[3|4|5|6|7|8|9]\d{9}$/.test(phone))
}

5、特殊字符和空格判断 如果有返回true

export function CheckString (str) {
  let reg = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\].<>/?~!@#¥……&*()——|{}【】‘;:”“'。,、?]")
  let regSpace = /\s/g
  return reg.test(str) || regSpace.test(str)
}

6、时间的一些转换

// 20180829105739 ====> 2018-08-29-10:57:39
export function changeTime (date) {
  return `${date.slice(0, 4)}-${date.slice(4, 6)}-${date.slice(6, 8)} ${date.slice(8, 10)}:${date.slice(10, 12)}:${date.slice(12, 14)}`
}
// 20180829 ====> 2018-08-29
export function changeResponseDate (date = '') {
  return `${date.slice(0, 4)}-${date.slice(4, 6)}-${date.slice(6, 8)}`
}
// 1546939193000 ===> 2019-01-08 17:19:53
export function formatTime (date) {
  if (!date) {
    return ''
  }
  date = new Date(date);
  let day = date.getDate() > 9 ? date.getDate() : '0' + date.getDate()
  let hour = date.getHours() > 9 ? date.getHours() : '0' + date.getHours()
  let minute = date.getMinutes() > 9 ? date.getMinutes() : '0' + date.getMinutes()
  let second = date.getSeconds() > 9 ? date.getSeconds() : '0' + date.getSeconds()
  let month = (date.getMonth() + 1) > 9 ? (date.getMonth() + 1) : '0' + (date.getMonth() + 1)
  return `${date.getFullYear()}-${month}-${day} ${hour}:${minute}:${second}`
}
// 'Thu May 12 2017 08:00:00 GMT+0800 (**标准时间)' =>> yyyy-MM-dd hh:mm:ss
export function grpcDateFormat (date) {
  if (!date) {
    return ''
  }
  date = new Date(date);
  let day = date.getDate() > 9 ? date.getDate() : '0' + date.getDate()
  let hour = date.getHours() > 9 ? date.getHours() : '0' + date.getHours()
  let minute = date.getMinutes() > 9 ? date.getMinutes() : '0' + date.getMinutes()
  let second = date.getSeconds() > 9 ? date.getSeconds() : '0' + date.getSeconds()
  let month = (date.getMonth() + 1) > 9 ? (date.getMonth() + 1) : '0' + (date.getMonth() + 1)
  return `${date.getFullYear()}-${month}-${day} ${hour}:${minute}:${second}`
}

uni-app引用Echarts的踩坑

安装依赖

npm install echarts mpvue-echarts --save

将下载后的三个库从node_modules剪切到项目的根目录下

<template>
	<view class="month-chart">
		<view class="chart">
			<mpvue-echarts canvasId="chartmonth" :echarts="echarts" @onInit="initChart" ref="chartmonth"/>
		</view>
	</view>
</template>

<script>
	import * as echarts from 'echarts/echarts.min.js' 
	import mpvueEcharts from 'mpvue-echarts'
	let chart = null
	export default {
		props: [],
		components: {
			mpvueEcharts
		},
		data () {
			return {
				echarts: echarts,
				xAxisData: ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'],
				seriesS: [320, 302, 301, 334, 390, 330, 320],
				seriesP: [120, 132, 101, 134, 90, 230, 210],
				isNoMsg: false
			}
		},
		created () {
		},
		mounted () {
		},
		methods: {
			handleEchart (e) {
				console.log(e)
			},
			initChart (e) {
				let {
					width,
					height
				} = e
				
				let canvas = this.$refs.chartmonth.canvas
				echarts.setCanvasCreator(() => canvas)
				const chart = echarts.init(canvas, null, {
					width: width,
					height: height
				})
				canvas.setChart(chart)
				let option = {
					tooltip: {
						trigger: 'axis',
						axisPointer: {
						  type: 'shadow'
						}
					},
					legend: {
						data: ['合理化建议', '问题反映'],
						itemGap: 30,
						bottom: '20',
						right: '20'
					},
					grid: {
						left: '0',
						top: '10',
						containLabel: true
					},
					xAxis: {
						type: 'category',
						data: this.xAxisData,
						axisTick: {
						  show: false
						},
						axisLine: {
						  show: false
					  }
					},
					yAxis: {
						type: 'value',
						// boundaryGap: [0, 0.01],
						axisTick: {
						  show: false
						},
						axisLine: {
						  show: false
						}
					},
					series: [
						{
						    name: '合理化建议',
								type: 'bar',
								stack: '总量',
						    data: this.seriesS,
						    color: ['#44AEFF'],
						    barWidth: '10',
							  barGap: '0'
						},
						{
						    name: '问题反映',
								type: 'bar',
								stack: '总量',
						    data: this.seriesP,
								color: ['#FF822E'],
								barWidth: '10',
								barGap: '0'
						}
					]
				}
				chart.setOption(option)
				chart.on('click', this.handleEchart)
				chart.on('legendselectchanged', params => {
					chart.setOption({
						legend: {
							selected: { [params.name]: true}
						}
					})
				})
				this.$refs.chartmonth.setChart(chart)
			}
			
		}
	}
</script>

<style lang="scss" scoped>
	.month-chart {
		padding: 10px 15px 0;
	}
	.chart {
		width: 100%;
		height: 320px;
	}
</style>

image

出现报错: this.echarts.setCanvasCreator is not a function

尝试将manifest.json - 源码视图中的小程序配置usingComponents删除

停止微信开发者工具后重新运行,虽然显示图表,但是这不应该是正确的处理方式。
于是寻找另外一种解决办法。根据处理方法 #插件讨论# 【 ECharts页面模板 - DCloud 】APP中 报错 this.echarts.setCanvasCreator is not a function(https://ask.dcloud.net.cn/question/70370),
替换最新的 mpvue-echarts 组件echarts.vue, 源码地址:https://github.com/dcloudio/hello-uniapp/blob/master/components/mpvue-echarts/src/echarts.vue
替换后查看echarts.vue,可以看到init()通过$emit将onInit事件和数据发出

<mpvue-echarts ref="pieChart" :echarts="echarts" @onInit="initChart" />

methods:{
    initChart:initChart
}

console不报错,但是页面也不显示图表。

原因是外框的height为0,需要设置外框的高度。同时要注意page的css
page{display:flex;}会同样无法显示图表。

接下来解决引用uni-app引用mpvue echarts超过小程序大小限制

在小程序开发工具中编译和预览时,提示Error:源码包超出最大限制,source size 3905KB exceed max limit 2MB

参考:https://www.npmjs.com/package/mpvue-echarts
FAQ:打包结果超过小程序大小限制?
使用自定义版 echarts,官网定制

FAQ:文件太大怎么办?
本项目默认提供的 ECharts 文件是最新版本的包含所有组件文件,为了便于开发,提供的是未压缩的版本。远程调试或预览可以下载 echarts.min.js 压缩版本。
发布时,如果对文件大小要求更高,可以在 ECharts 在线定制网页下载仅包含必要组件的包,并且选择压缩。

定制按需选择后得到echarts.min.js
将echarts.min.js文件复制到echarts目录下。

import * as echarts from 'echarts/echarts.min.js'
import mpvueEcharts from 'mpvue-echarts/src/echarts.vue'

h5 运行到浏览器时,控制台报错:TypeError: t.addEventListener is not a function

解决方法查看:UNI-app新引入echarts 报错 https://blog.csdn.net/qq_36444936/article/details/86599300
编辑刚才拷贝的echarts.min.js,检索“e(t.echarts={})”字符串
找到相邻的(this,function(t) 串 ,将其改为(this,function(t,window,document)保存即可

因为是适配小程序,所以一定要考虑代码量,chart.js使用在在线定制,在线定制地址:https://echarts.apache.org/zh/builder.html

markdown语法

1、加粗的语法(2种写法)

**加粗的字体** __加粗的字体__ eg: 加粗的字体 加粗的字体

2、斜体的语法(2种写法)

*斜体的字体* _斜体的字体_ eg: 斜体的字体 斜体的字体

3、斜体加粗

***斜体加粗*** eg: 斜体加粗

4、加删除线的文体

~~加删除线的文体~~ eg: 加删除线的文体

5、引用, 在引用的文字前加>即可。引用也可以嵌套,如加两个>>三个>>>

>引用 eg:

引用

6、分割线

---

----

***


*****


7、图片

![图片alt](图片地址 ''图片title'')

图片alt就是显示在图片下面的文字,相当于对图片内容的解释。
图片title是图片的标题,当鼠标移到图片上时显示的内容。title可加可不加
![blockchain](https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/
u=702257389,1274025419&fm=27&gp=0.jpg "区块链")

8、超链接

[超链接名](超链接地址 "超链接title")
title可加可不加
[百度](http://baidu.com)

eg: 百度

9、列表

无序列表用 - + * 任何一种都可以

- 列表内容
+ 列表内容
* 列表内容
注意:- + * 跟内容之间都要有一个空格

eg:

  • 列表内容
  • 列表内容
  • 列表内容
    有序列表 数字加点
1. 列表内容
2. 列表内容
3. 列表内容
注意:序号跟内容之间要有空格

eg:

  1. 列表内容
  2. 列表内容
  3. 列表内容

10、列表嵌套

上一级和下一级之间敲三个空格即可

- 列表内容
   1. 列表内容
   2. 列表内容
- 列表内容
   - 列表内容
   - 列表内容

eg:

  • 列表内容
    1. 列表内容
    2. 列表内容
  • 列表内容
    • 列表内容
    • 列表内容

11、表格

表头|表头|表头
---|:--:|---:
内容|内容|内容
内容|内容|内容

第二行分割表头和内容。
- 有一个就行,为了对齐,多加了几个
文字默认居左
-两边加:表示文字居中
-右边加:表示文字居右
注:原生的语法两边都要用 | 包起来。此处省略
姓名|技能|排行
--|:--:|--:
刘备|哭|大哥
关羽|打|二哥
张飞|骂|三弟
姓名 技能 排行
刘备 大哥
关羽 二哥
张飞 三弟

12、代码

单行代码:代码之间分别用一个反引号包起来

`代码`

eg: 代码
代码块:代码之间分别用三个反引号包起来,且两边的反引号单独占一行

<script></script>

eg:

<script></script>

13、流程图

```flow
st=>start: 开始
op=>operation: My Operation
cond=>condition: Yes or No?
e=>end
st->op->cond
cond(yes)->e
cond(no)->op
&```

eg:

st=>start: 开始
op=>operation: My Operation
cond=>condition: Yes or No?
e=>end
st->op->cond
cond(yes)->e
cond(no)->op
&```

前端使用mqtt,用于接收消息

主要是用vue 安装mqtt npm i mqtt

import mqtt from 'mqtt' 
let client = ''
export default {
  created () {
    let options = {
      connectTimeout: 40000,
      clientId: `id`,
      username: `定义的用户名`,
      password: `密码`,
      path: '/mqtt',
      clean: true,
      useSSL: true/false,
      port: '端口号',
      topic: '通信'
    }
    client = mqtt.connect(`链接的地址`, options)
    this.mqttMsg()
  },
  methods: {
    mqttMsg () {
      client.on('connect', () => {
        client.subscribe(`通信`, { qos: 0 }, (error) => {
          if (!error) {
            console.log('success')
          } else {
            console.log('fail')
          }
        })
      })
      // 接收消息处理
      client.on('message', (topic, message) => {
        let msg = message.toString()
        if (msg && JSON.parse(msg).content === 'ok') {
           console.log('信息成功')
        }
      })
      client.on('reconnect', (error) => {
        console.log('正在重连:', error)
      })
      // 链接异常处理
      client.on('error', (error) => {
        console.log('连接失败:', error)
      })
    },
  }
}

Ajax 数据异步交互(查询提示、天气预报查询地址、快递单号查询接口)

原文链接

1.查询提示

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>查询访问</title>
<style type="text/css">
		*{margin:0px;padding: 0px;}
		#container{width:800px;margin:auto;margin-top:10px;}
		input[id="keywords"]{width: 500px;height: 40px;border:solid 2px #cecece;font-size: 22px;line-height: 40px;color:#888;padding-left: 10px;} 	

		#sug{width:512px;list-style: none;border:solid 1px #ccc;}
		#sug li{height: 30px;background:#fcfcfc;line-height:30px;font-size:18px}
</style>
<script type="text/javascript" src="../jquery-1.12.4.js"></script>

</head>
<body>
	<div id="container">
		<div>
			<input type="text" id="keywords" placeholder="请输入关键词">
		</div>
		<ul id="sug">
			<!-- <li>建议搜索的关键词</li> -->
		</ul>
	</div>

	<script>
             // 获取输入框
	  var $kw = $("#keywords");
		// 添加键盘按键抬起事件
		$kw.keyup(function(){
			// 获取输入框中的输入
			var $value = $kw.val();
			// 调用函数,获取数据
			$.ajax({
				url:"https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?cb=?",
				type:"get",
				data:{wd:$value},
				dataType:"jsonp",
				success:function(msg){
					// 当url接口访问成功的时候,自动调用success对应的函数,接口返回的数据会自动存放在函数的参数data中
					console.log(msg.s);
					// 将输入输出到页面中;dom操作
					var _sug = msg.s;
					// 清空原来的url标签;
					$("#sug").empty();
					for (var i = 0;i< _sug.length;i++){
						// 创建一个li标签
						var $li = $("<li>")
						// 标签中添加文本数据
						$li.text(_sug[i]);
						// 将li标签,添加到页面中
						$("#sug").append($li);
					}
				}
			}); 
		});
	</script>
</body>
</html>
<!-- 	dataType:"jsonp",
		同源策略:web规范了只有相同源头(域名)的数据才可以互相访问
		同源策略是为了数据的安全性,而设置的一种网络数据访问限制

		跨域:从不同的域名下访问指定的数据 -->

效果展示
image

2.天气预报查询地址

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>天气预报</title>
	<style>
		*{margin:0px;padding:0px;}
		#container{width:800px;margin:auto;font-size: 20px;font-weight: bolder;}
		input[id="city"]{width:500px;height:35px;border:solid 2px #cecece;font-size:22px;line-height:35px;color:#888;padding-left:10px; margin:10px;}
		#show{display:block;width: 600px;height: 300px;border: solid 2px #888;margin: 10px auto; list-style: none;padding: 10px;border-radius: 8px;box-shadow: 10px 10px 5px #888}

	</style>
	<script type="text/javascript" src="../jquery-1.12.4.js"></script>
</head>
<body>
	<div id="container">
		<div>
			请输入城市名称:
			<input type="text" id="city" placeholder="请输入想查询的地区">
		</div>
		<ul id="show">
			<li>天气信息</li>
		</ul>
		
	</div>

 <script>
		// 获取需要的标签对象
		var _city = $("#city");
		var _show = $("#show");

		// 添加事件处理
		_city.blur(function(){
			// 获取输入框中的输入数据
			var $value = _city.val();

			_show.empty();
			// 调用函数,获取数据
			$.ajax({
				url:"http://wthrcdn.etouch.cn/weather_mini?callback=?",
				type:"get",
				data:{city:$value},
				dataType:"jsonp",
				success:function(msg){
					// 当url接口访问成功的时候,自动调用success对应的函数,接口返回的数据会自动存放在函数的参数data中
					console.log(msg);
					// 获取城市数据,展示到页面中
					var $city = $("<li>");
					$city.text(msg.data.city + "天气预报信息:");

					// 获取今天温度数据
					var $wd = $("<li>");
					$wd.text("今天温度:"+ msg.data.wendu);

					// 获取今天感冒指数数据
					var $gm = $("<li>");
					$gm.text("温馨提示:"+ msg.data.ganmao);

					// 今天天气预报
					var $today = $("<li>");

					var $date = $("<span>").text("日期:" + msg.data.forecast[0].date)
					var $type = $("<span>").text(";今天天气:" + msg.data.forecast[0].type)
					var $high = $("<span>").text(";最高气温:" + msg.data.forecast[0].high)
					var $low = $("<span>").text(";最低气温:" + msg.data.forecast[0].low)
					var $fl = $("<span>").text(";风力:" + msg.data.forecast[0].fengli)
					var $fx = $("<span>").text(";风向:" + msg.data.forecast[0].fengxiang)

					$today.append($date).append($type).append($high).append($low).append($fl).append($fx);

					_show.append($city).append($wd).append($gm).append($today);
				},	
				error:function(){
					console.log("运行错误...");				
				}
			}); 
		});

	</script>
</body>
</html>

效果展示
image

3.快递单号查询接口

<!DOCTYPE html>
	<html>
	<head>
		<meta charset="utf-8">
		<title>快递信息查询</title>
		<style type="text/css">
			*{margin: 0;padding: 0;}
			#container{width: 800px;margin: 15px auto;font-size: 20px;font-weight: bolder;}
			select[id="company"]{width: 200px;height: 30px;font-size: 18px;font-family: "微软雅黑";border-radius: 5px;}
			#wb{float: left;}
			input[id="postid"]{margin:10px auto;width: 200px;height: 20px;font-size: 14px;font-family: "微软雅黑";border-radius: 3px;}
			button[id="cx"]{display: block;width: 56px;height: 26px;background-color:#388bff;color:white;margin: 8px 380px;}
			ul[id="show"]{list-style: none;width: 500px;height:500px;border:solid 2px #888; border-radius: 8px; }
			#container ul li p{padding:15px;width:480px;
				min-height: 50px;font-size:14px;}

		</style>

		<script type="text/javascript" src="../jquery-1.12.4.js">
		</script>

	</head>
	<body>
		<div id="container">
			<div>
				<label for="company">快递公司名称</label>
				<select id="company" name="address">
						<option value="shunfeng">顺丰速运</option>
						<option value="shentong">申通快递</option>
						<option value="ems">EMS</option>
						<option value="yuantong">圆通速递</option>
						<option value="zhongtong">中通快递</option>
						<option value="tiantian">天天快递</option>
						<option value="huitongkuaidi">汇通快递</option>
						<option value="yunda">韵达速递</option>
						<option value="quanfengkuaidi">全峰快递</option>
						<option value="debangwuliu">德邦</option>
						<option value="zhaijisong">宅急送</option>
				</select>
			</div>
			<div id="wb">
				<label for="post">输入快递单号</label>
				<input type="text" id="postid">
			</div>
			<div>
				<button id="cx">查询</button>
			</div>

			<ul id="show">
				<li>
					<i></i>
					<p>物流信息</p>
				</li>
			</ul>
			<div style="clear:both;"></div>
		</div>

		<script>
			// 获取标签对象:快递公司
			var $selector=$("#company");
			// 获取快递单号
			var $postid=$("#postid");
			// 查询
			var $cx=$("#cx");

			// 给查询按钮添加点击事件
			$cx.click(function(){
				// 获取需要的数据
				var $company = $selector.val();
				var $value = $postid.val();

				// ajax 获取数据
				$.ajax({
					url:"https://sp0.baidu.com/9_Q4sjW91Qh3otqbppnN2DJv/pae/channel/data/asyncqury?cb=?",
					type:"get",
					data:{com:$company,nu:$value,appid:4001},
					dataType:"json",
					success:function(msg){
						// 清空历史消息
						$("#show").empty();

						// 获取接口返回的数据
						console.log(msg);
						var $info = msg.data.info.context;

						// 循环遍历数据
						for(var i = 0; i <$info.length;i++){
							// 获取每一笔的时间信息
							var $time = $info[i].time;
							$time = getTimeStr($time);

							// 获取每一笔的快递信息
							var $desc = $info[i].desc;

							// 创建标签,添加到页面中
							var $msg = $("<p>").text($time + ":" + $desc);
							var $i = $("<i>");

							var $kd = $("<li>");
							$kd.append($i).append($msg);
							// 添加到页面中
							$("#show").append($kd);
						} 


					},
					error:function(){
						console.log("系统繁忙,查询失败");
					}
				});
			});

			// 获取时间字符串
			function getTimeStr(dt){
				var _date = new Date(parseInt(dt*1000));
				return _date.getFullYear() + "-" + (_date.getMonth() + 1) + "-" + _date.getDate() + " " + _date.getHours() + ":" + _date.getMinutes() + ":" + _date.getSeconds();


			}
		</script>


	</body>
	</html>

效果展示
image

防抖和节流

js防抖和节流属于性能优化的知识,实际遇到的频率比较高,处理不当或者放任不管就容易造成浏览器卡死

防抖 (debounce)

防抖,顾名思义,防止抖动,以免把一次事件误认为多次,敲键盘就是一个每天都会接触到的防抖操作。

想要了解一个概念,必先了解概念所应用的场景。在 JS 这个世界中,有哪些防抖的场景呢

  1. 登录、发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖
  2. 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位,就用到了防抖
  3. 文本编辑器实时保存,当无任何更改操作一秒后进行保存

代码如下,可以看出来防抖重在清零 clearTimeout(timer)

function debounce (f, wait) {
  let timer
  return (...args) => {
    clearTimeout(timer)
    timer = setTimeout(() => {
      f(...args)
    }, wait)
  }
}

节流 (throttle)

节流,顾名思义,控制水的流量。控制事件发生的频率,如控制为1s发生一次,甚至1分钟发生一次。与服务端(server)及网关(gateway)控制的限流 (Rate Limit) 类似。

  1. scroll 事件,每隔一秒计算一次位置信息等
  2. 浏览器播放事件,每个一秒计算一次进度信息等
  3. input 框实时搜索并发送请求展示下拉列表,每隔一秒发送一次请求 (也可做防抖)

代码如下,可以看出来节流重在加锁 timer=timeout

function throttle (f, wait) {
  let timer
  return (...args) => {
    if (timer) { return }
    timer = setTimeout(() => {
      f(...args)
      timer = null
    }, wait)
  }
}

总结

  • 防抖: 防止抖动,单位时间内事件触发会被重置,避免事件被误伤触发多次,代码实现重在清零 clearTimeout 防抖可以比作等电梯,只要有一个人进来,就需要再等一会儿。业务场景有避免登录按钮多次点击的重复提交
  • 节流:控制流量,单位时间内,事件只能触发一次,与服务器限流(Rate Limit)相似, 代码实现重在开锁关锁 timer=timeout timer = null 节流可以比作过红绿灯,每等一个红灯时间就可以过一批。

链接

什么是防抖和节流,他们的应用场景有哪些
浅谈js防抖和节流

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.