最近刚完成一个项目,项目不大,但是设计支付等功能,在这里进行记录一下,以便自己随时可以回顾
一、微信小程序
1、跳转到一个页面时想关闭之前的叠加的页面栈
最初我的做法是直接使用页面卸载,但是我发现用户体验度不是很好,会有很明显的闪动效果,而且因为我的项目登录方式有游客方式不是必登录,不登录的情况下也要能看到这个页面,所以就不能使用onShow这个方法了,但是从上一个页面跳回时还要能刷新更新一下数据。
onUnload(){
uni.navigateTo({
url:'要跳转的页面'
})
}
后来百度了一下,找到了一种写法,感觉效果要好些,就是在跳转的时候调用一下跳转的页面 你想要刷新的方法
realodPage() {
let pages = getCurrentPages(); //获取当前页面
let beforePage = pages[pages.length - 2] //获取上一个页面的实例
//1、调用上一个页面onLoad
beforePage.onLoad()
//2、调用上一个页面方法
// beforePage.fun()
// uni.navigateBack({
// delta: 0
// })
},
onUnload(){
this.realodPage()
}
2、开启订阅号
uni.getSetting({
withSubscriptions: true,
success(res) {
if (!res.subscriptionsSetting.mainSwitch) {
uni.openSetting({
success(res) {
}
})
} else {
uni.requestSubscribeMessage({
tmplIds: [‘模版Id’],
success(res) {
// console.log('requestSubscribeMessage 订阅信息', res);
if (res[paymodelId] ==
"accept") { // 用户点击确定后
} else {
// console.log('拒绝,不会再弹出弹框 只能去设置页膝盖');
uni.showModal({
title: '您未开启消息订阅',
content: '为了给您提供更好的服务,请您授权消息订阅',
success: res2 => {
if (res2.confirm) {
uni.openSetting({
success(res) {
// console.log('打开设置页', res.authSetting);
}
})
} else {
// console.log('决绝')
}
}
})
}
},
fail(errMessage) {
// console.log("订阅消息 失败 ", errMessage);
},
complete(errMessage) {
// console.log("成功 失败都执行 ", errMessage);
that.buyClick()
}
})
}
},
})
3、百度地图经纬度转换
这个项目中用到地图导航,后管是用地图获取经纬度传到后端,后端再通过接口传到小程序端的,但是我使用的是百度地图,微信小程序用的腾讯地图,所以经纬度上会有差别导致地址不准所以需要转换一下,下面是我找到的转换方法
借鉴:https://blog.csdn.net/weixin_43311271/article/details/139468547
1.百度经纬度转换成腾讯/高德地图经纬度
function bMapTransQQMap(lng, lat) {
let x_pi = 3.14159265358979324 * 3000.0 / 180.0;
let x = lng - 0.0065;
let y = lat - 0.006;
let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
let lngs = z * Math.cos(theta);
let lats = z * Math.sin(theta);
return {
lng: lngs,
lat: lats
}
}
2、腾讯/高德地图经纬度转换成百度经纬度
function qqMapTransBMap(lng, lat) {
let x_pi = 3.14159265358979324 * 3000.0 / 180.0;
let x = lng;
let y = lat;
let z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
let theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
let lngs = z * Math.cos(theta) + 0.0065;
let lats = z * Math.sin(theta) + 0.006;
return {
lng: lngs,
lat: lats
}
}
4、左滑删除功能
<view class="list">
<view v-for="(item, index) in collectList" :key="index">
<movable-area class="movable-area" v-if="show">
<movable-view class="movable-view" direction="horizontal" out-of-bounds="true" damping="50" friction="4" inertia="true"
:x="movableX"
>
<view class="p-tb-30" style="position: relative;width: calc(100% - 80px);" @click="detailClick(item)">
<view class="row collect m-lr-30" >
<view class="collect-left">
<image :src="item.ticketImage" mode="aspectFill" style="width:225rpx;height:180rpx;"></image>
</view>
<view class="collect-right">
<view class="f30 text-two">{{item.ticketName}}</view>
<view class="label m-t-30">活动</view>
</view>
</view>
<!-- <image src="../../static/delete.png" mode="aspectFit" class="delete-img" v-if="item.type == 1"></image> -->
<image src="../../static/yishixiao.png" mode="aspectFit" class="delete-img" v-if="item.type == 1"></image>
</view>
<view class="delete-btn" @click="delData(item)">删除</view>
</movable-view>
</movable-area>
</view>
</view>
js
data(){
return{
// 设置开始的位置
movableX:0,
startX: 0,
startY: 0,
show:true,
}
},
delData(item){
this.movableX = -80
let params = {
favoriteId:item.favoriteId,
userId:uni.getStorageSync('userId'),
}
getCollectCancel(params).then(res => {
if(res.data.code === 200){
this.movableX = 0
this.show = false
this.getData()
uni.showToast({
title: '删除成功',
icon: 'success',
})
}
})
},
css
.movable-area {
width: 93%;
height: 90px;
overflow: hidden;
padding: 30rpx 0;
border-bottom: 1px solid #f1f1f1;
border-radius: 15rpx;
margin:auto;
margin-top: 30rpx;
box-shadow: 5rpx 5rpx 20rpx #cdcdcd;
}
.movable-view {
width: calc(100% + 80px); /* 增加额外的宽度用于显示删除按钮 */
height: 90px;
padding: 30rpx 0;
display: flex;
align-items: center;
justify-content: space-between;
background-color: #fff;
position: relative;
left: 0px; /* 默认隐藏删除按钮 */
}
.item-content {
width: 100%;
padding-left: 20px;
background-color: #fff;
}
.delete-btn {
width: 70px;
height: 90px;
line-height: 90px;
color: white;
background-color: red;
text-align: center;
padding: 30rpx 0;
}
5、传参参数过长导致丢失问题
方式一:
A页面
uni.navigateTo({
url: `/pages/index/infom/detail?url=${encodeURIComponent(JSON.stringify(item.location))}`,
})
B页面
onLoad(item) {
// 传入需要跳转的链接 使用web-view标签进行跳转
// this.url = decodeURIComponent(item.url)
if (item.url) {
this.urlLink = JSON.parse(decodeURIComponent(item.url))
}
}
方式二:(其实这种方式我没用明白,地址我已经获取到了,但是一拿出渲染到页面就不行了,目前还不知什么原因,所以亲测第一种方式可)
A页面
uni.navigateTo({
url: `/pages/index/infom/detail?url=${encodeURIComponent(JSON.stringify(item.location))}`,
success: function(res) {
// 通过eventChannel向被打开页面传送数据
res.eventChannel.emit('todetailData', { data: item.location })
}
})
B页面
const eventChannel = this.getOpenerEventChannel();
// 监听todetailData事件,获取上一页面通过eventChannel传送到当前页面的数据
eventChannel.on('todetailData',function(data){
console.log('详情数据',data)
this.urlLink = decodeURIComponent(data.data)
console.log('this.urlLink',this.urlLink)
})
6、项目前端js代码混淆加密
写这个项目的时候,领导提了一个要求,为了代码安全,让给项目做一下代码加密。
之后我就开始百度了,刚开始研究的时候一头雾水,百度找实现方法也是看的迷迷糊糊的,今天才算是研究明白,研究明白之后才发现其实挺简单的,我用的是 javascript-obfuscator 插件实现的,还有一种 terser-webpack-plugin,但是我没用明白,有看会的朋友可以留言替我解惑一下
首先是安装 javascript-obfuscator
当前项目安装(这里我用pnpm安装一直报错安装不下来,不知道为啥,后来换了npm就安装下来了,yarn没有试)
yarn add javascript-obfuscator
#
npm install javascript-obfuscator
全局安装
npm install javascript-obfuscator -g
当前项目安装使用方法
npx javascript-obfuscator ./path_to_input_dir --output ./path_to_output_dir
// 混淆示例
先编译成小程序源码,比如uniapp编译后的dev代码位于/yourproject/dist/dev/mp-weixin
进入项目根目录 cd /yourproject/dist/dev/
执行混淆如下
npx javascript-obfuscator ./mp-weixin --output ./mp-weixin
全局使用方法
javascript-obfuscator ./path_to_input_dir --output ./path_to_output_dir
注意:
我使用 npx javascript-obfuscator ./mp-weixin --output ./mp-weixin 对整个项目进行混淆加密之后,项目就起不起来了,所以小程序包内的文件common文件,app.js不能进行混淆加密,然后就可能麻烦点一个一个文件进行混淆加密了
下面介绍一种相对方面的方式,但是对于我的项目而言稍微有点缺陷,就是有的文件混淆不到
借鉴:https://blog.csdn.net/qq_40358970/article/details/112952264
我是在跟unpackage同等级的建了一个code-obfuscation文件夹
index.js
// 检索的相对文件夹
const relativePath = '../unpackage/dist/dev/mp-weixin'
// 不需要混淆的js或文件夹
const exitFile = ['uni_modules', 'index.js', 'app.js', 'common']
var fs = require('fs')
var process = require('child_process');
var readDir = fs.readdirSync(relativePath);
// 需要存在的js
const czFile = []
var filePath = relativePath
var arr = new Array()
readFile(readDir, filePath)
// 读取相对路径下的所有文件
function readFile(readDir, filePath) {
if (readDir.length > 0) {
for (var i = 0; i < readDir.length; i++) {
scannerFile(readDir[i], filePath)
}
}
}
// 扫描文件进行检索出js文件进行混淆
function scannerFile(file, filePath) {
console.log("file-----" + file);
var readdirpath = ""
if (filePath == './') {
readdirpath = filePath + file
} else {
readdirpath = filePath + "/" + file
}
if (exitFile.indexOf(file) < 0) {
console.log('-->Start entering FS');
fs.stat(readdirpath, (err, data) => {
if (err) {
console.log(err);
} else {
if (data.isDirectory()) {
console.log('-->isDirectory:' + file);
var readChildDir = fs.readdirSync(readdirpath);
console.log(readChildDir);
readFile(readChildDir, readdirpath)
} else {
console.log('-->isNotDirectory:' + file);
if (file.indexOf('.js') >= 0 && file.indexOf('.json') < 0) {
// 开始混淆代码
console.log('-->Start confusing code:' + file);
var cmd = 'npx javascript-obfuscator ' + readdirpath + ' --config index.json --output ' + readdirpath;
process.exec(cmd, function(error, stdout, stderr) {
console.log("error:" + error);
console.log("stdout:" + stdout);
console.log("stderr:" + stderr);
});
arr.push(readdirpath)
} else {
console.log('Non-folder - Non-js code :' + file);
}
}
}
})
} else {
console.log('-->skip------------');
}
}
index.json
{
"compact": false,
"controlFlowFlattening": true,
"controlFlowFlatteningThreshold": 1,
"numbersToExpressions": true,
"simplify": true,
"shuffleStringArray": true,
"splitStrings": true,
"stringArrayThreshold": 1
}
然后进入code-obfuscation文件夹执行命令行
node .\index.js
不过像这种在同一个文件夹下的两个页面只会执行一个js混淆加密
7、前端封装的方法
借鉴地址:https://blog.csdn.net/weixin_55176296/article/details/131309370
1、将一个对象里面的键值对转换成url地址
export function tansParams(params) {
let result = ''
for (const propName of Object.keys(params)) {
const value = params[propName];
var part = encodeURIComponent(propName) + "=";
if (value !== null && value !== "" && typeof (value) !== "undefined") {
if (typeof value === 'object') {
for (const key of Object.keys(value)) {
if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {
let params = propName + '[' + key + ']';
var subPart = encodeURIComponent(params) + "=";
result += subPart + encodeURIComponent(value[key]) + "&";
}
}
} else {
result += part + encodeURIComponent(value) + "&";
}
}
}
return result
}
该函数作为一个工具函数,用于将一个 JavaScript 对象转换为 URL 查询参数格式的字符串。在前端开发中,我们常常需要通过 AJAX 或者跳转链接的方式将数据传递到服务器端,此时将数据转换成 URL 查询参数格式是一种常见的做法。
下面是一个小栗子方便理解的
const params = {
name: "Jack",
age: 25,
hobbies: ["swimming", "jogging"],
address: {
city: "Beijing",
street: "Haidian",
},
};
const str = tansParams(params);
console.log(str);
// 输出: name=Jack&age=25&hobbies[0]=swimming&hobbies[1]=jogging&address[city]=Beijing&address[street]=Haidian&
通过调用该函数,我们能够将 JavaScript 对象转换为经过序列化的 URL 查询参数格式的字符串,并且这个过程是通用的,适用于从前端到后端的服务端开发。
2、将两个对象数据覆盖,如果检测有就合并没有就不合并
export function objAssign(target, provide) {
//注意这里遍历 target 的key
Object.keys(target).forEach((key) => {
// Object.prototype.hasOwnProperty.call 用于检查一个对象是否具有指定的自身属性(也就是不继承自原型链的属性)
if(Object.prototype.hasOwnProperty.call(provide, key)){
target[key] = provide[key];
}
});
}
Object.prototype.hasOwnProperty.call 用于检查一个对象是否具有指定的自身属性(也就是不继承自原型链的属性)
const object = {
name: 'John',
age: 30
};
console.log(Object.prototype.hasOwnProperty.call(object, 'name')); // true
console.log(Object.prototype.hasOwnProperty.call(object, 'toString')); // false
例如:
const target = { a: 1, b: 2 };
const provide = { b: 3, c: 4, d: 5 };
objAssign(target, provide);
console.log(target); //{a: 1, b: 3}
跟obj.assign还是有一定的区别的
const target = { a: 1, b: 2 };
const provide = { b: 3, c: 4, d: 5 };
console.log('123',Object.assign(target,provide))
// {a: 1, b: 3, c: 4, d: 5}