基于uniapp的日期区间选择组件开发
公司钉钉小程序有需求要让用户选择一个日期区间
在市场上没有找到相对比较匹配日期区间选择组件,于是考虑自己封装
公司的钉钉小程序用的是uniapp开发的,所以理所当然的基于uniapp开始了组件封装.
大概花了1天多时间简单做了一下封装,对钉钉和微信两个小程序端做了适配.
之前还没有针对picker-view做过封装,基本上用的都是现成的组件.这次封装算是对picker-view做下大概的了解.
不过因为是基于公司业务封装,功能也略偏向业务.
公司钉钉小程序有需求要让用户选择一个日期区间
在市场上没有找到相对比较匹配日期区间选择组件,于是考虑自己封装
公司的钉钉小程序用的是uniapp开发的,所以理所当然的基于uniapp开始了组件封装.
大概花了1天多时间简单做了一下封装,对钉钉和微信两个小程序端做了适配.
之前还没有针对picker-view做过封装,基本上用的都是现成的组件.这次封装算是对picker-view做下大概的了解.
不过因为是基于公司业务封装,功能也略偏向业务.
egg.js默认集成了XSS框架,附上框架链接:
https://jsxss.com/zh/index.html
使用方法是 const safehtml = this.ctx.helper.shtml(html)
返回的html就是过滤后的html内容,可以安全保存在数据库中了.
里面有各种对不同的tag,不同属性的配置,这里就不举例了,大部分情况下默认配置就行,个别情况要改的话,根据默认配置增减就行.这里附上源码中的默认配置,以便查阅
https://github.com/leizongmin/js-xss/blob/master/lib/default.js
if (isWhiteAttr && (name === 'href' || name === 'src')) {
if (!value) {
return;
}
value = String(value);
if (value[0] === '/' || value[0] === '#') {
return;
}
const hostname = utils.getFromUrl(value, 'hostname');
if (!hostname) {
return;
}
// If we don't have our hostname in the app.security.domainWhiteList,
// Just check for `shtmlConfig.domainWhiteList` and `ctx.whiteList`.
if (!isSafeDomain(hostname, domainWhiteList)) {
// Check for `shtmlConfig.domainWhiteList` first (duplicated now)
if (shtmlConfig.domainWhiteList && shtmlConfig.domainWhiteList.length !== 0) {
app.deprecate('[egg-security] `config.helper.shtml.domainWhiteList` has been deprecate. Please use `config.security.domainWhiteList` instead.');
shtmlConfig.domainWhiteList = shtmlConfig.domainWhiteList.map(domain => domain.toLowerCase());
if (!isSafeDomain(hostname, shtmlConfig.domainWhiteList)) {
return '';
}
} else {
return '';
}
}
}
源码可以看到 if(value[0] === '/' || value[0] === '#'){ return }
...
const shtmlConfig = utils.merge(this.app.config.helper.shtml, securityOptions.shtml);
...
// avoid overriding user configuration 'onTagAttr'
if (shtmlConfig.onTagAttr) {
const original = shtmlConfig.onTagAttr;
shtmlConfig.onTagAttr = function() {
const result = original.apply(this, arguments);
if (result !== undefined) {
return result;
}
return shtmlConfig[BUILD_IN_ON_TAG_ATTR].apply(this, arguments);
};
} else {
shtmlConfig.onTagAttr = shtmlConfig[BUILD_IN_ON_TAG_ATTR];
}
const config = {
// ...
helper: {
shtml: {
onTagAttr(tag, name, value, isWhiteAttr) {
if (isWhiteAttr && (name === 'href' || name === 'src')) {
if (!value) {
return
}
value = String(value)
// 测试环境通过/做代理,不要过滤掉.
if (value[0] === '/') {
return `${name}="${value}"`
}
}
},
},
},
// ...
}
有时候把自己写的代码复制到U盘中,想批量删除node_modules文件夹,可以使用rimraf的模糊匹配
rimraf ./**/node_modules/
我在开发大富翁游戏中,希望骰子能跟现实一样投掷,因为three.js中并没有物理引擎的引入,所以我需要引入cannon.js
cannon.js属于一个轻量级引擎,对cpu的性能要求比较低,非常适合放在web游戏中使用.
简单记录一下cannon.js使用过程中的要点,以便后面查阅.
this.world = new CANNON.World()
this.world.gravity.set(0, 0, -9.8 * 70) // 重力加速度设置 这里乘以70是因为之前创建的物体设置的比较大,所以需要加大重力加速度矫正
// 设置材质 这里设置了地面,墙壁,骰子三种材质
const cubeMaterial = new CANNON.Material('cube')
const material = new CANNON.Material('ground')
const wallMaterial = new CANNON.Material('wall')
// 地面
const bodyGround = new CANNON.Body({
mass: 0,
position: new CANNON.Vec3(0, 0, 0.1),
shape: new CANNON.Plane(),
material: material,
})
const wall1 = new CANNON.Body({
mass: 0,
position: new CANNON.Vec3(WIDTH / 2, 0, 0),
shape: new CANNON.Plane(),
material: wallMaterial,
})
wall1.quaternion.setFromAxisAngle(new CANNON.Vec3(0, 1, 0), -Math.PI / 2)
// 注意CANNON.Plane底部是包含材质的,并不是只有一个平面,假设 position: new CANNON.Vec3(0, 0, 0), 那么z方向<0的都是存在材质,物体如果在z方向<0 会被挤到上来,在z+方向有一个力
// 设置两个材质之间的参数值,因为我不希望骰子斜靠在墙上,所以墙壁和骰子的摩擦力设置成了0.
const groundContactMaterial = new CANNON.ContactMaterial(material, cubeMaterial, {
friction: 0.1, // 摩擦力
restitution: 0.5, // 弹性
})
const wallContactMaterial = new CANNON.ContactMaterial(wallMaterial, cubeMaterial, {
friction: 0,
restitution: 1,
})
addBox(cube: Cube, speed = 1) {
return new Promise<void>((resolve, reject) => {
const pos = cube.instance.position
const qua = cube.instance.quaternion
const size = cube.size
const halfExtents = new CANNON.Vec3(size / 2, size / 2, size / 2)
const bodyBox = new CANNON.Body({
mass: 5,
position: new CANNON.Vec3(pos.x, pos.y, pos.z),
shape: new CANNON.Box(halfExtents),
quaternion: new CANNON.Quaternion(qua.x, qua.y, qua.z, qua.w),
linearDamping: 0.01,
angularDamping: 0.05,
material: cubeMaterial,
})
const x = 500 * speed * randPM()
const y = 500 * speed * randPM()
const z = 300 + 300 * speed
bodyBox.velocity.set(x, y, z)
bodyBox.angularVelocity.set(rendAngular(), rendAngular(), (50 + 50 * Math.random()) * randPM())
function rendAngular() {
return (10 + 10 * Math.random()) * randPM()
}
const box: PhysicsBody = {
type: 'cube',
cube,
bodyBox,
resolve,
reject,
timer: new Date().getTime(),
}
this.world.addBody(bodyBox)
this.bodyList.push(box)
})
}
// updatePhysics
render(res: any) {
const delta = res.delta as number
if (delta) {
// console.log(delta)
this.world.step(fixedTimeStep, delta, maxSubSteps)
for (let i = this.bodyList.length - 1; i >= 0; i--) {
const box = this.bodyList[i]
// 将物理引擎中的计算值同步到threejs中的对象中(position,quaternion),并判断CANNON.Body的速度和角速度是否低于某个阈值,
// 如果低于阈值后,则可以认为骰子已经停止运动了,可以读取骰子的朝向及点数值了.
if (this.syncInstanceValue(box)) {
this.bodyList.splice(i, 1)
// 延迟去除,多个骰子
setTimeout(() => {
this.world.remove(box.bodyBox)
}, 5000)
box.resolve()
}
}
}
}
立了flag要在2021年开发一款3d休闲小游戏,勉强做了一个大富翁1.0,还有不少需要修改的地方,本来想修改完成后来发博客,下半年为了赚钱稍微忙了点...停了一段时间后就一直没继续了.
先发个github的地址链接,后面有时间,再发些文章记录一些开发web游戏的坑...
游戏规则参考
https://j9981168.pixnet.net/blog/post/239327645
后面有时间在游戏里补上帮助(逃ε=ε=ε=┏(゜ロ゜;)┛)