分类 Javascript 下的文章

绘制虚线圆

最近有绘制虚线圆圈的需求,简单封装了一下,这里记录一下以便将来查阅:

    ctx.save()
    ctx.strokeStyle = CIRCLE_COLOR
    ctx.lineWidth = 2

    const step = 120   // 圆的总共段数 最好能被360整除
    const count = Math.floor(360 / step)
    let s = count / 180 * Math.PI * 2

    for (let b = 0, e = s / 2; e <= 360; b += s, e += s) {
      ctx.beginPath()
      ctx.arc(x, y, radius, b, e);  
      ctx.stroke();
    }

    ctx.restore();

实现地图指定显示范围在指定区域内

大部分地图框架的地图对象都会有一个方法是设置地图当前显示范围
如高德地图:
setBounds(bound:Bounds) // 指定当前地图显示范围,参数bounds为指定的范围
我们只需要传入希望地图显示的范围区域,地图框架自动计算合适的center 中心点 和zoom 层级

但是有时候我们做地图展示页面,而为了美观我们会把地图设置为整个屏幕,对应的窗体浮动显示在地图上层.
如图
地图显示

地图的实际有效范围只在中间这部分.

通过有效范围在实际地图容器中的位置,宽高比值,我们根据希望实际显示容器中的范围计算得到修正后的真实显示范围,
然后调用地图显示范围时传入真实显示范围后,在实际显示区域中则会刚好是我们希望地图显示的范围区域.
这里记录一下核心代码:

/**
 * 返回修正后的Bounds范围:
 * 地图区域有遮挡或者其他内容时,传入目标返回以及偏移值,返回修正后的范围
 * 主要和map.setBounds方法配合使用.
 * @param {AMap.Bounds} sourceBound 
 * @param {Number} left 地图显示有效区域距离实际地图容器左侧比例
 * @param {Number} top 地图显示有效区域距离实际地图容器上方比例
 * @param {Number} width 地图显示有效宽度与实际地图容器宽度比值
 * @param {Number} height 地图显示有效高度与实际地图容器高度比值
 */
export function getFixMapBound(sourceBound, left, top, width, height) {
  let minPoint = sourceBound.getSouthWest()
  let maxPoint = sourceBound.getNorthEast()

  // 计算出原区域的经纬度差值
  let subX = maxPoint.getLng() - minPoint.getLng()
  let subY = maxPoint.getLat() - minPoint.getLat()


  let addX = subX / width - subX // 总共需要增加的经度值
  let addY = subY / height - subY // 总共需要增加的维度值

  let topY = subY * top / height // 头部维度差值
  let leftX = subX * left / width // 左边经度差值
  let rightX = addX - leftX
  let bottomY = addY - topY

  let minXY = [minPoint.getLng() - leftX, minPoint.getLat() - bottomY]
  let maxXY = [maxPoint.getLng() + rightX, maxPoint.getLat() + topY]

  return new AMap.Bounds(minXY, maxXY)
}

以上是高德的修复Bounds范围的代码,改成其他地图框架只要根据其他地图框架的实际对象,微调AMapBounds,maxPoint和minPoint即可.

以下是调用代码的简易代码.

      var bounds = xxxx    // 希望地图显示的范围区域
      // 根据希望显示的范围区域,拿到实际地图应该传入的修正区域
      var fixBounds = getFixMapBound(
        bounds,
        0.25,    // 有效区域距离地图容器左边是25%距离
        0.1,    // 有效区域距离地图容器上方是10%距离
        0.5,    // 有效区域的宽度与实际地图容器的宽度比值为0.5 : 1
        0.9    // 有效区域的高度与实际地图容器的高度比值为0.9 : 1
      )
      map.setBounds(fixBounds)    // 让地图根据修正后的区域设置显示范围,则地图的有效范围刚好是显示bounds的范围区域

getFixMapBound方法也支持负数.

js代码模拟实现输入框input事件

