分类 技术文章 下的文章

0、保存Map实例

NOTE:

如何引入天地图SDK请参考以前的文章

首先要做的肯定是保存Map实例,可以保存在Vue实例上:

this.Map = new T.Map(......);

或者保存在window上:

window.Map = new T.Map(......);

1、创建标注

创建标注使用的是工具类。下面都用点(Marker)来作为例子。

在页面中创建一个按钮,使用它的click事件来打开标注工具

<button @click="btnClick">添加点</button>

为了看起来不违和,你可以把这个按钮的样式做成和地图原生控件一样。

click事件中打开标注工具:

btnClick(){
  //如果标注工具已经存在,先关闭它
  window.marktool && window.marktool.close();

  //创建一个Icon实例
  let icon = new T.Icon({
    iconUrl: 'https://x.y.z/1.png'
  });

  //实例化工具
  let marktool = new T.MarkTool(window.Map, {
    icon,
    follow: true
  });

  marktool.open();
  window.marktool = marktool;
}

现在,点击添加点按钮的时候,鼠标指针将变成你定义的icon的样式,点击地图,就会在点击的位置留下一个标记。

2、给标记添加自定义的数据

标记肯定代表了某个实际的东西,需要补充额外的内容。可以在上一步给marktool注册一个mouseup事件,给刚刚创建的标记添加一个click事件,以便我们进行更多的操作:

//别忘了先保存一下Vue实例this:
let _this = this;
//onMarkMarked是Vue的Method
//e.currentMarker代表当前标记
marktool.addEventListener('mouseup', function (e) {
  _this.onMarkMarked(e.currentMarker);
});

VueonMarkMarked方法中:

onMarkMarked(marker){
  let _this = this;
  //直接添加数据
  marker.MyData = {foo: 'bar', baz: 'balabala...'};
  //保存marker,使页面中任何代码都能访问,就能任意赋值了
  //但要注意,currentMark保存的是当前标记,创建新标记时,它代表的是新的标记
  _this.currentMark = marker;
}

Vue的其他方法中给它赋值:

onModelClosed(){
  this.currentMark.myname = this.inputName;
  //......

  //可以在控制台看到marker实例中包含自定义的数据
  console.log(this.currentMark);
}

3、保存标记数据

首先获取到标记:

let markers = window.Map.getOverlays();

返回的是一个标记数组,如果有多个标记,根据需要,可能需要循环处理。这里假设只有一个marker标记。
标记信息含有很多无用的信息,我们需要的一般都是标记的坐标、自定义的数据。标记的样式由于是提前定义好的,所以并不会通过标记获取。

let lnglat = markers[0].getLnglat();
let { myname, MyData } = markers[0];

此时就可以保存到数据库了。


END

UPDATE:8/16

天地图的JavaScript3.0 API中提供了一些方法,在4.0的文档中没有,但是仍然可用,比如设置地图的样式:

map.setMapType(...)

1、引入天地图API

按需引入,在需要用到天地图API的时候,动态创建script标签:

//某组件
...
mounted() {
    this.initMap();
},
...
//methods
initMap(){
    let script = document.getElementById('MapDivId');
    if (script) {
        return this._initMap();
    }

    const _this = this;
    script = document.createElement('script');
    script.id = 'MapDivId';
    script.src = 'https://tianditu.gov.cn/xxxxxxxx';
    script.onload = function () {
        _this._initMap();
    };

    document.body.appendChild(script);
}

二、初始化地图

...
_initMap() {
    //添加卫星图层,下面这个url是固定的,我只找到这种默认显示卫星图层的办法
    let satelliteLayerUrl = "http://t0.tianditu.gov.cn/img_w/wmts?" + "SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles" + "&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=您的密钥";
    let layer = new T.TileLayer(satelliteLayerUrl, { minZoom: 3, maxZoom: 18 });
    window.GIS.Map = new T.Map('Map', { layers: [layer] });
    // 定位到一个默认的坐标,例如北京。这里的坐标是虚构的
    window.GIS.Map.centerAndZoom(new T.LngLat(123.45678, 30.1234), 12);

    //添加地图类型控件
    let ctrlMapType = new T.Control.MapType([
        {
            title: '卫星混合',
            icon: 'http://api.tianditu.gov.cn/v4.0/image/map/maptype/satellitepoi.png',
            layer: TMAP_HYBRID_MAP
        },
        {
            title: '地图',
            icon: 'http://api.tianditu.gov.cn/v4.0/image/map/maptype/vector.png',
            layer: TMAP_NORMAL_MAP
        }
    ]);
    window.GIS.Map.addControl(ctrlMapType);

    //添加缩放控件
    let ctrlZoom = new T.Control.Zoom();
    window.GIS.Map.addControl(ctrlZoom);
    ctrlZoom.setPosition(T_ANCHOR_BOTTOM_RIGHT);

    //添加比例尺控件
    let ctrlScale = new T.Control.Scale();
    window.GIS.Map.addControl(ctrlScale);
},
...

