上面准备工作中,只有开通chatgpt的api算是最高难度的了,国内visa信用卡还不支持,就算是国外也不是所有的信用卡都支持,因此网上有一些虚拟信用卡的开通服务,但是也要慎用。我是找了美国的朋友,用他的信用卡开通。
1 | data: |
有些字段会有换行符和特殊字符,这些字符如何直接格式化后拼接会报错,这种在返回代码中最为明显,所以在返回到了前端处理的时候,要处理一下,我是这么做的,如果可以直接JSON.parse的话,那么就正常取值,如果JSON.parse报错的话,手动截取引号中间的内容返回。
1 | const newReg = (str: string) => { |
打字机效果是文字一个一个出现的效果,这个效果在本地显示的好好的,但是服务器怎么都不显示,在google和github查了很多资料后,终于找到了是因为服务器的nginx的配置导致的,需要更改nginx.config配置。
1 | proxy_cache off; # 关闭缓存 |
markdown这个确实是需要自己去处理返回的代码的语言类型,语言内容,我用的是MarkdownIt这个插件,具体实现如下
1 | mdi.renderer.rules.code_inline = function (tokens, idx, options, env, slf) { |
基本上 bpmn 原有的元素从 UI 到功能上面都会有所更改,从左侧元素工具栏到中间的元素,连接线,元素的面板,基本上都要重新覆盖。
最终效果如下:
最开始想到的解决办法是手动处理每个sharp的样式,手动把 x,y,font-size,fill 给填上,这么做虽然可行,但是每个sharp的坐标,位置,大小,文字长度都得计算,觉得这并不是一个好方案,然后翻阅了 bpmn.js 的源码,看了他的实现,觉得可以在自定义这块重新在调用就可以了,实现如下代码:
1 | import TextUtil from 'diagram-js/lib/util/Text.js'; |
监听bpmnModeler变化时,执行如下代码即可1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25setArrowColor() {
const marker = svgCreate('marker')
svgAttr(marker, {
id: 'sequenceflow-arrow-normal',
viewBox: '0 0 20 20',
refX: '11',
refY: '10',
markerWidth: '10',
markerHeight: '10',
orient: 'auto'
})
const path = svgCreate('path')
svgAttr(path, {
d: 'M 1 5 L 11 10 L 1 15 Z',
style:
' stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1; '
})
const defs = domQuery('defs')
svgAppend(marker, path)
svgAppend(defs, marker)
}
1 | #sequenceflow-arrow-normal { |
因为 bpmn.js 是通过svg实现图形功能的,所以简单的是绝大部分的元素的隐藏都可以通过 css 来处理,只有少部分需要自行操作svg的属性。
可以使用内置的tiny-svg这个库来解决,结合min-dom和min-dash其实能解决好多关于svg的问题,都是一些很简单也很好用的库,地址:
1 | a.xxx.com/ |
改成为1
2xxx.com/a/
xxx.com/b/
总结一下更改的过程及内容
1 | new Router({ |
1 | export const globalHistory = createBrowserHistory({ |
1 | output: { |
1 | "homepage": "/__PUBLIC_PATH_PLACEHOLDER__", |
1 | run.sh 文件 |
都说三十而立,过了而立之年就应该有所成就,承担责任,能够有明确的人事目标和方向;我来讲讲我的现状,用两个字概括的话,就是焦虑;
焦虑充斥在家庭,工作,生活之中,甚至一度导致我有点抑郁,因为看不到未来,看不到希望,有时候觉得天都是灰色的,有很多烦恼,压力无处去发泄,心态严重的失衡,也证明了我并不是一个内心强大的人,当闭上眼睛脑海里面浮现的都是孩子的教育,孩子的未来,我的工作,我的工资等等,都是一些自己无能为力但是又不停内耗的事。
没读过万卷书,也没行过万里路,一个普通人,去过的地方屈指可数,一直想真正的潇洒一下,来一场说走就走的旅行,希望能带着我儿子,去看看祖国的大好河山,让他感受一下生活以外的地方是什么样,也增加和孩子的相处时间。 这几年看的书也丰富了起来,不在局限于文学、技术类的,也会看看地理、哲学、经济一类的,希望自己能够保持阅读的习惯,丰富自己的灵魂。
觉得自己有很多可以改进的地方,比如:沟通,懒惰,耐心,逻辑思维的完善性;觉得自己随着年龄增长,也多了几分不可理喻和放纵,不想去思考,也懒得去思考,后来想想,觉得这是一种逃避现实的方法,百害而无一利;觉得自己虽然面对电脑的时间比面对人的时间还多,但是也不能忘了沟通的重要性,多看一些关于沟通相关的书籍和视频,更重要的是多实战吧。
正视自己,不要逃避,保持良好情绪,适当发泄情绪;不想就这么过完一生;共勉。
]]>前端性能优化是一门综合性很强的学科,它涉及到网络、浏览器、JavaScript、CSS、HTML、图片等多个方面。为了达到最佳效果,我们需要从多个角度出发,采用各种技巧和工具来分析、测试、监控和改进网页的性能。
本文旨在提供一份全面而实用的前端性能优化指南。(本段文字来自chatGPT生成)
以上来自雅虎优化指南,也叫雅虎军规。
Content Delivery Network(CDN)
cdn具有能提高网站的访问速度、节省带宽等优势,其工作原理是通过将源站的内容缓存到分布在不同地区和运营商的边缘节点上,当用户请求时,就近返回节点上缓存的内容。cdn还涉及DNS解析、负载均衡、内容分发、调度等技术模块。
浏览器缓存
缓存的设置可以大大提高响应速度,减少http请求,节省带宽等优势,缓存包括强缓存、协商缓存等,可以添加Expires头,配置ETag等属性来选择缓存的方式。当浏览器请求一个资源时,它会检测本地缓存中是否有该资源,并且是否在有效期内,如果是,则直接从本地缓存中返回该资源。
强缓存是利用HTTP请求头中的Expires和Cache-Control 两个字段来进行控制,用来表示资源的缓存时间,Expires是一个绝对时间,Cache-Control 是一个相对时间,表示资源在多长时间内有效;一般会对js、css、图片等资源使用强缓存。
协商缓存是利用 HTTP 请求头中的 Last-Modified/If-Modified-Since 和 ETag/If-None-Match 两对字段来进行控制,用来表示资源的更新时间和唯一标识。
当浏览器再次请求一个资源时,如果本地缓存已经过期,它会携带这些字段向服务器发送请求,询问资源是否有更新。如果没有更新,则服务器会返回 304 状态码,告诉浏览器可以继续使用本地缓存。如果有更新,则服务器会返回 200 状态码和新的资源,并更新本地缓存。
AppCache
在html页面中指定manifest文件的路径,例如<html manifest="example.appcache">
在manifest文件中列出需要缓存的资源,以及在离线时显示的页面,例如:
1 | CACHE MANIFEST |
在服务器端配置正确的MIME类型,例如text/cache-manifest
在浏览器中访问html页面,浏览器会自动下载并缓存manifest文件中指定的资源
在离线时,浏览器会从缓存中加载资源,并在无法访问的情况下显示fallback页面
Localstorge、Sessionstorage、Cookie、CacheStorage
用于本地存储,常用,不必过多解释。
减少请求数
减少文件大小,节省请求带宽
静态资源域名
域名的要求一般是独立短小,短小可以减少头部开销,域名越短请求头的URI就越短;独立是因为独立的域名不会共享主域的cookie,可以减少请求头大小,还有一个原因是浏览器对相同域名的并发连接数是有限制的,一般同域名为6-8个连接,当然域名不是越多越好,每个域名的第一次连接都要经理DNS查询,会耗费时间,尽量控制域名在2-4个间,需要注意的是,同一静态资源在不同页面散列到不同子域下,会导致无法利用http缓存。
http2(来源:baidu.com)
使用外链CSS和JS,CSS放头,JS放尾,防止阻塞以减少对并发下载的影响,尽早刷新文档的输出。
html的代码优化,如:
css的代码优化,如:
js的代码优化,如:
图片格式的选择:
合理分配资源加载时间,按需加载,包括CSS、JS文件以及图片、业务模块等。 根据我们网页最初加载需要的最小内容集推断其他内容延迟加载;无条件提前加载公共内容或根据用户行为推断提前加载某些内容,如根据搜索框输入的文字来判断加载的内容。加载机制如下:
减少DNS 查询:DNS 查询一般需要几毫秒到几百毫秒,移动环境下会更慢。我们可以预先读取DNS,减少用户等待时间。
更多代码规范相关,请参考: 前端代码规范
]]>1 | import { Form, Input } from 'antd'; |
这代码熟悉吧!是不是经常写?
这是 antd 的 Form 组件的用法:
通过 useForm 拿到 form 对象,设置到 Form 组件里,然后用 form.setFieldsValue 设置的字段值就能在 Form.Item 里取到。
Form.Item 只需要在 name 里填写字段所在的路径就行,也就是 [‘d’, ‘e’] 这个。
有的同学可能会问了,为啥这里只设置了个 name,它下面的 Input 就有值了呢?
我们让 Form.Item 渲染一个自定义的组件试一下,比如这样:
1 | const MyInput = (props) =>{ |
1 | return ( |
通过给自定义组件打断点,可以看到,组件内部传入了 id、value、onChange 等参数进来,
这就是为啥 Input 能有值,因为传入了 value 参数。
而且变化了也能同步到 fields,因为传入了 onChange 参数。
有的时候我们要对保存的值做一些修改,就可以这样写:
1 | function MyInput(props) { |
所以说,Form.Item 会给子组件传入 value、onChange 参数用来设置值和接受值的改变,同步到 form 的 fields。
以下是我个人经常使用的上传图片的组件:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63import React, { useEffect, useState } from 'react'
import { message, Upload } from "antd";
import { LoadingOutlined, PlusOutlined } from "@ant-design/icons";
const defaultUrl = ""
const imageURL = ""
const UploadImg = (props: any) => {
const {value, onChange} = props;
const [loading, setLoading] = useState(false);
const handleChange = (info: any) => {
if (info.file.status === "uploading") {
setLoading(true);
return;
}
if (info.file.status === "done") {
const url = info.file.response.data.url;
onChange && onChange(url);
setLoading(false);
}
};
const beforeUpload = (file: any) => {
const isJpgOrPng = file.type === "image/jpeg" || file.type === "image/png";
if (!isJpgOrPng) {
message.error("只支持 JPG/PNG 文件!");
}
const isLt2M = file.size / 1024 / 1024 < 5;
if (!isLt2M) {
message.error("图片必须小于5MB!")
}
return isJpgOrPng && isLt2M;
};
return (
<Upload
name="file"
// customRequest={customRequest}
listType="picture-card"
className="avatar-uploader"
showUploadList={false}
action={defaultUrl}
beforeUpload={beforeUpload}
onChange={handleChange}
>
{value ? (
<img src={imageURL + value} alt="avatar" style={{ width: "100%" }} />
) : (
<div>
{loading ? <LoadingOutlined /> : <PlusOutlined />}
<div style={{ marginTop: 8 }}>点击上传</div>
</div>
)}
</Upload>
)
}
export default UploadImg
上面的代码已经完成了80%的内容,下面让我们来继续完善游戏内容;
1 | game.physics.arcade.collide(player, platforms); |
Phaser.Physics.arcade.collide(object1, object2, collideCallback, processCallback, callbackContext)
参数分别为,对象1,对象2,碰撞回调函数,比如有的关卡,有陷阱一类的,人物要是碰撞后,在回调中kill人物,state跳到over上。
跟碰撞类似,只是api不同1
game.physics.arcade.overlap(player, platforms);
Phaser.Physics.arcade.overlap(object1, object2, collideCallback, processCallback, callbackContext)
多用在获得道具上,比如人物和星星重叠后,可以加分,然后消除星星。
1 | game.physics.arcade.overlap(player,stars,function (player,star) { |
1 | cursors = game.input.keyboard.createCursorKeys(); |
Phaser.Game.input.keyboard.createCursorKeys()
1 | if(cursors.left.isDown){ |
当按下键盘 <- 左键时,x轴加速为-150,然后执行animations的left动画,有一点是需要注意的是,在没有按下左右键的时候,让frame定格在第4帧,1
player.frame = 4;
以下为全部代码:
Phaser 小游戏About。
1 | var game = new Phaser.Game(288,505,Phaser.AUTO,'game',state); |
state 是一个场景,可以是一个对象,也可以是一个构造函数,只要存在proload、create、update中的一个,就是一个合法的state;
1 | //state可以是一个自定义对象 |
proload函数是最先执行的,用来加载资源、create是初始化场景的函数,等proload执行完成后执行,update是更新函数,游戏每一帧都要执行update;
1 | function state() { |
使用方法为:
game.load.’资源’(‘别名’,’路径’);
常用的资源有:image、audio、tilemap、text、spritesheet;
别名指后面用的名称;
其中spritesheet还需要添加每帧的宽高帧数等。
资源加载完成后,会自动进入create函数1
2
3this.create = function () {
game.add.sprite(0,0,'sky')
}
sprite对象,也叫精灵,可以用图片来创建精灵,然后用phaser提供的属性,来操作。1
game.add.sprite(0,0,'sky')
创建后,会自动添加对应的内容在主界面。
说一个比较重要的对象:Phaser.group(),也就是组,相当于一个统一一个父容器,把需要的子对象放进去,然后可以通过组的方法进行批量的操作,比如统一的位移和碰撞检测等。1
2
3
4
5platforms = game.add.group();
var ground = platforms.create(0,0,'platform');
var ledge = platforms.create(400,200,'platform');
Phaser已支持一些不同的物理系统,有Arcade Physics,,Ninja Physics 和 P2.JS Full-Body Physics。对与简单的物理方法,我们使用Arcade Physics即可。
物理引擎在Phaser中是默认关闭的,要启用可以在create中使用:1
game.physics.startSystem(Phaser.Physics.ARCADE);
要启用整组的物理属性,使用enableBody即可1
platforms.enableBody = true;
开启物理属性后,即可得到一个body属性,所有的物理属性方法都挂在body上面
常用的属性有:
immovable、bounce、gravity、drag、sprite、x、y、collideWorldBounds、input等,对应各种固定,弹性、重力,拖拽,边界等。
1 | ground.body.immovable = true; |
1 | player.animations.add('left', [0, 1, 2, 3], 10, true); |
TileSprite、Rope、Image、Button、Sprite等拥有animations属性,可以添加动画方法1
Phaser.Sprite.animations.add(name, frames, frameRate, loop, useNumericIndex)
分别为动画名称,帧数数组,每秒帧数,循环次数;
1 | game.add.text(10,10,'score:0',{ font: "35px Arial", fill: "#ff0044"}) |
//Phaser.Game.add.text(x, y, text, style, group);
如果你经常使用canvas的话,对这种应该不陌生,分别为:x、y、文字内容,样式组。
这样我们基本完成了create函数的内容:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48this.create=function () {
//开启物理引擎
game.physics.startSystem(Phaser.Physics.ARCADE);
//添加天空
game.add.sprite(0, 0, 'sky');
//添加地板组
platforms = game.add.group();
//开启地板组的物理属性
platforms.enableBody = true;
//添加底部地板
var grounds = platforms.create(0,game.world.height-32,'platform');
//设置缩放
grounds.scale.setTo(2,1);
//禁止移动
grounds.body.immovable = true;
var legs = platforms.create(-150,120,'platform');
legs.body.immovable = true;
legs = platforms.create(400,270,'platform');
legs.body.immovable = true;
//添加人物
player = game.add.sprite(32, 150, 'dude');
game.physics.arcade.enable(player);
player.body.bounce.y = 0.3;
player.body.gravity.y = 500;
player.body.collideWorldBounds = true;
player.animations.add('left', [0, 1, 2, 3], 10, true);
player.animations.add('right', [5, 6, 7, 8], 10, true);
cursors = game.input.keyboard.createCursorKeys();
//添加文字
fonts = game.add.text(10,10,'score:0',{ font: "35px Arial", fill: "#ff0044"})
//添加星星
stars = game.add.group();
stars.enableBody = true;
for(var i =0;i<12;i++){
var star = stars.create(i * 70 , 0, 'star');
star.body.bounce.y = 0.7;
star.body.gravity.y = 400;
star.body.collideWorldBounds = true;
}
}
1、在~/.ssh下,新建文件,比如login,或者test1等;
2、1
2
3
4
5
6
7
8
9
10
11
set user root
set host 192.168.1.109
set password test123###
set timeout -1
spawn ssh $user@$host
expect "*assword:*"
send "$password\r"
interact
expect eof
3、如果是其他的端口,在set一个port xxxx,xxxx对应你的端口;
4、打开iterm2的Profiles,点击+号,新增一个profile,name写自己连接主机的名称,然后在command上选择command,把:1
expect ~/.ssh/login
后面的login对应你建立的文件名称
5、使用的时候,直接在iterm2上面的Profiles选择你填写的用户名即可。
又是一年的开始,做个今年的计划吧!
1、写完自己的vueUI组件,传说中的Lui,哈哈
2、写go程序或者python,毕竟很久没写了
3、写一款自己的小游戏
4、精通typescript
5、看完10左右的技术书籍
具体使用方法为:canvas.toDataURL(type,encoderOptions)
第一个参数type为,支持的类型,默认为images/png,第二个参数是质量,默认为0.92
简单示例:1
2
3
4var fullQuality = canvas.toDataURL("image/jpeg", 1.0);
// data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ...9oADAMBAAIRAxEAPwD/AD/6AP/Z"
var mediumQuality = canvas.toDataURL("image/jpeg", 0.5);
var lowQuality = canvas.toDataURL("image/jpeg", 0.1);
完整代码:1
<img src="" alt="" id="img" crossorigin="anonymous">
1 | function drawImg(path, callback) { |
二、canvas.drewImage()
完整代码:1
<canvas id="myCanvas"></canvas>
1 | function render(src,size) { |
参考:
]]>我们通常看线上的js或者css都是这样的
通过在sources下的{},点击即可格式化代码很方便
其实chrome中也是可以储存我们自己的代码的,如果不想每次都粘贴在控制台中或者临时想写些什么,那么sources中的Sinppets将是你的一个很好的选择,
Sinppets中你可以新建很多个不同的代码段,跟文本一样,可以写一些文字或者代码,可以command+s保存,如果你写的是js代码一类的,可以直接右键你的Sinppets
文件名称,点击Run,即可执行你的代码,也可以右键文件Save as保存文件到本地。
ctrl+p 项目中定位文件,以下查找VueJS库文件:
ctrl+shif+o 文件中定位成员函数,以下定位到VueJS的nextTick接口:
暂且写这么多,network及短点什么的,估计大家都会用了,就不介绍了。
]]>Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.
1 | $ hexo new "My New Post" |
More info: Writing
1 | $ hexo server |
More info: Server
1 | $ hexo generate |
More info: Generating
1 | $ hexo deploy |
More info: Deployment
]]>