一些时候我们要做网页插件时往往需要去做很多输入框自动赋值,去实现对应功能.
随着web前端发展,MVVM框架的流行,很多页面想要实现自动赋值不再向以前那样对输入框简单的赋值即可,还需要对应的触发相关的事件让对应框架去取值才行.
一般情况下,最常见的就是发送输入框input事件了,(如vue的v-model本身就是自动帮你绑定了input事件去取值)
这里简单封装了一个方法.

window.___inputValue = function (dom, st) {
  var evt = new InputEvent('input', {
    inputType: 'insertText',
    data: st,
    dataTransfer: null,
    isComposing: false
  });
  dom.value = st;
  dom.dispatchEvent(evt);
}

简单的调用:

window.___inputValue(document.querySelector('input'),'输入要赋值的内容')

这方面的资料相对较少,这里记录一下以便将来需要用到时查阅方便.

vue中实现jsx语法编译

vue的template模板在平时写业务代码的时候非常好用,但是很多时候封装vue组件的时候,template就没有那么灵活.
这个时候我们基本上会舍弃他的template模板,直接写render函数去渲染,这个时候要是可以用jsx语法,就会大大简化我们的代码以及提高代码可读性,并且让我们的代码看起来非常优雅.
简单记录一下vue通过babel编译实现在render函数中写jsx的要点:
首先需要安装babel-plugin-transform-vue-jsx
装好后npm会提示你babel-helper-vue-jsx-merge-props没装,所以一起装上.

npm install babel-plugin-transform-vue-jsx babel-helper-vue-jsx-merge-props --save-dev

如果只装这两个还是会报错,实际上这个插件里面还用到了babel-plugin-syntax-jsx,所以也装上.

npm install babel-plugin-syntax-jsx --save-dev

装完后在.babelrc的plugins添加上:

{
   ...,
   "plugins": [
    ...,
    "transform-vue-jsx"
  ]
}

最后记得在webpack的config文件加上对jsx文件的编译

{
  ...,
  module:{
    ...,
    {
      test: /\.jsx$/,
      loader: 'babel-loader'
    }
  }
}

现在就可以跟导入vue文件一样导入jsx文件了.(记得所有用jsx语法的文件用.jsx后缀结尾)

JSON.parse与JSON.stringify

平时我们用JSON.parse或者JSON.stringify的时候,经常只会传入一个参数,即:要序列化的对象或者反序列化的对象字符串.实际上这两个方法都可以传入第2个function参数去处理对应的value值.

function函数支持两个参数key,value分别对应处理后的key,value,可以通过函数去动态改变对应的value值.

    //JSON.stringify 示范代码.
    let data = {
        test: 'test',
        msg: '成功',
        data: {
            value: 1,
            text: 'hello',
            time: new Date()
        },
        time: new Date(),
        fun: function (a, b) {
            console.log(a + b);
        }
    }

    let jsonStr = JSON.stringify(data, (key, value) => {
        switch (key) {
            case 'test':
                return undefined;   //返回undefined,最终不会序列化
            case 'time':
                return value.replace('T', ' ');
            default:
                if (typeof value === 'function') { 
                    //简单处理函数的序列化方式,实际上真正的处理要复杂的多
                    return value.toString();
                }
                return value;
        }
    }, 4); //stringify还支持第3个参数格式化字符串(4代表4个空格,也可以输入字符串去代替.)

使用JSON.stringify的时候也要注意对象是否有toJSON这个方法.如果存在的话最终序列化会调用toJSON这个方法(一般情况不太可能重写js的序列化方法)

同样的,JSON.parse也支持第2个参数去处理最终的value值.

    let jsonObj = JSON.parse(jsonStr, (key, value) => {
        if (key === 'time') {
            return new Date(value);
        } else if (typeof value !== 'object' && /^function/.test(value)) {
            //简单的对函数进行处理.
            return eval('(' + value + ')');
        }
        return value;
    });

这让我们有些情况下处理序列化及反序列化得到很大的灵活性,不过似乎没有找到修改key的办法(除了改写toJSON),如果有的话请千万告诉我.^_^