三、添加各种标注工具

首先编写HTML结构,定位到地图上的某个位置,并绑定一个click事件,这部分很简单,效果如下:

1.png

然后编写click事件代码:

<span class="icon xxxx" @click="openPolygonTool"></span>
openPolygonTool() {
    if (window.GIS.handler) window.GIS.handler.close();
    let handler = new T.PolygonTool(window.GIS.Map);
    handler.open();
    window.GIS.handler = handler;
}

效果如下:

2.png

四、保存标注数据

一般在打开标注工具的时候,注册一个相关事件,这样,在结束标注的时候,就能获取到标注的数据。多边形的结束事件是draw

openPolygonTool() {
    ...
    handler.addEventListener('draw', function(e){
        console.log(e);
    });
    handler.open();
    ...
}

到这里,就可以把需要的数据存储起来了。

END

还没仔细研究antd vue的代码,所以动态菜单图标的显示机制还没弄明白,时间仓促,临时找到一个解决办法。

1、选好所需图标

iconfont网站上选好要用的图标,放到一个项目中,在项目设置中,把图标前缀改成anticon,更新代码后,选择下载到本地或者复制在线地址。

2、在public/index.html文件中引用图标

如果下载到本地,就把资源复制到public/static/下,然后在index.html中引入,或者直接引入复制的在线网址。

3、在菜单中使用图标

在系统设置-菜单管理中,在图标一栏填入图标的名字,注意不要带前缀。图标的名字可以在iconfont网站上,鼠标放到项目中的图标上,直接点击复制
当然,也可以在页面的任意位置用任意标签使用图标:

<span class="anticon anticon-tubiao"></span>

4、在任意全局的地方(比如index.html中)加入下面的css代码:

<style>
  .anticon:before {
    display: block !important;
  }
</style>

为什么要在iconfont的项目设置中修改图标前缀呢?因为antd vue图标的class就是anticon
重置.anticon:before的样式,目前也没有发现任何副作用。

有更好的方法欢迎留言告诉我。

END

在一个宽度100%,也就是宽度不固定的容器中,里面有横向排列并且会换行的列表项,列表项的宽度固定,所以每行列表项的个数随着容器的宽度变化:

<div class="box">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    ....
</div>
.box{
    display: flex;
    flex-wrap: wrap;
}
.item{
    width: 200px;
    height: 300px;
    margin-bottom: 20px;
}

在列表项不超过一行的时候表现很正常,但是在出现换行的情况下,每行最后可能会出现比较大的空白,这是因为虽然这行剩余的空间放不下一个.item了,但可能只比.item的宽度小一点点:

1.png

我们的目的是,让列表两端对齐,每个项的边距一样大,最后一行如果有空缺,那么就左对齐:

3.png

如果给.box设置下面的样式会怎样呢:

