初始化

This commit is contained in:
dengtongyu committed 2020-11-23 18:59:26 +08:00
commit 5efd5b9c40
129 files changed
+16739

No files matched your search

+155
View File
@@ -0,0 +1,155 @@
---
title: Angular CLI 之初体验
tags: []
id: '143'
categories:
- - 分享
date: 2017-09-20 17:13:04
---
[**Angular CLI**](https://cli.angular.io/)是一个**命令行界面**工具,它可以创建项目、添加文件以及执行一大堆开发任务,比如测试、打包和发布。 比起需要自己去搭建工作流,**[Angular CLI](https://cli.angular.io/)** 可以为你省去这些繁琐的工作,直接进行项目的开发。
## 配置开发环境
1. 安装最新版本的node,angular官方要求**node `6.9.x` 和 npm `3.x.x` 以上的版本。** 具体安装请参考 [node官网](http://nodejs.cn/) ,安装过程不再赘述。
2. 全局安装 [**Angular CLI**](https://cli.angular.io/)
```
npm install -g @angular/cli
```
## 创建新项目
1. 打开终端窗口 运行下列命令来生成一个新项目以及应用的骨架代码:
```
ng new myapp
```
2. 进入项目目录,并启动服务器。
```
cd myapp
ng serve --open
```
ng serve命令会启动开发服务器,监听文件变化,并在修改这些文件时重新构建此应用。 使用--open(或-o)参数可以自动打开浏览器并访问http://localhost:4200/。
![app-works](https://image.dengtongyu.com/blog/2017/09/app-works.png)
## 设置代理
1. 我们开发的时候,有时需要对接口做代理,**[Angular CLI](https://cli.angular.io/)**同样给我们提供了设置代理的方式
首先在项目的根目录下创建一个**proxy.conf.json** 文件
```
{
"/data": {
"target": "http://xxx.xxx.xxx.xxx:8080",
"secure": false,
"changeOrigin": true
}
}
```
"/data"是接口所包含的字符,target则是代理的ip和端口号
2. 然后在项目的根目录打开终端,运行下面的指令:
```
ng serve --proxy-config proxy.conf.json
```
这样代理的设置就完成了。
## 样式编译
**[Angular CLI](https://cli.angular.io/)** 支持sass、less、stylus等方式编译样式
1. 在创建项目时可以设置编译方式:
```
ng new myapp --style=sass
ng new myapp --style=less
ng new myapp --style=stylus
```
上面分别是创建项目时设定的样式编译方式:sass、less、stylus
2. 当然,你也可以在手动修改,在项目根目录下找到 **.angular-cli.json**
```
"defaults": {
"styleExt": "styl",
"component": {}
}
```
defaults下面的styleExt就是你要设定的编译方式,这里采用了stylus,stylus的后缀为styl,其他的方式设置对应的后缀名。
然后继续在该文件中找到
```
"styles": [
"styles.styl"
]
```
全改完了之后,不要忘了把项目**根目录**里的css文件和**src/app**里的css文件也改成相应的后缀
## 打包编译后资源引入根目录
**[Angular CLI](https://cli.angular.io/)** 打包编译后,引入的资源都是"/"根目录引入,但有时候我们的项目可能并不是存放在域名的根目录,所以这种情况就需要我们设置一下引入资源的根目录了
1. 打开src目录下面的**index.html**文件,在<head>标签里面有个base标签
```
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>myapp</title>
<base href="/">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>
```
base标签默认是"/"根目录
2. 然后我们回到整项目的根目录下面找到**package.json**文件,打开文件,找到"scripts",修改"build"的值
```
"scripts": {
"ng": "ng",
"start": "ng serve --proxy-config proxy.conf.json",
"build": "ng build --prod --bh /pages/myapp/",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
```
然后在命令行中输入
```
npm run build
```
等待编译完成后,在dist目录下的**index.html**文件中的base标签的值就变成你之前设置的目录了,引入的资源放到正式环境也可以正常访问。
当然,你也可以不设置**package.json**文件,直接在命令行输入
```
ng build --prod --bh /pages/myapp/
或者
ng build --prod --base-href /pages/myapp/
```
@@ -0,0 +1,58 @@
---
title: browser-sync代理接口在IE8下返回406问题
tags: []
id: '64'
categories:
- - 分享
date: 2016-06-28 10:15:34
---
正常情况下,代理返回的头信息为: HTTP/1.1 200 OK server?? ?Apache-Coyote/1.1 content-type?? ?application/json;charset=UTF-8 transfer-encoding?? ?chunked date?? ?Tue, 28 Jun 2016 02:07:39 GMT connection?? ?close   然而在IE8下面却返回了下面的头信息: HTTP/1.1 406 Not Acceptable server: Apache-Coyote/1.1 set-cookie: JSESSIONID=7F367B9EB53FDC8306D807E0A7BD4201; Path=/; HttpOnly content-type: text/html;charset=utf-8 date: Tue, 28 Jun 2016 02:01:31 GMT connection: close Transfer-Encoding: chunked   通过对比头信息,在代理设置里做了一下判断,在低版本IE浏览器重新设置一下头信息。
```js
var browserSync = require('browser-sync');
var proxyMiddleware = require('http-proxy-middleware');
var proxy_context = ['/service/web'];
var proxy_option = {
target: 'http://' + proxyConfig.host + ':' + proxyConfig.port,
//增加一个错误处理在window 7 ie7,8
onProxyReq: function(proxyReq, req, res){
var is4dot0 = false;
var acceptValue = "";
var acceptEncodeing = "";
var rawHeaders = req.rawHeaders;
rawHeaders.forEach(function(value, index){
if(value === "Accept"){
acceptValue = rawHeaders[index+1];
}
if(value === "Accept-Encoding"){
acceptEncodeing = rawHeaders[index+1];
}
if(value.indexOf("Mozilla/4.0") === 0){
is4dot0 = true;
}
});
if(is4dot0){
proxyReq.setHeader("Accept", acceptValue);
proxyReq.setHeader("Accept-Encoding", acceptEncodeing);
}
}
};
var proxy = proxyMiddleware(proxy_context, proxy_option);
browserSync({
host: 'local.xxx.com',
port: 3000,
open: 'external',
browser: 'google chrome',
ghostMode: false, // 每个页面的镜像独立,不相互影响
server: {
baseDir: "build",
middleware: [proxy]
}
});
```
@@ -0,0 +1,252 @@
---
title: egret 练手 《围住神经猫》
tags: []
id: '115'
categories:
- - 分享
date: 2017-09-04 11:42:10
---
Egret引擎是一个开源免费的游戏框架,用于构建二维游戏、演示程序和其他图形界面交互应用等。Egret使用TypeScript脚本语言开发。当游戏完成最终的打包后,可以将程序转换为HTML5游戏。实现跨平台特性。 Egret不仅仅是一个基于HTML5技术的游戏引擎,我们的产品线中除了Egret引擎还提供了很多辅助游戏开发的工具。准确的来说,Egret是一套游戏开发的解决方案。你可以使用Egret引擎来帮助你开发HTML5游戏,并运行在手机和PC端的浏览器中,同时也你可以使用Egret提供的相关工具搭建你自己的游戏开发工作流。 Egret的语法与ActionScript 3.0 一致,如果对as3.0熟悉的童鞋能很快上手。 果然有兴趣的童鞋可以直接去Egret的官网,有详细的文档资料 [白鹭引擎官网](https://www.egret.com/) 最近学习Egret,看了一些文档后,决定找个简单的项目自己练一下手,《围住神经猫》应该是个很好的选择。 先贴上完成的作品 [Demo](https://demo.dengtongyu.com/pages/nervcat/) **1.新建项目** 打开EgretWing --> 文件 --> 新建项目 --> Egret游戏项目 完成后打开 src 下的 Main.ts,改文件就是整个项目的入口文件,里面还有一些已经写好的方法,方便你后面调用。 具体请参考 [传送门](http://edn.egret.com/cn/article/index/id/579) 里面介绍得很详细 **2.加载进度条** 新建游戏项目后,默认的加载进度比较简陋,我们需要美化一下。 打开 src\\LoadingUI.ts 文件,这个就是加载进度条的类。
```
class LoadingUI extends egret.Sprite {
public constructor() {
super();
this.createView();
}
private textField:egret.TextField;
private createView():void {
this.textField = new egret.TextField();
this.addChild(this.textField);
this.textField.y = 300;
this.textField.width = 480;
this.textField.height = 100;
this.textField.textAlign = "center";
}
public setProgress(current:number, total:number):void {
this.textField.text = `Loading...${current}/${total}`;
}
}
```
从代码可以看出,进度条仅仅是用文字展示了加载进度,我们来加个进度条UI美化一下。
```
class LoadingUI extends egret.Sprite {
public constructor() {
super();
this.createView();
}
private textField:egret.TextField;
private pBarBg:egret.Shape;
private pBarMove:egret.Shape;
private createView():void {
this.pBarBg = new egret.Shape();
this.pBarBg.graphics.beginFill( 0x989898, 1);
this.pBarBg.graphics.drawRect( 0, 0, this.width, this.height );
this.pBarBg.graphics.endFill();
this.addChild(this.pBarBg);
this.pBarMove = new egret.Shape();
this.addChild(this.pBarMove);
this.textField = new egret.TextField();
this.textField.width = this.width;
this.textField.textAlign = "center";
this.textField.y = 15;
this.addChild(this.textField);
}
private moveProgressBar(percent:number):void{
this.pBarMove.graphics.beginFill( 0x518cdd, 1);
this.pBarMove.graphics.drawRect( 0, 0, this.width*percent, this.height);
this.pBarMove.graphics.endFill();
}
public setProgress(current:number, total:number):void {
var num = Math.floor(current / total * 100);
this.textField.text = 'Loading... ' + num.toString() + " %";
this.moveProgressBar(current/total);
}
}
```
效果如图: ![20170901165944](https://image.dengtongyu.com/blog/2017/09/20170901165944.png) **3.开始画面** 进度条弄好之后,我们开始做游戏开始的画面。如图: ![20170901171729](https://image.dengtongyu.com/blog/2017/09/20170901171729.png) 可以看出,开始画面由背景、网格地图和开始按钮的图片组成,这个实现起来很简单。
```
private mapGroup:eui.Group;//地图容器
private circleArray:Array<object>;//圆圈网格的数组
private bg:egret.Bitmap;//开始Bitmap
private popGroup:eui.Group;//开始画面容器
private btnStart:eui.Button;//开始按钮
private btnStartPng:egret.Bitmap;//开始Bitmap
private init():void{
//利用白鹭预设的创建bitmap方法创建背景图片
this.bg = this.createBitmapByName("bg_jpg");
this.stage.addChild(this.bg);
//地图容器
this.mapGroup = new eui.Group();
this.mapGroup.width = 560;
this.mapGroup.height = 560;
this.mapGroup.x = 40;
this.mapGroup.y = 400;
this.stage.addChild(this.mapGroup);
//开始画面容器
this.popGroup = new eui.Group();
this.popGroup.width = this.SW;
this.popGroup.height = this.SH;
this.popGroup.layout = new eui.BasicLayout();
this.stage.addChild(this.popGroup);
//开始Bitmap
this.btnStartPng = this.createBitmapByName("btn_start_png");
this.btnStartPng.scaleX = this.btnStartPng.scaleY = 1.2;
//开始按钮
this.btnStart = new eui.Button();
this.btnStart.width = this.btnStartPng.width;
this.btnStart.height = this.btnStartPng.height;
this.btnStart.horizontalCenter = 0;
this.btnStart.verticalCenter = 0;
this.popGroup.addChild(this.btnStart);
this.btnStart.addChild(this.btnStartPng);
this.btnStart.addEventListener(egret.TouchEvent.TOUCH_TAP,this.touchHandler,this);
}
private touchHandler(event:TouchEvent) {
this.popGroup.visible = this.btnStartPng.visible = false;
this.btnStart.removeEventListener(egret.TouchEvent.TOUCH_TAP,this.touchHandler,this);
}
然后在createGameScene方法里面执行this.init()就可以了。
但是我们还要绘制围住神经猫的9X9的网格地图。
我们在 src 下面创建一个自定义布局类,命名为 Map.ts
```
```
module uilayout {
var UIComponentClass = "eui.UIComponent";
/**自定义的布局类*/
export class CatMap extends eui.LayoutBase{
public constructor(){
super();
}
/**
* 计算target的尺寸
* 如果您的自定义布局需要根据内部子项计算尺寸,请重写这个方法
**/
public measure():void{
super.measure();
}
/**
* 重写显示列表更新
*/
public updateDisplayList(unscaledWidth:number, unscaledHeight:number):void{
super.updateDisplayList(unscaledWidth, unscaledHeight);
if (this.target==null)
return;
let sunElement:eui.UIComponent;
//子元素个数
let count:number = this.target.numElements;
//元素x轴方向间隔
let gapX:number = 0;
//元素y轴方向间隔
let gapY:number = 0;
//元素所在列数
let column:number = 0;
//元素所在行数
let row:number = 0;
//奇偶行数错位距离
let parityWidth:number = 0;
if(count > 0) {
sunElement = <eui.uicomponent> this.target.getElementAt(0);
gapX = (unscaledWidth - sunElement.width * 9 - sunElement.width / 2)/8;
gapY = (unscaledHeight - sunElement.height * 9 - sunElement.height / 2)/8;
//console.log(unscaledWidth,unscaledHeight,sunElement.width,sunElement.height);
}
for (let i:number = 0; i < count; i++){
let layoutElement:eui.UIComponent = <eui.uicomponent> ( this.target.getElementAt(i) );
if ( !egret.is(layoutElement,UIComponentClass) !layoutElement.includeInLayout ) {
continue;
}
row = Math.floor(i / 9);
column = i % 9;
if(row % 2 == 0) {
parityWidth = 0;
}else{
parityWidth = layoutElement.width / 2;
}
let childX:number = column * (layoutElement.width + gapX) + parityWidth;
let childY:number = row * (layoutElement.height + gapY);
layoutElement.setLayoutBoundsPosition(childX, childY);
}
}
}
}
```
这样一个自定义布局类就写好了,如果对自定义布局不太了解的,可以去Egret的官网查看文档 [传送门](http://edn.egret.com/cn/article/index/id/525) 然后,我们在Main.ts入口文件里绘制9X9的圆圈网格。
```
/**创建网格**/
private creatMap() {
this.circleArray = new Array();
for(let i = 0;i<81;i++){ let circleData = new Object(); circleData['ui'] = new eui.Group(); circleData['ui'].name = i; circleData['img1'] = this.createBitmapByName('pot1_png'); circleData['img2'] = this.createBitmapByName('pot2_png'); if(i == 40) { circleData['img1'].visible = true; circleData['img2'].visible = false; circleData['val'] = 0; }else{ if(Math.random()*10 > 8) {
circleData['img1'].visible = false;
circleData['img2'].visible = true;
circleData['val'] = 1;
}else{
circleData['img1'].visible = true;
circleData['img2'].visible = false;
circleData['val'] = 0;
}
}
this.circleArray.push(circleData);
circleData['img1'].scaleX = circleData['img1'].scaleY = 1.2;
circleData['img2'].scaleX = circleData['img2'].scaleY = 1.2;
circleData['ui'].width = circleData['img1'].width;
circleData['ui'].height = circleData['img1'].height;
//circleData['ui'].layout = new eui.BasicLayout();
circleData['ui'].addChild(circleData['img1']);
circleData['ui'].addChild(circleData['img2']);
if(i == 40) {//中间神经猫的位置
this.insertRunCat(circleData['ui']);
this.cat.visible = false;
this.catPos = 40;
}
if(circleData['val'] == 0) {
circleData['img1'].touchEnabled = true;
circleData['img1'].addEventListener(egret.TouchEvent.TOUCH_TAP,this.touchCircle,this);
}
this.mapGroup.addChild(circleData['ui']);
}
//引用自定义布局
this.mapGroup.layout = new uilayout.CatMap();
}
```
然后在init方法里面执行this.creatMap()就可以完成绘制了 ![20170901171508](https://image.dengtongyu.com/blog/2017/09/20170901171508.png) 后面的操作逻辑就不赘述了,有机会再跟大家分享。
@@ -0,0 +1,84 @@
---
title: egret 获取设备陀螺仪信息以及运动状态信息
tags: []
id: '217'
categories:
- - 分享
date: 2017-11-22 15:55:55
---
在最新版本的egret(5.0.12)中,已经支持了移动设备陀螺仪和运动状态的相关API。 **egret.DeviceOrientation** 可以监听设备方向的变化。 **egret.Motion**从用户设备读取运动状态信息并派发 CHANGE 事件。当设备移动时,传感器会检测到此移动并返回设备加速度,重力和旋转数据。 废话不多说,直接上代码:
```
class Main extends egret.DisplayObjectContainer {
private orientationLabel: egret.TextField;
private motionLabel: egret.TextField;
public constructor() {
super();
this.orientationLabel = new egret.TextField();
this.orientationLabel.width = 640;
this.orientationLabel.textAlign = egret.HorizontalAlign.CENTER;
this.addChild(this.orientationLabel);
this.motionLabel = new egret.TextField();
this.motionLabel.width = 640;
this.motionLabel.y = 300;
this.motionLabel.textAlign = egret.HorizontalAlign.CENTER;
this.addChild(this.motionLabel);
//创建 DeviceOrientation 类
var orientation = new egret.DeviceOrientation();
//添加事件监听器
orientation.addEventListener(egret.Event.CHANGE,this.onOrientation,this);
//开始监听设备方向变化
orientation.start();
//创建 Motion 类
var motion = new egret.Motion();
//添加事件监听器
motion.addEventListener(egret.Event.CHANGE,this.onMotion,this);
//开始监听设备方向变化
motion.start();
}
private onOrientation(e:egret.OrientationEvent){
this.orientationLabel.textFlow = >[
{text: "绕 Z 轴的角度:\n"}
, {text: e.alpha, style: {"textColor": 0xff0000}}
, {text: "\n\n绕 X 轴的角度:\n"}
, {text: e.beta, style: {"textColor": 0xff0000}}
, {text: "\n\n绕 Y 轴的角度:\n"}
, {text: e.gamma, style: {"textColor": 0xff0000}}
];
}
private onMotion(e:egret.MotionEvent){
this.motionLabel.textFlow = >[
{text: "X 轴方向的加速度\n"}
, {text: e.acceleration.x, style: {"textColor": 0xff0000}}
, {text: "\n\nY 轴方向的加速度:\n"}
, {text: e.acceleration.y, style: {"textColor": 0xff0000}}
, {text: "\n\nZ 轴方向的加速度:\n"}
, {text: e.acceleration.z, style: {"textColor": 0xff0000}}
, {text: "\n\nX 轴加速度(考虑重力加速度)\n"}
, {text: e.accelerationIncludingGravity.x, style: {"textColor": 0xff0000}}
, {text: "\n\nZ 轴方向的加速度:\n"}
, {text: e.accelerationIncludingGravity.y, style: {"textColor": 0xff0000}}
, {text: "\n\nZ 轴方向的加速度:\n"}
, {text: e.accelerationIncludingGravity.z, style: {"textColor": 0xff0000}}
, {text: "\n\n左右旋转速度(alpha轴向的角速度)\n"}
, {text: e.rotationRate.alpha, style: {"textColor": 0xff0000}}
, {text: "\n\n前后旋转速度(beta轴向的角速度)\n"}
, {text: e.rotationRate.beta, style: {"textColor": 0xff0000}}
, {text: "\n\n扭转速度(gamma轴向的角速度)\n"}
, {text: e.rotationRate.gamma, style: {"textColor": 0xff0000}}
];
}
}
```
首先创建了DeviceOrientation的实例orientation。并给他添加了一个事件侦听器,监听它的CHANGE事件。然后调用了他的start()方法来开始监听设备方向的变化。 当系统监听到了方向的变化后,将回调函数 onOrientation。然后通过egret.OrientationEvent事件的三个属性来获取设备的方向变化信息。 OrientationEvent的三个属性:alpha,beta和gamma。 alpha表示设备绕 Z 轴的角度,单位是 角度 beta 表示设备绕 X 轴的角度,单位是 角度 gamma 表示设备绕 Y 轴的角度,单位是 角度 同样,创建了Motion的实例motion。并给他添加了一个事件侦听器,监听它的CHANGE事件。然后调用了他的start()方法来开始监听设备方向的变化。 当系统监听到了方向的变化后,将回调函数 onMotion。然后通过egret.MotionEvent事件的三个属性来获取设备运动的具体信息。 acceleration 表示设备在 X Y Z 轴方将的加速度信息,单位是 m/s2,不包含重力。 acceleration 表示设备在 X Y Z 轴方将的加速度信息,单位是 m/s2,包含重力。 rotationRate 表示设备在 alpha、 beta 和 gamma 三个轴向的角速度信息,单位是 角度每秒。 最终的效果demo->[传送门](https://demo.dengtongyu.com/pages/orientation/) 或者手机扫一扫: ![egret陀螺仪demo](https://image.dengtongyu.com/blog/2017/11/下载-1.png)
@@ -0,0 +1,60 @@
---
title: egret3d 用视频video做纹理贴图
tags: []
id: '267'
categories:
- - 分享
date: 2018-01-29 17:50:02
---
前段时间学习了一下egret3d,然后有些奇妙的想法,如果用视频video来做纹理贴图可不可以呢?于是就尝试了一下,效果还不错。
思路也很简单,创建一个立方体,然后把立方的纹理设置成一个视频video,主要代码如下
```
public createGameScene() {
this.createVideoTexture();
this.loaderSkyBox();
}
//创建视频纹理
private createVideoTexture() {
this.video = new egret3d.VideoTexture(640,264);
this.video.source = "resource/oceans-clip.mp4";
}
// 加载资源
private loaderSkyBox() {
this.queueLoader = new egret3d.QueueLoader();
this.queueLoader.load("resource/background.jpg");
this.queueLoader.addEventListener(egret3d.LoaderEvent3D.LOADER_COMPLETE, this.onSkyBoxTexture, this);
}
// 资源加载完成 创建立方体
private onSkyBoxTexture(e: egret3d.LoaderEvent3D) {
// 设置背景
let panelIamge: egret3d.ITexture = this.queueLoader.getAsset("resource/background.jpg");
this.view.backImage = panelIamge;
// 创建立方体和cube贴图
this.ge = new egret3d.CubeGeometry(200, 200, 200);
this.mat = new egret3d.TextureMaterial(panelIamge);
this.mat.diffuseTexture = this.video;
this.mesh = new egret3d.Mesh(this.ge,this.mat);
this.view.addChild3D(this.mesh);
// 更新摄像机信息
this.cameraCtl.distance = 1000;
this.cameraCtl.rotationX = 45;
this.cameraCtl.rotationY = 45;
this.cameraCtl.update();
}
```
效果->[传送门](https://demo.dengtongyu.com/pages/videocude/)
![视频贴图](https://image.dengtongyu.com/blog/2018/01/下载.png)
+93
View File
@@ -0,0 +1,93 @@
---
title: egret天空盒子浅尝
tags: []
id: '238'
categories:
- - 分享
date: 2017-11-22 18:35:36
---
现在移动端越来越多类VR的推广H5页面需求,egret恰好也有相关的API可以方便我们使用,这就是egret的天空盒子-**egret3d.Sky** 在 Egret 3D 所创建的空间中最外层是由天空盒子来包裹起来的。我们通常使用天空盒子来展现风景,地平线,天空,星空等等空间的“大背景”。天空盒子由一组无缝的贴图包裹起来的盒状空间。当我们的 3D 场景中包含有物体时,天空盒子总是充当其背景。 ![天空盒子](https://image.dengtongyu.com/blog/2017/11/images.jpeg) 环境:egret 5.0.12 IDE:egret wing 3
# 加载天空盒子素材资源
通过**egret3d.QueueLoader**加载器加载资源,然后监听资源加载完成事件**egret3d.LoaderEvent3D.LOADER\_COMPLETE**。
```
/**
* 加载器
*/
private queueLoader: egret3d.QueueLoader;
// 加载天空盒资源
private loaderSkyBox() {
this.queueLoader = new egret3d.QueueLoader();
this.queueLoader.load("resource/front.png");
this.queueLoader.load("resource/back.png");
this.queueLoader.load("resource/left.png");
this.queueLoader.load("resource/right.png");
this.queueLoader.load("resource/up.png");
this.queueLoader.load("resource/down.png");
this.queueLoader.addEventListener(egret3d.LoaderEvent3D.LOADER_COMPLETE, this.onSkyBoxTexture, this);
}
```
# 创建天空盒子
资源加载完成后,用**egret3d.Sky**创建天空盒子,**egret3d.Sky**方法有三个参数, Sky(geometry:egret3d.Geometry, material:egret3d.MaterialBase, camera:egret3d.Camera3D), 分别是3D几何形状,纹理贴图,摄像机。然后把天空盒子添加到3D显示类里。
```
// 天空盒资源加载完成 创建天空盒
private onSkyBoxTexture(e: egret3d.LoaderEvent3D) {
var loader: egret3d.QueueLoader = e.target;
var fr: egret3d.ITexture = loader.getAsset("resource/front.png");
var bk: egret3d.ITexture = loader.getAsset("resource/back.png");
var lf: egret3d.ITexture = loader.getAsset("resource/left.png");
var rt: egret3d.ITexture = loader.getAsset("resource/right.png");
var up: egret3d.ITexture = loader.getAsset("resource/up.png");
var dn: egret3d.ITexture = loader.getAsset("resource/down.png");
// 创建cube贴图
var cubeTexture: egret3d.CubeTexture = egret3d.CubeTexture.createCubeTextureByImageTexture(bk, fr, lf, rt, up, dn);
// 创建cube geometry 和 cube 材质
var sky: egret3d.Sky = new egret3d.Sky(new egret3d.CubeGeometry(500, 500, 500), new egret3d.CubeTextureMaterial(cubeTexture), this.view.camera3D);
// 设置天空盒 渲染模式为背面渲染
sky.material.cullMode = egret3d.ContextConfig.FRONT;
this.view.addChild3D(sky);
}
```
# 获取陀螺仪信息
我们需要通过获取陀螺仪信息来根据手机的旋转,让天空盒子视角旋转对应的角度。
```
// 获取设备旋转角度
private setOrientation() {
//创建 DeviceOrientation 类
var orientation = new egret.DeviceOrientation();
//添加事件监听器
orientation.addEventListener(egret.Event.CHANGE,this.onOrientation,this);
//开始监听设备方向变化
orientation.start();
}
private onOrientation(e:egret.OrientationEvent){
this._alpha = e.alpha;
this._beta = e.beta;
this._gamma = e.gamma;
this.cameraCtl.rotationY = (this._alpha % 360) * (-1);
this.cameraCtl.rotationX = (this._beta - 90) % 360 * (-1);
this.cameraCtl.rotationZ = 0;
//console.log(e.rotationRate)
}
```
最终效果->[传送门](https://demo.dengtongyu.com/pages/boxsky/) 手机扫一扫 ![egret天空盒子demo](https://image.dengtongyu.com/blog/2017/11/下载-2.png)
@@ -0,0 +1,181 @@
---
title: egret引用Animate CC发布的HTML5 Canvas
tags: []
id: '252'
categories:
- - 分享
date: 2017-12-15 18:04:34
---
在flash时代,我们可以在Adobe Flash中导出swf,然后在ActionScript 3.0项目里面引用。让设计人员可以直接提供素材给开发人员,这大大提高了开发效率。
但在egret里,虽然官方也提供了很丰富的工具,但是不得不承认,目前并没有足够的设计人员参与进来,导致开发人员拿到素材后还要“二次加工”,开发效率自然上不去。
所以,在Adobe Animate CC已经普及的今天,我们能不能让Animate CC导出的HTML5 Canvas直接用到我们的项目里呢?
在我尝试了一翻后,确实能达到不错的效果。
# 1.建立引用路径
![egret引用HTML5 Canvas](https://image.dengtongyu.com/blog/2017/12/20171215173527.png)
在egret项目里建立一个存放Animate CC导出的HTML文件目录,这里我引用了/html/man的实例。里面的index.html和index.js是用Animate CC发布导出的
# 2.动画采集器
通过外部引用html,然后获取页面的canvas的bitmap,然后添加到egret的舞台上。
新创建一个类,命名为CollectAnimation.ts
```
class CollectAnimation extends egret.DisplayObjectContainer {
private _iframe:any;
private _canvas:any;
private _canvasBitmapData:any;
private _canvasTexture:egret.Texture;
private _canvasBitmap:egret.Bitmap;
private _oldCanvasBitmap:egret.Bitmap;
private _timer:egret.Timer;
public constructor(url:string) {
super();
this._iframe = document.createElement('iframe');
this._iframe.style.height = 0;
this._iframe.style.border = 'none';
this._iframe.style.display = 'none';
this._iframe.src = url;
document.querySelector('body').appendChild(this._iframe);
this._iframe.onload = () => {
this._canvas = this._iframe.contentWindow.canvas;
//console.log(this._canvas);
}
this._timer = new egret.Timer(50);
this._timer.addEventListener(egret.TimerEvent.TIMER,this.timerFunc,this);
}
public get getCanvasBitmap() {
if(this._canvas) {
this._canvasBitmapData = new egret.BitmapData(this._canvas);
this._canvasTexture = new egret.Texture();
this._canvasTexture.bitmapData = this._canvasBitmapData;
this._canvasBitmap = new egret.Bitmap(this._canvasTexture);
return this._canvasBitmap;
}else{
return null;
}
}
private timerFunc() {
if(this._canvas) {
this._canvasBitmapData = new egret.BitmapData(this._canvas);
this._canvasTexture = new egret.Texture();
this._canvasTexture.bitmapData = this._canvasBitmapData;
if(this._canvasBitmap) {
this._oldCanvasBitmap = this._canvasBitmap;
}
this._canvasBitmap = new egret.Bitmap(this._canvasTexture);
if(this._oldCanvasBitmap && this._oldCanvasBitmap.parent) {
this.removeChild(this._oldCanvasBitmap);
}
this.addChild(this._canvasBitmap);
}
}
public start() {
this._timer.start();
}
public stop() {
this._timer.stop();
}
public depose() {
if(this._iframe) {
this._iframe = null;
}
if(this._canvas) {
this._canvas = null;
}
if(this._canvasBitmapData) {
this._canvasBitmapData = null;
}
if(this._canvasTexture) {
this._canvasTexture = null;
}
if(this._canvasBitmap) {
this._canvasBitmap = null;
}
if(this._oldCanvasBitmap) {
this._oldCanvasBitmap = null;
}
if(this._timer) {
this._timer.stop();
this._timer = null;
}
if(this.parent) {
this.parent.removeChild(this);
}
}
}
```
# 3.在egret中使用
在Main.ts中使用我们刚刚创建的类
```
class Main extends egret.DisplayObjectContainer {
public constructor() {
super();
this.addEventListener(egret.Event.ADDED_TO_STAGE, this.onAddToStage, this);
}
private onAddToStage(event: egret.Event) {
let man = new CollectAnimation('html/man/index.html');
this.addChild(man);
man.start();
// setTimeout(() =>{
// man.stop();
// man.depose();
// man = null;
// },3000)
}
}
```
通过start和stop方法开始播放和停止,depose方法删除
以上就是在egret中引用HTML5 Canvas的一些尝试,还有别的东西可能要等我慢慢挖掘了。
效果->[传送门](https://demo.dengtongyu.com/pages/walkman/)
@@ -0,0 +1,74 @@
---
title: egret粒子系统官方文档的那些坑
tags: []
id: '200'
categories:
- - 分享
date: 2017-10-20 16:33:15
---
最近体验了一下[egret粒子系统](http://edn.egret.com/cn/article/index/id/178),看了官方文档后,照着文档写,发现各种报错,不知道是原来文档就是错误的,还是egret版本多次迭代后,文档没有及时更新,而且在[egret开发者中心](http://developer.egret.com/)提供的QQ群加了也没有回应,或许是egret官方太忙了,但是不管怎样,这种错误的官方文档对新手很不友好。
下面我来说说我在体验[egret粒子系统](http://edn.egret.com/cn/article/index/id/178)踩的一些坑
说到egret的粒子系统,egret官方提供了一个制作粒子素材的工具——[Egret Feather](http://developer.egret.com/cn/github/egret-docs/tools/Feather/manual/index.html)
有兴趣的可以移步到相关的官方文档查看,因为我使用[Egret Feather](http://developer.egret.com/cn/github/egret-docs/tools/Feather/manual/index.html)的时候没有遇到什么问题,所以这里就不做赘述了,大家看官方文档就好了
### egret粒子系统官方文档的错误?
在egret的粒子系统文档中([传送门](http://edn.egret.com/cn/article/index/id/178)),在创建粒子示例的地方是这样的
![egret粒子系统创建示例](https://image.dengtongyu.com/blog/2017/10/QQ截图20171020160019.png)
按照示例的代码在egret 4.0.3版本中,编译就会报错
```
error TS2339: Property 'system' does not exist on type 'Main'.
```
'system'这个属性不属于'Main',新人们在这里会懵逼一会儿,但是代码是死的,人是活的,我直接用个变量来保存particle对象嘛。我把代码改一下
```
let texture = RES.getRes("funny");
let config = RES.getRes("funny_json");
let funny = new particle.GravityParticleSystem(texture, config);
funny.start();
this.addChild(funny);
```
我用个变量funny来保存particle对象,然后我再编译一下,没有报错,但是刷新浏览器的时候报错了
```
Uncaught TypeError: Cannot read property 'textureWidth' of null
```
无法读取纹理的宽度,其值为null。出现这种报错一般就是纹理加载不成功,所以要看看加载素材的地方
```
let texture = RES.getRes("funny");
let config = RES.getRes("funny_json");
```
上面的纹理加载很明显与egret的素材加载方式有点不一样,不知道官方文档为什么会这样写,所以我改了一下,把纹理的后缀加上
```
let texture = RES.getRes("funny_png");
let config = RES.getRes("funny_json");
```
编译没有报错,刷新浏览器,粒子效果完美呈现。[demo传送门](https://demo.dengtongyu.com/pages/featherfunuy/)
![egret粒子系统demo](https://image.dengtongyu.com/blog/2017/10/下载.png)
### egret粒子系统库的引入,另一个坑?
egret粒子系统库的引入也是一个小坑,我从[egret第三方库的GitHub](https://github.com/egret-labs/egret-game-library)上下载了particle粒子库,然后放到项目里引入,结果编译时间很久,而且会各种报错,经过一系列的Google 百度后,结果是:
**第三方库必须放到项目外面!**
**第三方库必须放到项目外面!**
**第三方库必须放到项目外面!**
重要的事情说三遍
@@ -0,0 +1,41 @@
---
title: ES6 下定义变量,let大法好!
tags: []
id: '52'
categories:
- - 分享
date: 2016-06-16 22:37:51
---
  var _声明的变量作用域不是块级的,会扩大变量的作用域,可能造成变量污染。_ let _声明的变量作用域就更精确,离开作用域变量就销毁。_ const _顾名思义就是常量了。_ **变量作用域更加精准** 不用担心变量作用域自动提升,造成上一级或全局变量值被覆盖。 举个栗子:
```js
let a = 1;
var b = 1;
if (true) {
let a = 2;
var b = 2;
}
console.log(a) // 输出 1
console.log(b) // 输出 2
```
**变量作用域可控性更好** let 的作用域是根据代码块(enclosing block)来判定的,而 var 的作用域是根据函数块(function block)来判定的。这样的话,如果我们的变量都使用 let/const 来声明,那么以前的立即执行函数就不需要了,我们只要加一个代码块就好了。 举个栗子:
```js
{
let a = 1;
}
console.log(a) // 输出 a is not defined
```
**Runtime自动检查重复声明的函数并报错** 在同一个作用域内不允许重复声明变量。 举个栗子:
```js
if (true) {
let a = 1;
let a = 2;
}
```
Runtime会报错:Uncaught SyntaxError: Identifier 'a' has already been declared 有了更加清晰的作用域,我们的代码就能够更好被预测,也更好维护。 有了更容易控制的作用域可以让我们减少很多立即执行的函数。 Runtime的自动检查可以避免不必要,甚至是错误的代码声明。
@@ -0,0 +1,246 @@
---
title: https实践,Let's Encrypt 免费泛域名 SSL 证书申请
tags: []
id: '304'
categories:
- - 分享
date: 2018-07-12 11:26:42
---
![let's-encrypt](https://image.dengtongyu.com/blog/2018/07/lets-encrypt.png)
2018 年 3 月 14 日,Let’s Encrypt 对外宣布 ACME v2 已正式支持泛域名证书。这就意外味着用户可以在 Let’s Encrypt 上免费申请支持泛域名的 SSL 证书。
### 什么是 Let’s Encrypt
部署 HTTPS 网站的时候需要证书,证书由 CA 机构签发,大部分传统 CA 机构签发证书是需要收费的,这不利于推动 HTTPS 协议的使用。
[Let’s Encrypt](https://letsencrypt.org/) 也是一个 CA 机构,但这个 CA 机构是免费的!也就是说签发证书不需要任何费用。
[Let’s Encrypt](https://letsencrypt.org/) 是国外一个公共的免费 SSL 项目,由 Linux 基金会托管。由 Mozilla、思科、Akamai、IdenTrust 和 EFF 等组织发起,目的就是向网站自动签发和管理免费证书。以便加速互联网由 HTTP 过渡到 HTTPS,目前 Facebook 等大公司开始加入赞助行列。
Let’s Encrypt 已经得了 IdenTrust 的交叉签名,这意味着其证书现在已经可以被 Mozilla、Google、Microsoft 和 Apple 等主流的浏览器所信任。用户只需要在 Web 服务器证书链中配置交叉签名,浏览器客户端会自动处理好其它的一切,Let’s Encrypt 安装简单,使用非常方便。
### 什么是泛域名证书
泛域名证书类似 DNS 解析的泛域名概念,泛域名证书就是证书中可以包含一个通配符。主域名签发的泛域名证书可以在所有子域名中使用,比如 demo.domain.com、bbs.domain.com。这样就一张证书可以用于更多的主机了
### 如何申请 Let’s Encrypt 泛域名证书
Let’s Encrypt 上的证书申请是通过 ACME 协议来完成的。ACME 协议规范化了证书申请、更新、撤销等流程,实现了 Let’s Encrypt CA 自动化操作。解决了传统的 CA 机构是人工手动处理证书申请、证书更新、证书撤销的效率和成本问题。
ACME v2 是 ACME 协议的更新版本,泛域名证书只能通过 ACME v2 获得。要使用 ACME v2 协议申请泛域名证书,只需一个支持该协议的客户端就可以了,官方推荐的客户端是 Certbot。
#### 安装Certbot
如果没有下载安装过Certbot,先下载Certbot客户端
```
wget https://dl.eff.org/certbot-auto
```
然后把certbot-auto设为可执行权限
```
chmod a+x certbot-auto
```
#### 升级Certbot
如果已经安装了Certbot,查看下自己的Certbot客户端是不是支持 ACME v2 版本,官方介绍 Certbot 0.22.0 版本支持新的协议版本
```
./certbot-auto --version
Upgrading certbot-auto 0.21.1 to 0.25.1...
Replacing certbot-auto...
./certbot-auto --version
certbot 0.22.0
```
客户在申请 Let’s Encrypt 证书的时候,需要校验域名的所有权,证明操作者有权利为该域名申请证书,目前支持三种验证方式:
1. dns-01:给域名添加一个 DNS TXT 记录。
2. http-01:在域名对应的 Web 服务器下放置一个 HTTP well-known URL 资源文件。
3. tls-sni-01:在域名对应的 Web 服务器下放置一个 HTTPS well-known URL 资源文件。
#### 申请泛域名证书
申请泛域名证书,只能使用 dns-01 的方式
使用 Certbot 客户端申请证书方法比较的简单,输入以下命令:
```
./certbot-auto certonly -d domain.com -d *.domain.com --manual --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory
```
_1、把domain换成你自己的域名。_
_2、\*.domain.com可作用于所有子域名,但好像不能作用于domain.com,所以加上domain.com这样的裸域名。_
#### 相关参数说明
1. certonly,表示安装模式,Certbot 有安装模式和验证模式两种类型的插件。
2. \--manual 表示手动安装插件,Certbot 有很多插件,不同的插件都可以申请证书,用户可以根据需要自行选择
3. \-d 为那些主机申请证书,如果是通配符,输入 \*.domain.com(可以替换为你自己的域名)
4. \--preferred-challenges dns,使用 DNS 方式校验域名所有权
5. \--server,Let's Encrypt ACME v2 版本使用的服务器不同于 v1 版本,需要显示指定。
执行完这一步之后,就是命令行的输出,请根据提示输入相应内容:
```
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Cert is due for renewal, auto-renewing...
Renewing an existing certificate
Performing the following challenges:
dns-01 challenge for xxxxx.com
dns-01 challenge for xxxxx.com
-------------------------------------------------------------------------------
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.
Are you OK with your IP being logged?
-------------------------------------------------------------------------------
(Y)es/(N)o: y
```
上述有两个交互式的提示:
1. 是否同意 Let's Encrypt 协议要求
2. 询问是否对域名和机器(IP)进行绑定
确认同意才能继续。
继续查看命令行的输出,非常关键:
```
-------------------------------------------------------------------------------
Please deploy a DNS TXT record under the name
_acme-challenge.xxxxx.com with the following value:
XQOqY8npyso******ovtudA3zMd_C1dh9bjMEkbkKHM
Before continuing, verify the record is deployed.
-------------------------------------------------------------------------------
Press Enter to Continue
```
执行到上图最后一步时,先暂时不要回车。要求配置 DNS TXT 记录,从而校验域名所有权,也就是判断证书申请者是否有域名的所有权。接下来需要按照提示在域名后台添加对应的 DNS TXT 记录。
上面输出要求给 \_acme-challenge.XXXXX.com 配置一条 TXT 记录,在没有确认 TXT 记录生效之前不要回车执行。
我使用的是阿里云的域名服务器,登录控制台操作如下图:
![泛域名证书](https://image.dengtongyu.com/blog/2018/07/QQ20180711-181503@2x.png)
如上图所示,有两条DNS TXT,因为我们申请的时候就有两个域名,domain.com 和 \*.domain.com,所以我们在阿里云的后台添加一条DNS TXT后,我们回到命令行,按回车继续,然后会输出第二条DNS TXT
```
-------------------------------------------------------------------------------
Please deploy a DNS TXT record under the name
_acme-challenge.xxxxx.com with the following value:
XQOqY8npyso******ovtudA3zMd_C1dh9bjMEkbkKHM
Before continuing, verify the record is deployed.
-------------------------------------------------------------------------------
Press Enter to Continue
```
同样,按照上面的步骤在阿里云的后台多加一条DNS TXT解析就好。加完稍等几分钟后,回到命令行,按回车
```
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/dengtongyu.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/dengtongyu.com/privkey.pem
Your cert will expire on 2018-XX-XX. To obtain a new or tweaked
version of this certificate in the future, simply run certbot-auto
again. To non-interactively renew *all* of your certificates, run
"certbot-auto renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Press Enter to Continue
```
看到上面的输出,说明已经生效。
你也可以输入以下命令确认 TXT 记录是否生效:
```
dig -t txt _acme-challenge.XXXXXX.com @8.8.8.8
; <<>> DiG 9.10.6 <<>> -t txt _acme-challenge.XXXXXX.com @8.8.8.8
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 55138
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;_acme-challenge.XXXXXX.com.INTXT
;; ANSWER SECTION:
_acme-challenge.XXXXXX.com.599 INTXT"bQzqaEADZbE******KvPiltbucW130jaj9PNTkAH3mU"
_acme-challenge.dengtongyu.com.599 INTXT"XQOqY8npyso******ovtudA3zMd_C1dh9bjMEkbkKHM"
;; Query time: 175 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Thu Jul 12 10:59:20 CST 2018
;; MSG SIZE rcvd: 171
```
到了这一步后,恭喜您,证书申请成功。 证书和密钥保存在下列目录:
```
/etc/letsencrypt/live/xxx.com/
├── cert.pem
├── chain.pem
├── fullchain.pem
└── privkey.pem
```
然后校验证书信息,输入如下命令:
```
openssl x509 -in /etc/letsencrypt/live/xxx.com/cert.pem -noout -text
...
Authority Information Access:
OCSP - URI:http://ocsp.int-x3.letsencrypt.org
CA Issuers - URI:http://cert.int-x3.letsencrypt.org/
X509v3 Subject Alternative Name:
DNS:*.xxx.com
...
```
可以看到证书包含了 SAN 扩展,该扩展的值就是 \*.xxx.com
### 在 Nginx 中 配置 Let’s Encrypt 证书
Nginx 配置文件片断:
```
server {
server_name xxx.com;
listen 443 http2 ssl;
ssl on;
ssl_certificate /etc/letsencrypt/live/XXXXXX.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/XXXXXX.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
```
@@ -0,0 +1,53 @@
---
title: navigator.mediaDevices.getUserMedia调用本地摄像头
tags: []
id: '94'
categories:
- - 分享
date: 2017-04-28 15:20:27
---
MediaDevices.getUserMedia()方法提示用户允许使用一个视频和/或一个音频输入设备,例如相机或屏幕共享和/或麦克风。 如果用户给予许可,就返回一个Promise 对象,MediaStream对象作为此Promise对象的Resolved[成功]状态的回调函数参数,相应的,如果用户拒绝了许可,或者没有媒体可用的情况下,PermissionDeniedError 或者NotFoundError作为此Promise的Rejected[失败]状态的回调函数参数。 _注意,由于用户不会被要求必须作出允许或者拒绝的选择,所以返回的Promise对象可能既不会触发resolve 也不会触发 reject。_ 首先在页面中放置一个video标签,用来播放本地摄像头采集到的视频流
```
<video id="video" width="200" height="150" autoplay=""></video>
```
然后在js部分如下
```js
//获取video标签
var vedio = document.querySelector('#video');
//constraints 参数是一个包含了video 和 audio两个成员的MediaStreamConstraints
//对象,用于说明请求的媒体类型。必须至少一个类型或者两个同时可以被指定。
var constraints = {
audio: true,
video: {
//帧率
frameRate: { ideal: 10,max: 15,min: 8 }
}
}
//获取设备(摄像头或者麦克风)
navigator.mediaDevices.getUserMedia({ audio: false, video: true })
.then(function(mediaStream){
console.log(mediaStream);
video.src = window.URL.createObjectURL(mediaStream);
video.onloadedmetadata = function(e) {
video.play();
console.log(e);
};
})
.catch(function(error){
console.log(error);
});
```
_注意:调取本地视频或音频设备的接口,出于安全的考虑,只能在localhost或者https下使用!_
[demo 传送门](https://demo.dengtongyu.com/pages/20170522j7/)
@@ -0,0 +1,24 @@
---
title: react native for ios 下的一个小坑
tags: []
id: '84'
categories:
- - 分享
date: 2016-12-09 18:07:07
---
最近在尝试学习一下react native,然后就按照官网的教程一步步配置环境,一切都很顺利,但是在xcode下run的时候就报错了。
```js
Error: *** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
reason: 'bundleURL must be non-nil when not implementing loadSourceForBridge'
```
谷歌百度一系列之后,仍然无法解决,然后加了react native中文的官方群提问,有人说是开启了VPN导致,然而我的Mac并没有配置VPN,一切又回到原点。 然而受到这个启发,把之前写web dom时配置的 127.0.0.1 localhost 还原。神奇的事情发生了,Xcode里的项目跑起来了!喜大普奔,然而我也没搞懂这是为什么。
```js
#host文件一定要有这个
127.0.0.1 localhost
```
@@ -0,0 +1,54 @@
---
title: vue CLI 代理设置以及打包引入配置
tags: []
id: '173'
categories:
- - 分享
date: 2017-10-17 15:25:49
---
## 代理设置
在用 [vue CLI](https://www.npmjs.com/package/vue-cli) 做开发的时候,很多时候我们需要用到代理请求获取数据,[vue CLI](https://www.npmjs.com/package/vue-cli) 也很方便的为我们提供配置代理的API,打开[vue CLI](https://www.npmjs.com/package/vue-cli)项目的 _/config/index.js_ 文件,找到dev里的proxyTable
```
module.exports = {
//代理设置
dev: {
env: require('./dev.env'),
port: 8080,
autoOpenBrowser: true,
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {
'/data': {
target: 'http://dengtongyu.com', //代理目标地址
secure: false,
changeOrigin: true
}
},
cssSourceMap: false
}
}
```
## 打包引入配置
我们用[vue CLI](https://www.npmjs.com/package/vue-cli)打包项目的时候默认引入的资源是"/"根目录,如果我们的项目在非根目录下就要重新配置一下了,同样的,打开[vue CLI](https://www.npmjs.com/package/vue-cli)项目的 _/config/index.js_ 文件,找到build里的assetsPublicPath
```
module.exports = {
build: {
env: require('./prod.env'),
index: path.resolve(__dirname, '../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: '/pages/myproject/', //配置引入资源的根目录
productionSourceMap: true,
productionGzip: false,
productionGzipExtensions: ['js', 'css'],
bundleAnalyzerReport: process.env.npm_config_report
}
```
@@ -0,0 +1,42 @@
---
title: vue-resource http请求在ios浏览器下的一个小坑
tags: []
id: '69'
categories:
- - 分享
date: 2016-07-05 18:41:00
---
```js
new Vue({
el: 'body',
ready:function(){
this.$http.get('url',{
}).then(function(json){
console.log( typeof json.data ) //谷歌返回的是string,ios返回的是object
},function(json){
});
}
});
```
以上代码,在谷歌返回的是string,ios浏览器返回的是object, 所以通过JSON.parse()格式化json.data的时候,在ios浏览器下就报错了 通过使用vue-resource提供的json()方法解决 具体代码如下
```js
new Vue({
el: 'body',
ready:function(){
this.$http.get('url',{
}).then(function(json){
console.log( typeof json.json())
},function(json){
});
}
});
```
@@ -0,0 +1,10 @@
---
title: 一个星期一早晨感慨
tags: []
id: '22'
categories:
- - 生活
date: 2016-05-30 09:59:06
---
你看那天,看那墙,看那秋海棠,今天还是星期一。 ——加西亚马尔克斯《百年孤独》 为什么星期五离星期一这么近,星期一离星期五却这么远!这不科学!
+10
View File
@@ -0,0 +1,10 @@
---
title: 人应该要学会生活
tags: []
id: '20'
categories:
- - 生活
date: 2016-05-26 23:27:30
---
卖力,不卖命,卖艺,不卖身。 熬通宵这种玩意儿,最最摧残身体健康,有碍养生,过了青春期,万万不可行。 在这狗一般的生涯里,唯一的指望,就是太阳落山。 噫,又是一天,快快乐乐,躺下约会周公,几乎有种释放解脱涅槃的感觉。 ——亦舒《此一时也彼一时也》
@@ -0,0 +1,100 @@
---
title: 你也可以成为鉴黄师,nsfwjs鉴黄库初探
tags: []
id: '361'
categories:
+ - 分享
date: 2020-06-20 12:11:46
---
近日,我偶然在Github发现了一个鉴定不雅内容的 js 库 NSFW JS,出于好奇,于是就研究了一下,并且写了一个demo。下面就跟大家分享一下。
首先,NSFW JS 给一张图片鉴定的结果可能会得到如下 5 个分类结果。
1. 绘画(Drawing)——无害的艺术,或艺术绘画;
2. 变态(Hentai)——色情艺术,不适合大多数工作环境;
3. 中立(Neutral)——一般,无害的内容;
4. 色情(Porn)——不雅的内容和行为,通常涉及生殖器;
5. 性感(Sexy)——不合时宜的挑衅内容。
最终结果输出一个数组,每个分类都会输出一个概率,按概率从高到低排,所有分类的概率总和是1
```
[
{
"className": "Sexy",
"probability": 0.35769057273864746
},
{
"className": "Neutral",
"probability": 0.3514401912689209
},
{
"className": "Porn",
"probability": 0.2888406813144684
},
{
"className": "Hentai",
"probability": 0.0012577027082443237
},
{
"className": "Drawing",
"probability": 0.0007708172197453678
}
]
```
### 安装
NSFW JS是由TensorFlow.js作为对等依赖项提供支持。 所以我们要先安装TensorFlow.js。
```
yarn add @tensorflow/tfjs
yarn add nsfwjs
// or
npm i @tensorflow/tfjs
npm i nsfwjs
```
### 加载模型
然后我们需要加载模型。这个“模型”是用来评估图像的函数。可以在[nsfw\_model](https://github.com/gantman/nsfw_model)下载它们。这些文件是 4MB 大小的分片,便于在客户端进行缓存。因为我在vue项目中使用,所以把它们放在 /public/model/ 文件夹中。
![QQ截图20200620114436](https://image.dengtongyu.com/blog/2020/06/QQ截图20200620114436.png)
### 使用
```
// 导入模块
import * as nsfwjs from "nsfwjs";
// 图片dom节点
const img = document.getElementById('img')
// 载入模型
nsfwjs.load().then(model => {
// 鉴定图片
model.classify(img).then(predictions => {
console.log("Predictions: ", predictions);
});
});
```
在demo中测试的结果很惊喜,特意选取了一些干扰性的图片,也能正确识别
![微信图片_20200620120800](https://image.dengtongyu.com/blog/2020/06/微信图片_20200620120800.png)
![微信图片_20200620120806](https://image.dengtongyu.com/blog/2020/06/微信图片_20200620120806.png)
![微信图片_20200620120811](https://image.dengtongyu.com/blog/2020/06/微信图片_20200620120811.png) 最后,这里附上我写的demo,[传送门](https://demo.dengtongyu.com/pages/nsfwtool/)
@@ -0,0 +1,102 @@
---
title: 使用acme.sh 申请 Let's Encrypt 泛域名SSL证书
tags: []
id: '333'
categories:
- - 分享
date: 2018-07-23 18:25:45
---
之前用ertbot方式获取Let's Encrypt泛域名证书,必须手动在添加DNS TXT 记录,也不能自动续签,使用起来颇为不便。
今天发现了github上的一个开源工具[acme.sh](https://github.com/Neilpang/acme.sh),是一个开源的Let’s Encrypt SSL申请工具,操作和流程比官方的申请方式简化很多,使用起来非常方便,推荐大家使用。欢迎大家给该工具打星。
### 安装acme.sh
```
curl https://get.acme.sh sh
```
执行完代码后,acme.sh会被自动安装到~/.acme.sh/中
### 设置DNS API
目前泛域名证书仅支持DNS验证,acme.sh通过DNS提供商的API自动完成操作,因此需要先设置DNS API,以阿里云为例。
先前往阿里云后台获取App\_Key跟App\_Secret,在【用户信息管理】-【安全信息管理】创建SecretKey [传送门](https://ak-console.aliyun.com/#/accesskey),然后执行以下脚本
```
# 替换成从阿里云后台获取的密钥
export Ali_Key="LTA*********uV6"
export Ali_Secret="QKmsZgo*************8Htr6"
```
这个临时环境变量只需配置这一次,当成功申请证书后,API 信息会被自动保存在~/.acme.sh/account.conf,下次你使用acme.sh的时候会被自动使用
### 获取证书
```
# 换成自己的域名
acme.sh --issue --dns dns_ali -d dengtongyu.com -d *.dengtongyu.com
```
如果acme.sh,提示命令没找到,那就请再执行以下指令:
```
source ~/.bashrc
acme.sh --issue --dns dns_ali -d dengtongyu.com -d *.dengtongyu.com
```
或者先cd到acme.sh目录下,再执行文件
```
cd ~/.acme.sh
./acme.sh --issue --dns dns_ali -d dengtongyu.com -d *.dengtongyu.com
```
\--dns dns\_ali参数表示使用 阿里云 的 API,如果是其他解析商,请[点这里](https://github.com/Neilpang/acme.sh/blob/master/dnsapi/README.md)查看对应的参数
执行完代码后,会有120秒等待DNS生效,所以至少需要等待两分钟,等倒数结束后看到Cert success就是成功了
![使用acme.sh 申请 Let's Encrypt 泛域名SSL证书 ](https://image.dengtongyu.com/blog/2018/07/tdcdjdcxsov.png)
### 拷贝证书
前面证书生成以后, 接下来需要把证书 copy 到真正需要用它的地方.
注意, 默认生成的证书都放在安装目录下: ~/.acme.sh/, 请不要直接使用此目录下的文件, 例如: 不要直接让 nginx/apache 的配置文件使用这下面的文件. 这里面的文件都是内部使用, 而且目录结构可能会变化.
正确的使用方法是使用 --installcert 命令,并指定目标位置, 然后证书文件会被copy到相应的位置:
```
acme.sh --installcert -d dengtongyu.com \
--key-file /etc/nginx/ssl/dengtongyu.key \
--fullchain-file /etc/nginx/ssl/fullchain.cer \
--reloadcmd "service nginx force-reload"
```
(一个小提醒, 这里用的是 service nginx force-reload, 不是 service nginx reload, 据测试, reload 并不会重新加载证书, 所以用的 force-reload)
### 在 Nginx 中 配置 Let’s Encrypt 证书
Nginx 配置文件片断:
```
server {
server_name xxx.com;
listen 443 http2 ssl;
ssl on;
ssl_certificate /etc/nginx/ssl/fullchain.cer;
ssl_certificate_key /etc/nginx/ssl/dengtongyu.key;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
```
### 证书续期
Let's Encrypt 证书的有效期为三个月,acme.sh会每隔60天自动帮你续期,你无需任何操作
最后,更详细等内容请看[官方说明](https://github.com/Neilpang/acme.sh/wiki/%E8%AF%B4%E6%98%8E)
+10
View File
@@ -0,0 +1,10 @@
---
title: 吾日三省吾身
tags: []
id: '61'
categories:
- - 生活
date: 2016-06-23 23:13:16
---
当你的才华还撑不起你的野心时,那你就应该静下心来学习。 当你的能力还驾驭不了你的目标时,那你就应该沉下心来历练。 我绝对算不上好人,也决非坏到无药可救, 我把在这个时期自我调整的过程,称为人生, 我把自我调整过程中的感受,称为命运。
+10
View File
@@ -0,0 +1,10 @@
---
title: 咸鱼需要冷藏
tags: []
id: '29'
categories:
- - 生活
date: 2016-06-02 21:22:10
---
6月,广州! 白天大地在蒸腾,只需在太阳底下10秒,就能感受到阳光满满的恶意。 夜晚空气弥漫着热浪,连呼吸都能灼伤你五脏六腑。 这种闷热的环境,让我忘了自己几乎就是条咸鱼。 咸鱼就应该待在咸鱼该待的地方,于是我开了空调……
+10
View File
@@ -0,0 +1,10 @@
---
title: 奇妙能力歌
tags: []
id: '8'
categories:
- - 生活
date: 2016-05-24 22:59:20
---
\[audio mp3="https://image.dengtongyu.com/blog/2016/05/奇妙能力歌.mp3"\]\[/audio\] 我想要更好更圆的月亮 想要未知的疯狂 想要声色的张扬 我想要你
+10
View File
@@ -0,0 +1,10 @@
---
title: 如果有来生
tags: []
id: '24'
categories:
- - 生活
date: 2016-06-01 09:31:05
---
![小新](https://image.dengtongyu.com/blog/2016/05/u23298692062573679482fm21gp0.jpg) 如果有来生,我要当条被子,不是躺在床上就是在晒太阳! ——野原新之助
@@ -0,0 +1,24 @@
---
title: 字符html创建DOM节点
tags: []
id: '76'
categories:
- - 分享
date: 2016-08-25 09:58:05
---
jQuery的创建节点的方式非常方便,$('<div></div>') 只要这样就可以创建一个div的节点。 我们也可以通过JavaScript简单实现一下这种方式。
```js
function createDom(html) {
var tempDom = document.createElement('div');
tempDom.innerHTML = html;
return tempDom.childNodes;
};
var div = createDom('<div>新创建的div</div>')[0];
document.getElementsByTagName('body').appendChild(div);
```
不过值得注意的是,childNodes返回的是一个DOM节点的列表,记得处理一下
+10
View File
@@ -0,0 +1,10 @@
---
title: 小悟
tags: []
id: '110'
categories:
- - 生活
date: 2017-08-01 09:12:01
---
人生除了生和死,其他都是小事。 世界上没有无缘无故的爱,也没有无缘无故的恨, 一切的偶然其实都是必然, 一切的必然看起来可以躲过,其实都避免不了, 把握好当下的每一次偶然, 你才有机会改变未来的每一次必然,珍惜眼前!
@@ -0,0 +1,10 @@
---
title: 忙碌的工作日,潮流的朋友圈
tags: []
id: '14'
categories:
- - 生活
date: 2016-05-25 23:17:50
---
最近很忙,穷忙、瞎忙··· 朋友圈一如既往的热闹,今天是2016年5月25日,杨绛女士逝世。 朋友圈迎来了一场悼念杨绛女士的潮流。我相信那些人跟我一样不曾读过她的作品或者了解过她事迹,但不妨碍那些人加入这场悼念的盛会,纷纷在朋友圈表达了自己的悲痛和惋惜之情。 托朋友圈的福,我在今天终于认识了杨绛女士。惭愧,对于贡献如此之多的人,我现在才知道她。所以我辈有什么资格评价杨绛女士,多读点杨女士书吧。 至于朋友圈的蜡烛还是你们点吧,我继续生活的苟且···
+10
View File
@@ -0,0 +1,10 @@
---
title: 我脑中的橡皮擦
tags: []
id: '34'
categories:
- - 生活
date: 2016-06-12 21:52:59
---
![无脸男](https://image.dengtongyu.com/blog/2016/06/20150121124317_k2JGJ.jpg) 最近感觉自己容易忘记一些东西,重要的、琐碎的、又或者无关紧要的。 它犹如一块橡皮擦,偷偷的抹掉你一个字,一个词,甚至一句话,而你却浑然不觉。 待你回顾这些篇章的时候,你才发现记忆的空白。 于是你努力回想,企图找回只字片语,但看到的只是一片模糊的掠影。
@@ -0,0 +1,69 @@
---
title: 条件注释判断浏览器
tags: []
id: '38'
categories:
- - 分享
date: 2016-06-14 10:03:23
---
项目
范例
说明
!
\[if !IE\]
_The NOT operator. This is placed immediately in front of the?feature,?operator, or?subexpression?to reverse the Boolean meaning of the expression._ **NOT运算符。这是摆立即在前面的_功能_,_操作员_,或_子表达式_扭转布尔表达式的意义。**
lt
\[if lt IE 5.5\]
_The less-than operator. Returns true if the first argument is less than the second argument._ **小于运算符。如果第一个参数小于第二个参数,则返回true。**
lte
\[if lte IE 6\]
_The less-than or equal operator. Returns true if the first argument is less than or equal to the second argument._ **小于或等于运算。如果第一个参数是小于或等于第二个参数,则返回true。**
gt
\[if gt IE 5\]
_The greater-than operator. Returns true if the first argument is greater than the second argument._ **大于运算符。如果第一个参数大于第二个参数,则返回true。**
gte
\[if gte IE 7\]
_The greater-than or equal operator. Returns true if the first argument is greater than or equal to the second argument._ **大于或等于运算。如果第一个参数是大于或等于第二个参数,则返回true。**
( )
\[if !(IE 7)\]
_Subexpression operators. Used in conjunction with boolean operators to create more complex expressions._ **子表达式运营商。在与布尔运算符用于创建更复杂的表达式。**
&
\[if (gt IE 5)&(lt IE 7)\]
_The AND operator. Returns true if all subexpressions evaluate to true_ **AND运算符。如果所有的子表达式计算结果为true,返回true**
\[if (IE 6)(IE 7)\]
_The OR operator. Returns true if any of the subexpressions evaluates to true._ **OR运算符。返回true,如果子表达式计算结果为true。**
  举个栗子
```
<!-- [if IE 7]> 仅IE7可识别 <![endif]-->
<!--[if lte IE 7]> IE7以及IE7以下版本可识别 <![endif]-->
<!--[if gte IE 7]> IE7以及IE7以上版本可识别 <![endif]-->
```
@@ -0,0 +1,242 @@
---
title: 浅尝 HTML 5 input 新属性
tags: []
id: '276'
categories:
- - 分享
date: 2018-02-07 18:16:11
---
在HTML 5中,input增加了许多新的特性,本篇文章整理了一些新增的,并且谷歌浏览器也已经支持的属性。 这些新增的属性,很大程度的丰富了表单控件,很多原来需要js去验证的表单,现在只要一个属性就可以了,大大提高了生产效率。 #color::-webkit-input-placeholder { /\* WebKit, Blink, Edge \*/ color:#f00; } #color::-moz-placeholder { /\* Mozilla Firefox 19+ \*/ color:#f00; } #color:-ms-input-placeholder { /\* Internet Explorer 10-11 \*/ color:#f00; } dl input { border: 1px solid #ccc; }
## required 属性
required属性规定必需在提交表单之前填写输入字段。
```
<!-- 此输入框为必填-->
<input type="text" required>
```
## list 属性
属性引用 datalist 元素,其中包含 input 元素的预定义选项。
```
<input list="city">
<datalist id="city">
<option value="北京">
<option value="上海">
<option value="广州">
<option value="深圳">
<option value="杭州">
</datalist>
```
## maxlength 属性
属性规定 input 元素中允许的最大字符数。
```
<!-- 只允许输入3个字符 -->
<input type="text" name="usrname" maxlength="3">
```
## max min 属性
属性规定 input 元素的最大和最小值。
```
<!-- 最大值为10 -->
<input type="number" max="10" required>
<!-- 最小值为10 -->
<input type="number" min="10" required>
<!-- 1到10之间的数字 -->
<input type="number" min="1" max="10" required>
```
## multiple 属性
可接受多个值的文件上传字段
```
<!-- 按住Ctrl,可选择上传多个文件 -->
<input type="file" multiple required>
```
## pattern 属性
pattern 属性规定用于验证 input 元素的值的正则表达式。
```
<!-- 用pattern属性限制只能输入字母 -->
<input type="text" pattern="^[a-zA-Z]+$" title="只能输入字母" required>
```
## step 属性
step 属性规定 input 元素的合法数字间隔。
```
<!-- 只能输入能被5整除的数字 -->
<input type="number" step="5" required>
```
## src alt 属性规定
input按钮用图片展示
```
<!-- src的值可以是图片链接或者base64 -->
<input type="image" src="data:image/png;base64">
```
## placeholder 属性
placeholder 属性规定可描述输入 input 字段预期值的简短的提示信息 。
```
<!-- 带有 placeholder 文本的输入字段 -->
<input type="text" placeholder="请输入你的文本">
<!-- placeholder 文本也可以指定颜色 -->
<style type="text/css">
#color::-webkit-input-placeholder { /* WebKit, Blink, Edge */
color:#f00;
}
#color::-moz-placeholder { /* Mozilla Firefox 19+ */
color:#f00;
}
#color:-ms-input-placeholder { /* Internet Explorer 10-11 */
color:#f00;
}
</style>
<input id="color" type="text" placeholder="请输入你的文本">
```
## type 属性
在HTML5中,type有了更多丰富的控件类型让我们使用
### color 拾色器
```
<!-- 拾色器 -->
<input type="color">
```
### date 日期控件
```
<!-- 日期控件 -->
<input type="date">
```
### month 年月控件
```
<!-- 定义 month 和 year 控件(不带时区) -->
<input type="month">
```
### time 时间控件
```
<!-- 定义用于输入时间的控件(不带时区) -->
<input type="time">
```
### week 周控件
```
<!-- 定义 week 和 year 控件(不带时区) -->
<input type="week">
```
### datetime-local 带时间的日期控件
```
<!-- date 和 time 控件(不带时区) -->
<input type="datetime-local">
```
### email 定义用于 e-mail 地址的字段(当提交表单时会自动对 email 字段的值进行验证)
```
<!-- 输入的必须是邮箱格式 -->
<input type="email" required>
```
### number 数字
```
<!-- 输入的必须是数字 -->
<input type="number">
```
### password 密码
```
<!-- 输入密码控件 -->
<input type="password">
```
### range 范围取值
```
<!-- 选择1到10的范围 -->
<input type="range" min="1" max="10">
```
### tel 电话
```
<!-- 输入的值必须是电话号码 -->
<input type="tel">
```
### url 链接
```
<!-- 输入的值必须是链接 -->
<input type="url" required>
```
# [页面demo](https://demo.dengtongyu.com/pages/input/)
@@ -0,0 +1,122 @@
---
title: 演唱会随机选座解题思路
tags: []
id: '346'
categories:
- - 分享
date: 2018-12-16 14:07:46
---
最近遇到一个演唱会随机选座的问题,这个问题细想起来确实有趣,正好周末有空,所以我想花点时间分享一下我的解题思路。
演唱会会场分A、B、C、D四个区域,每个区域第一排50个座位,向后每排递增2个座位,最后一排100个座位。一个人可以买1~5张票,系统要随机分配座位,但必须连号,问要怎么分配?
![情景图](https://image.dengtongyu.com/blog/2018/12/情景图.jpg)
因为买票的张数不确定性,如果直接随机分配,则有可能出现很多单个位置空出的情况,降低了座位的有效利用率。如果直接顺序出票,那就出现人群扎堆的情况。所以我们要在均衡分布与高利用率之间取一个平衡点。
首先定义座位信息
```
let item = {
index: 0, //下标(索引)
group: 0, //分组
groupName: 'A', //分组名称
number: 3, //座位编号
row: 9, //第几排
disable:false //该座位是否可选
};
```
把座位和排数用数组保存起来
```
let front = 2; //前排座位数
let back = 10; //后排座位数
let .gap = 2; //每行座位数差
let group = 4; //分组数
let lines = (this.back - this.front) / this.gap; //每个分组有多少排
let index = 0; //下标(索引)
for (let g = 0; g < this.group; g++) {
for (let line = this.lines; line >= 0; line--) {
let rowArray = [];
for (let seat = 0; seat < (this.back - this.gap * (this.lines - line)); seat++) {
let item = {
index:index++,
group: g,
groupName: this.groupName(g), //分组名称
number: seat,
row: line,
disable:false
};
rowArray.push(item);
seats.push(item);
//console.log(item)
}
rows.push(rowArray);
};
}
```
把符合条件的座位排数筛选出来(即有足够连号的空位的排数)
```
suitableRows(length) {//length为买票的张数
let haveSeatRows = [];
this.rows.forEach((list) => {
//可选的座位数组
let haveSeatList = list.filter((item) => {
return !item.disable;
});
if(haveSeatList.length <= 0) return false;
//有N张连号的排数
if(this.selectPlace(haveSeatList,length).length > 0) {
haveSeatRows.push(haveSeatList);
}
});
if(haveSeatRows.length > 0) {
return haveSeatRows;
}else{
return false;
}
}
```
最后把从筛选出来的排数中选出座位
```
let index = Math.floor(Math.random() * haveSeats.length);
let places = this.selectPlace(haveSeats[index], length);
selectPlace(list, length) {
let places = [];
for(let i = 0;i < list.length - 1;i++) {
let end = i + length;
if(end > list.length) break;
let selects = list.slice(i, end);
let flag = false;
selects.forEach((val, k) => {
if(k + 1 <= selects.length - 1) {
if(val.number + 1 == selects[k + 1].number) {
flag = true;
}else{
flag = false;
}
}
});
if(flag) {
places = selects;
break;
}
}
return places;
}
```
总结起来,基本思路就是把符合条件的行数收集起来,再从所有行数中随机选出一行,顺序出票,从而在均衡分布与高利用率之间取一个平衡点。
[demon实例,点击查看!](https://demo.dengtongyu.com/pages/20181112o4/)
@@ -0,0 +1,69 @@
---
title: 用Node+express搭建本地https服务
tags: []
id: '90'
categories:
- - 分享
date: 2017-01-24 15:21:05
---
1.安装node环境(自行谷歌百度,不赘述) 2.安装express(自行谷歌百度,不赘述) 3.打开命令行,利用openssl生成证书文件
```js
//生成私钥key文件
openssl genrsa 1024 > /keys/private.pem
//通过私钥文件生成CSR证书签名
openssl req -new -key /keys/private.pem -out /keys/csr.pem
//通过私钥文件和CSR证书签名生成证书文件
openssl x509 -req -days 365 -in /keys/csr.pem -signkey /keys/private.pem -out /keys/file.crt
```
4.编写server文件
```js
var app = require('express')();
var fs = require('fs');
var http = require('http');
var https = require('https');
//引入私钥、证书
var privateKey = fs.readFileSync('./keys/private.pem', 'utf8');
var certificate = fs.readFileSync('./keys/file.crt', 'utf8');
var credentials = {key: privateKey, cert: certificate};
//创建服务,设置端口号
var httpServer = http.createServer(app);
var httpsServer = https.createServer(credentials, app);
var PORT = 18080;
var SSLPORT = 18081;
//监听端口号
httpServer.listen(PORT, function() {
console.log('HTTP Server is running on: http://localhost:%s', PORT);
});
httpsServer.listen(SSLPORT, function() {
console.log('HTTPS Server is running on: https://localhost:%s', SSLPORT);
});
//路由
app.get('/', function(req, res) {
if(req.protocol === 'https') {
res.status(200).send('这是一个经过加密的https请求!');
}
else {
res.status(200).send('这是一个普通的http请求!');
}
});
```
5.启动服务
```js
node server.js
```
@@ -0,0 +1,10 @@
---
title: 第一条写些什么呢?
tags: []
id: '4'
categories:
- - 生活
date: 2016-05-24 18:30:10
---
![无脸男](https://image.dengtongyu.com/blog/2016/05/015986554b84ec000001bf7267e627.jpg) 以后的生活会更精彩吧···嗯嗯···
+9
View File
@@ -0,0 +1,9 @@
---
title: 首页
tags: []
id: '18'
categories:
- - uncategorized
comments: false
date: 2016-05-26 16:57:35
---