.box {
    ......
    justify-content: space-between;
    ......

如果一共5个.item,每行显示3个.item,结果会像这样:

2.png

解决办法就是补齐缺少的.item。因为第二行缺少1个.item,我们可以给它补上一个看不见的、高度是0的.item

<div class="box">
    ......
    <div class="item"></div>
    <div class="item placeholder"></div>
    ....
</div>
.placeholder{
    visibility: hidden;
    height: 0;
}

这时候就达到了最初的目的:

3.png

那如果每行显示4个、5个项,最后一行缺少2个、3个……怎么办?
如果你能知道你的列表最多有几个列,就可以补上几个.placeholder。如果你不确定,那么可以补多一些,保证补的.placeholder数量多于可能会出现最多的列数。因为.placeholder的高度是0,所以不会对垂直方向的布局产生影响。

这样有一个缺点:随着改变窗口大小,会发现.item之间的空隙忽大忽小。这是因为随着.box的宽度变化,行剩余的空间随之变化,行中的.item的间隙是flex动态计算的,所以会不断变化。如果你不能接受这一点,可以继续往下看。

我们设置固定的边距,并且让列表看起来两端对齐:

.box {
    ......
    /* 删掉或注释掉下面一行 */
    /* justify-content: space-between; */
    /* 设置负margin是为了让列表看上去两端对齐,两边不出现空白 */
    margin: 0 -10px 0;
    ......
}

.item可以扩展宽度并设置基本宽度:

.item {
    flex: 1 200px;
    /* 删掉或注释掉下面一行 */
    /* width: 200px */
    margin: 0 10px 20px;
}

这样,随着.box宽度的变化,.item之间的边距不再变化。但是每个.item的宽度又会跟着变化了,道理同上。不过,宽度变化视觉上要好于边距变化,个人倾向于这种方法。

下面是第二种方法的完整代码:

<div class="box">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <!-- 个数根据需要增减 -->
    <div class="item placeholder"></div>
    <div class="item placeholder"></div>
    ....
</div>
.box{
    display: flex;
    flex-wrap: wrap;
    margin: 0 -10px;
}
.item{
    flex: 1 200px;
    height: 300px;
    margin: 0 10px 20px;
}

END

现在的各种APP,只要注册,就必须把自己的手机号交给它们,想要使用某些功能,还必须要实名认证,甚至还要刷脸认证,理由是“根据监管……”也不知道是真的还是假托这样的理由。更有甚者,比如支付宝,不仅要你的身份信息、人脸信息,还千方百计引诱你交出车牌号、社保卡号、公积金账户、教育经历、学历、入职公司……等一切有价值的隐私信息,真让人害怕。

现在国内的APP在滥用用户个人信息方面已经不成样子了,用户毫无隐私可言。各大互联网公司互通有无,你在这个平台上浏览了某个商品,另一个APP上马上为你推荐这类商品。这还不算什么,要是有无良公司把你的信息卖给所谓的金融公司、野鸡招聘网……等等,那你就面临被诈骗的风险。

昨天滴滴被国安部查了,事情非常严重。滴滴掌握的这些信息对国家安全都有影响。

既然这样,为什么不让国家牵头,建立一个统一的认证中心呢?这个中心对外提供接口,接受加密的用户验证信息,在此过程中确保互联网公司不能获取到用户信息;验证通过后,只要返回true或者false来告诉互联网公司验证结果。这样一来,互联网公司没理由再收集用户信息了,国家又能提供权威的验证,又掌握了公民的信息安全,技术上难度也不大,这对国家对个人都有好处,唯一不高兴的肯定是那些大公司了。

不过这样做也不能解决所有问题。就比如钉钉,现在小学校都在用它留作业、交作业,家长也需要参与进去。这样,钉钉能获取的信息简直太丰富了:孩子的基本信息、位置信息、家庭信息、父母信息、孩子的学校班级、学习成绩、班级排名,进而分析出学生的学习习惯、生活习惯、性格,学校的基本信息、教学状况等、家长的财务状况、文化水平……,通过关联其他APP还能获得更多的信息,简直取之不尽……

希望国家重视这类信息的监管,这些信息掌握在国家手里我是放心的。

0、前言

vs code市场里面的主题很多。然而数量虽多,却很难找到一个完全符合自己心意的主题,往往总有几个地方是自己不满意,或者无法接受的。市场中主题的预览图因为一些原因无法打开,只能把主题安装后再应用,才能看到效果,这也导致想要找到一个合适的主题非常麻烦。为什么不自己制作一个简单的主题呢?

我们不是vs code扩展的开发者,不可能从头阅读大量的开发手册。我们要做的是,找到一个最简单的办法,制作出自己的主题。

1、生成扩展

首先需要安装扩展生成器,用来生成vs扩展的基本框架。
用管理员身份打开命令提示符,定位到你想要存放代码的位置,输入并运行下面的命令:

npm install -g yo generator-code

安装完毕之后,使用下面的命令来生成扩展的基本结构:

yo code

运行上面的命令,需要你输入或者选择一些内容,大概是:

是否发送反馈
创建扩展类型,这里选择颜色主题
是创建新的还是导入现有的
主题是浅色还是深色、名称、创建者、其他用户在市场中看到的主题名等等
是否初始化git仓库
等等

根据提示和自己的需要,直到提示创建成功。创建好的文件在命令提示符所在的目录。用vs code打开此目录,结构是这样的:

1.png

themes文件夹下的json文件就是我们要编辑的主题文件。

主题的各种配置十分繁琐。为了节省时间,我们首先在主题市场中找到一个看起来比较顺眼的主题,找到主题配置文件,一般在\Users\你的用户名\.vscode\extensions\扩展名称\themes\主题名称.json,打开它,发现它和你的json文件结构是一样的,大概如下:

2.png

其中的colors配置界面的配色,tokenColors配置语法高亮。

如果你需要定制自己独特的配色,当然可以从头配置各项的颜色,具体的配置在这里:

https://code.visualstudio.com/api/extension-guides/color-theme

如果你也只是希望修改一下刚刚下载的那个主题,那就可以先复制粘贴,用那个主题的配置覆盖你的配置,然后在此基础上修改自己不满意的地方。注意不要把自己主题的名字之类的东西覆盖。

保存之后,按F5进入调试模式,此时会打开一个新的vs窗口,你可以在这个窗口中打开任意文件,用来观察效果。修改json文件并保存后,调试窗口立刻显示出修改后的效果。

2、修改界面配色

以修改编辑器的背景颜色为例。

打开一个颜色拾取器,比如微信截图,将鼠标放到编辑器编辑区内,获取其色值。色值需要16进制格式,如果你获取的是RGB格式,还需要转换一下。接下来在你的json文件中查找并替换这个16进制的颜色。
这里介绍一个小技巧。如果你仅仅想修改颜色的深浅,那么你可以打开一个在线LESS编辑器,使用darken或者lighten函数并编译成css来获得新色值。
替换并保存之后,在调试窗口查看效果。
重复上面的过程,直到把自己想要修改的地方都改好。

3、修改语法高亮配色

语法配色当然也可以从头配置,参考这个链接:

https://code.visualstudio.com/api/language-extensions/syntax-highlight-guide

配置也是非常复杂的。这里还是在别人的主题基础上修改。
参照现有配置,发现tokenColors对象是一个数组,数组的每一个项都是一个对象,这就是一个配置项,结构如下:

{
    "name": "xxxx",
    "scope": [
        "variable.language.this.js",
        "support.type.property-name.json.comments"
    ],
    "settings": {
        "fontStyle": "bold",
        "foreground": "#0094f0"
    }
}

我们新建一个配置项,其中的name是任意命名的,settings也好理解,大概就是颜色、粗体、斜体、下划线等有限几个配置,至于scope,就需要使用下面的命令来获取了:

3.png

如果你想要调整JavaScript语法高亮的配色,需要用任意窗口打开任意一个js文件,为了方便观察效果,这里就在调试窗口里打开一个js文件,按Ctrl+Shift+P打开运行输入框,运行图中的命令。运行后,当你在文件中点击代码时,会弹出一个窗口,告诉你你点击的代码所属的scope

4.png

一般第一行就是我们想要的scope。复制这一行,粘贴到上面我们新建的配置项中的scope字段中。如果有多个scope用同一个配置项,需要用逗号隔开不同的scope。

保存查看效果。在关键字、函数名、变量名...之上点击鼠标,查看它们的scope名,并按需建立不同的配置项,来实现不同的代码不同的配色。

满意后,按ESC关闭scope查看窗口。

4、打包主题

扩展编辑完毕后,就需要打包了。因为我们不想发布到市场,所以只打包到本地就可以了。如果你想把你制作的主题发布到市场,请参阅vs相关文档。

用管理员身份打开命令提示符,运行下面的命令安装VSCE:

npm install -g vsce

安装好之后,定位到开发文件夹,运行:

vsce package

如果配置正确,就会输出一个.vsix包到你的开发目录下。拖动这个文件到VS的扩展窗口,就可以安装这个主题,在主题列表里选择并应用这个主题。也可以把这个文件分享给别人使用。

至此,简单的自定义vs code主题开发完成了。下面是我比较喜欢的样式:

HTML,自定义组件粗体显示:
5.png

JavaScript:
6.png

LESS:
7.png

End

以前,删除好友后,只要对方没有把你删除,再把TA添加回来,对方是没有任何提示的。但是事情从今天开始可能就变了。

今天我在实验的时候发现,即使对方没有把你删除,你在添加对方时,如果对方开启了验证,已经需要发送验证请求了,如果对方没有开启验证,那对方还是没有任何提示的。

所以在此提示大家,珍惜友情,谨慎删除好友。本次实验用的是我自己的小号 :-)

End

Windows 11泄露大概一周时间了,昨天晚上微软正式发布了Windows 11,今天工作不太忙,就想体验一下新系统,于是下载了iso文件,解压缩,双击setup.exe,按照提示一步一步来,非常简单,就像安装一个普通程序。安装过程中重启了3次,就进入到了新系统。虽然安装在系统盘的程序不见了,但是文档应该都还在,因为重装了微信之后,聊天记录都在。

首先看到的就是居中的开始菜单,第一次进入桌面时,它是展开着的。这些图标的排列有点像安卓系统,比磁贴要好看多了,至少没有了毫无意义的背景色块。“已固定”和“推荐的项目”位置是固定的,即使里面没有任何条目也还是显示在那里,不能调整大小和隐藏。如果条目太多,就会出现安卓桌面地下那种“小白点”来指示当前处于第几页。“所有应用”因为变成了一个比较小的按钮,所以感觉不那么容易进入所有程序列表了。整个开始菜单透明度没有提升。便利性方面,应该是不如以前方便了,视觉上更好看了。

微信截图_20210625150722.png

接下来是任务栏。任务栏除了图标居中外,其他变化不大。在任务栏上单击右键只有一个“任务栏设置”选项,想打开“任务管理器”需要在开始按钮上单击右键。目前调整任务栏的大小需要调整注册表,有大、中、小三种,图中是最小的样子。

2.png

然后就是新风格的壁纸了。现在好像非常流行这种抽象的壁纸,Windows终于也赶上时代了。

其他的改变就是窗口在不是最大化的状态下,有了一个圆角的样式,至于有什么感受呢,说不上来。做出这样一个改变,不知道微软花了多大力气,为什么不恢复Windows 7那种透明效果呢?现在的样式显得窗口很厚重。

3.png

下面这个功能还是挺不错的,想要显示多个窗口更方便了。只要把窗口从边缘拖回,窗口就能恢复之前的大小。

4.png

还有需要提一下的是窗口最大化最小化的动画。动画用了一个缓动效果,先慢后快,可惜动画感觉完全倒退了,刚开始的慢让人感觉电脑响应慢、卡顿,没有了Windows 8的轻盈,动作显得沉重,最小化窗口的时候有明显的延迟,让人感觉非常笨重和不流畅。很多窗口在最小化的时候,窗口内容变为一片空白,在动画的过程中,除了尺寸变化,没有透明度等其他变化。

打开app的时候,窗口的位置还是让人非常迷惑,和Windows 10一样,窗口不是居中的,而是在左侧,至于具体是左上还是左下,我还没摸清规律。这一点让我感觉到非常莫名其妙,关于窗口位置这一点,从Windows 8开始,我到现在“还没get到微软的点”。

安全中心的图标现在常驻状态栏,我没找到不显示的办法。

现在Windows 10还很不完善,大多数菜单不支持中文。Windows会自动下载需要的中文包,可是一直是失败状态。网上说是因为微软还没上传中文资源。

总而言之,这次Windows 10到Windows 11更像是修改了一下UI,修改的还非常有限,易用性没有任何提升,流畅度也没什么进步。想到微软的印度裔CEO说的“Windows 11是全新一代Windows”,我更佩服三哥吹牛的能力了。

结论:目前泄露版不值得折腾体验,应该耐心等待后续版本的优化和提升。

End

应该有挺多人遇到了这一问题,就是formidableparse无论如何也不执行,找了很多原因,尝试了很多方法,都不管用。

const formidable = require('formidable');

const form = new formidable({
    multiples: true,
    uploadDir: path.join(__dirname, '../ ', '../', '../', 'public', 'uploads'),
    keepExtensions: true
});

form.parse(req, (err, fields, files) => {
    console.log(0); // 不执行
})

我也遇到了这种情况。在parse上选择转到定义,在formidable - parse的源码中添加console,可以看到实际上parse是执行了的,但是浏览器一直在转圈,node端也没有反应,说明这时node不知道怎么处理这个请求,一直处在等待状态。

既然不是formidable的问题,那肯定是请求有问题。
这是一个POST请求,请求由submitbutton触发,由HTML的form发出。
既然是由form发出的请求,那我们来检查一下form的配置是否正确。form如下:

<form method="POST" action="user/add">
  <file/>
</form>

问题就在这里了。这里的form好像缺少一个常用的属性:enctype。这个属性有3个取值,其中有一个值是multipart/form-data,它的描述是:不对字符编码。当使用有文件上传控件的表单时,该值是必需的,而我们的form里面恰恰有一个file
所以,给form加上这个属性试试:

<form method="POST" action="user/add" enctype="multipart/form-data">
......

问题解决了。

End